grain.social is a photo sharing platform built on atproto. grain.social
atproto photography appview
57
fork

Configure Feed

Select the types of activity you want to include in your feed.

docs: note deferred follow-ups for locations and cameras

Inline comments near each relevant file capturing work discussed but not
shipped in ca49c1b: /place/[slug] URL scheme, capturing osm_type/osm_id
from Nominatim, source of the "USA" country variant, limit param for the
index pages, and native parity with the multi-cell union behavior.

+51
+9
app/lib/utils/nominatim.ts
··· 1 + // FOLLOW-UP: Nominatim responses also include `osm_type` ("node"|"way"|"relation") 2 + // and `osm_id` — these form a globally stable, never-reused OSM identity 3 + // (e.g. `relation:175905` is New York City forever). We currently discard 4 + // them. Capturing them in `extractAddress` as an `osmId` string would give 5 + // new gallery records a canonical place ID that's resilient to locality 6 + // spelling variants. Only worth doing if the country-alias approach stops 7 + // covering the variants we see in `address.country`, since existing PDS 8 + // records can't be backfilled and a parallel identity system needs a 9 + // reconciliation layer. See server/feeds/location.ts comment. 1 10 export interface NominatimResult { 2 11 display_name: string; 3 12 lat: string;
+17
server/feeds/location.ts
··· 3 3 // 4 4 // Accepts both resolution-10 (venue) and resolution-5 (city) H3 indices. 5 5 // For city-level queries, matches galleries whose venue H3 is a child of the city cell. 6 + // 7 + // FOLLOW-UPS (see commit ca49c1b for context): 8 + // 9 + // 1. Replace the `name` display-string param with a `/place/[slug]` URL 10 + // scheme. The current encoding serialises structured address fields into 11 + // a display string, then parses them back out below — this works today 12 + // but will break if a locality contains a comma ("Washington, D.C."), 13 + // if display names get localised, or if the format evolves. Cleaner 14 + // alternative: add `locality`/`region`/`country` to LocationItem in the 15 + // lexicon, carry them through the URL + feed param as structured data, 16 + // keep `name` purely for display. 17 + // 18 + // 2. grain-native still calls this feed with only `location=<h3>` and no 19 + // `name` — it falls through to the legacy single-cell path below, so 20 + // native users don't benefit from the multi-cell union. Fix lives in 21 + // grain-native's FeedEndpoints.swift + LocationFeedView.swift + pinned 22 + // feed paths. Additive, non-breaking. 6 23 7 24 import { defineFeed } from "$hatk"; 8 25 import { hydrateGalleries } from "../hydrate/galleries.ts";
+9
server/helpers/country.ts
··· 5 5 // upper-cased on match, so spelling case doesn't matter. 6 6 7 7 // Only the variants actually observed in the data. Add more as they appear. 8 + // 9 + // The single observed non-canonical value ("USA") comes from one external 10 + // DID (timtrautmann.com) posting to the grain lexicon via a third-party tool 11 + // — grain-web and grain-native both uppercase `country_code` from Nominatim 12 + // and produce ISO-2. If a second source starts writing other variants, add 13 + // them here. If the table balloons, consider instead the alternatives noted 14 + // in server/feeds/location.ts: a server-side indexer enrichment step that 15 + // calls Nominatim on ingest and canonicalises the country field into the 16 + // AppView index. 8 17 export const COUNTRY_ALIASES: Record<string, string> = { 9 18 USA: "US", 10 19 };
+8
server/xrpc/getCameras.ts
··· 5 5 // client gets consistent, human-readable names. Rows that collide after 6 6 // normalization are merged (e.g. "RICOH IMAGING COMPANY, LTD. GR III" and 7 7 // a hypothetical "Ricoh GR III" fold into one entry with summed counts). 8 + // 9 + // FOLLOW-UPS: 10 + // - Results are capped at top 30. The `/cameras` index page uses this 11 + // endpoint — if more is ever needed, add an optional `limit` param. 12 + // - ~50 records in prod have make="CAMERA" model="CAMERA", likely test 13 + // data; they normalize to a single "Camera" row. Harmless, but it's 14 + // the one row you might want to filter out if the sidebar ever feels 15 + // cluttered. 8 16 9 17 import { defineQuery } from "$hatk"; 10 18 import { cleanCameraName } from "../helpers/cameraName.ts";
+8
server/xrpc/getLocations.ts
··· 6 6 // finally to an H3 res-5 cell for records missing address data. This 7 7 // eliminates the old H3-cell-first grouping, which could produce duplicate 8 8 // entries when a city's photos spanned multiple res-5 parent cells. 9 + // 10 + // FOLLOW-UPS: 11 + // - Results are capped at top 30. The `/locations` index page uses this 12 + // same endpoint. If the index needs to show more, add an optional 13 + // `limit` param (bounded) rather than lifting the cap unconditionally. 14 + // - At time of writing, only 4 records in prod have `location` but no 15 + // `address` — they fall to the `location.name` / H3 res-5 fallback 16 + // paths below. If that number grows, revisit the ladder. 9 17 10 18 import { defineQuery } from "$hatk"; 11 19 import { getResolution, cellToParent } from "h3-js";