Gjør romnr til autoritativ tilfluktsrom-ID (Room-PK og IndexedDB-key)
Produktbeslutning (Forgejo #15): romnr — DSBs romnummer — er den autoritative IDen. lokalId regenereres av Geonorge ved hver eksport og beholdes bare som informasjonsfelt; det skal aldri sammenlignes eller nøkles på. Utredningen mot Geonorge/DSB droppes. Dette retter også en reell feil på Android: etter «Oppdater data» holdt selectedShelter det gamle objektet med utdatert lokalId, så rebuildShelterList() la til en duplikatrad med «utenfor nærområdet»- badge for et rom som var blant de nærmeste, og markørhøylysingen mistet målet (markørkartet var nøklet på nye lokalId-er). Android: - Shelter: @PrimaryKey romnr; lokalId vanlig kolonne - ShelterDatabase: versjon 2 + fallbackToDestructiveMigration() — tabellen er ren cache som reseedes fra asset når den er tom - Parsere (GeoJSON + bundled): krever romnr > 0, lokalId valgfri - MainActivity: markørkart Map<Int, Marker>, høylysing og isSelectedAmongNearest/indexOfFirst på romnr - ShelterListAdapter: DiffUtil areItemsTheSame på romnr PWA: - shelter-db.ts: DB_VERSION 2, keyPath 'romnr', upgrade sletter og gjenoppretter store ved oldVersion < 2 - map-view.ts: _shelterRomnr i stedet for _shelterLokalId - types.ts: dokumentert identitet; fetch-shelters.ts hopper over features uten romnr (speiler Android-parseren) ARCHITECTURE.md: nytt avsnitt «Shelter identity — romnr is authoritative», felt-tabell, valideringsregel og IndexedDB-skjema oppdatert. Verifisert: emulator med v1.10.2-DB → migrering til v2 + reseed (556 rom); velg rad 2 → Oppdater → ingen duplikatrad, valg og høylysing beholdt. Playwright: seedet v1-IndexedDB → app oppgraderer til v2 (keyPath romnr, 556 poster, get(1681) treffer), dyplenke og markør OK. Forgejo: #15 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FrDGDmN2WAXvNPS85rWJGK
This commit is contained in:
parent
5b463f0ca6
commit
c3ab73c915
13 changed files with 108 additions and 54 deletions
|
|
@ -67,8 +67,8 @@ Geonorge ZIP (EPSG:25833 UTM33N)
|
|||
|
||||
| Field | Description |
|
||||
|------------|--------------------------------------|
|
||||
| `lokalId` | Unique identifier (UUID) |
|
||||
| `romnr` | Shelter room number |
|
||||
| `romnr` | Shelter room number — **authoritative ID / primary key** (see [Shelter identity](#shelter-identity--romnr-is-authoritative)) |
|
||||
| `lokalId` | Upstream UUID, re-rolled on every export — informational only |
|
||||
| `plasser` | Capacity (number of people) |
|
||||
| `adresse` | Street address |
|
||||
| `latitude` | WGS84 latitude (converted from UTM) |
|
||||
|
|
@ -135,7 +135,7 @@ OkHttp response stream
|
|||
→ Per feature:
|
||||
→ Extract UTM33N coordinates
|
||||
→ CoordinateConverter.utm33nToWgs84()
|
||||
→ Validate: lokalId not blank, plasser ≥ 0, within Norway bounds
|
||||
→ Validate: romnr > 0, plasser ≥ 0, within Norway bounds
|
||||
→ Create Shelter entity (skip malformed features with warning)
|
||||
```
|
||||
|
||||
|
|
@ -207,19 +207,21 @@ The domain is configured in one place: `DEEP_LINK_DOMAIN` in `build.gradle.kts`
|
|||
|
||||
Share messages include the HTTPS URL, which SMS apps auto-link as a tappable URL.
|
||||
|
||||
#### Deep link identifier — why `romnr`, not `lokalId`
|
||||
#### Shelter identity — `romnr` is authoritative
|
||||
|
||||
The path component is the shelter's `romnr` (DSB room number — an integer like `776`), not the GeoJSON `lokalId` UUID, even though `lokalId` is what Room and Leaflet use as the in-memory primary key.
|
||||
**Decision (2026-08-17, Forgejo #15):** `romnr` — DSB's room number — is the authoritative shelter identifier everywhere: Room primary key, IndexedDB `keyPath`, marker maps, list diffing, selection equality and the deep-link path. `lokalId` is stored as informational data only and must never be compared or keyed on. Records without a positive `romnr` are skipped by both parsers.
|
||||
|
||||
The deep-link path component is therefore `romnr` (an integer like `776`), not the GeoJSON `lokalId` UUID.
|
||||
|
||||
**Empirical reason:** the upstream GeoJSON ZIP at `nedlasting.geonorge.no/.../TilfluktsromOffentlige_GeoJSON.zip` re-rolls every `lokalId` on every export. Three snapshots of the same dataset (taken Dec 2025, Apr 20 2026, Apr 27 2026) had **556/556 different lokalIds** while every other field (`romnr`, `adresse`, `plasser`, `latitude`, `longitude`) was byte-identical and the shelter count was unchanged. The most recent two snapshots are only seven days apart, so this is regular drift, not a one-off re-issue.
|
||||
|
||||
That makes `lokalId` unsuitable for any cross-device or cross-build identifier:
|
||||
- Sender and receiver who fetched the dataset on different days have different lokalIds for the same physical shelter, so a lokalId-keyed share link fails with "shelter not found" on the receiving side.
|
||||
- Even on a single device, a user who hits "Refresh data" while a shelter is selected would lose the selection if it was tracked by lokalId.
|
||||
- Even on a single device, a user who hits "Refresh data" while a shelter is selected keeps the *object* but its `lokalId` no longer matches anything in the new dataset — before the switch this produced a duplicate "outside nearest" list row and a lost marker highlight on Android.
|
||||
|
||||
`romnr` is the actual DSB business key — the room number physically assigned to the shelter by the civil-defence authority — and is stable across exports. Verified unique (556/556) and present (no zeros) on the current dataset.
|
||||
|
||||
The internal Room primary key remains `lokalId` because (a) it's already the upstream-supplied UUID and changing it would force a destructive Room schema migration, and (b) within a single fetch it's a perfectly fine in-memory key. Only the *external* deep-link identifier was switched.
|
||||
Room schema v2 and IndexedDB v2 switched the primary key to `romnr` (destructive migration in both — the tables are pure caches re-seeded from the bundled asset / `data/shelters.json` when empty). The weekly romnr-stability routine (`scripts/romnr-baseline.json`) remains the safety net: it diffs each Geonorge export against the baseline and flags any romnr that disappears, appears or moves.
|
||||
|
||||
---
|
||||
|
||||
|
|
@ -292,7 +294,7 @@ bun run build # TypeScript check + Vite build + SW generation
|
|||
**Storage:** IndexedDB via the `idb` library.
|
||||
|
||||
**Schema:**
|
||||
- Object store `shelters` (keyPath: `lokalId`) — full shelter records
|
||||
- Object store `shelters` (keyPath: `romnr`, DB v2) — full shelter records
|
||||
- Object store `metadata` — `lastUpdate` timestamp
|
||||
|
||||
**Loading strategy:**
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue