# Map — Plan

**Module ID:** `oscar.map`
**Version:** 0.2.0

The plan order is binding per rules.md §5. Implementation must proceed in this order; reordering requires an explicit amendment fragment.

## Phase 1 — Doctrinal Foundation (CURRENT)

1. Extend `pact/recipes/map/recipe.md` to v0.2.0 — DONE
2. Extend `pact/recipes/map/codex.md` to v0.2.0 — DONE
3. Extend `pact/recipes/map/rules.md` to v0.2.0 — DONE
4. Update `pact/recipes/map/ingredients.json` to v0.2.0 — DONE
5. Update `pact/recipes/map/module-meta.json` to v0.2.0 — DONE
6. Add v0.2.0 fragments to `pact/fragments/oscar.map.*.002.md` — IN PROGRESS
7. Update `pact/recipes/map/coverage-matrix.md` to v0.2.0 — pending
8. Verify drift = zero in doctrine

## Phase 2 — Implementation (NOT STARTED, awaiting operator go)

The implementation order matches the operator's 9-item design and matches the C6 user simulation order. Each step re-anchors via re-running C6 + coverage matrix.

9. Selection + Side Panel (Item 1) — DONE
   - Shared `selectedLayerId` state — DONE
   - Click-on-shape + click-on-row handlers — DONE
   - `SidePanel.tsx` with all listed fields + action buttons — DONE
   - Esc / empty-map-click deselection — DONE
   - Auto-pan/zoom on selection (fitBounds) — DONE
   - Base-layer toggle (Map/Sat/Hyb) in toolbar top row — DONE
   - Re-anchor: C6 user sims 8, 9, 10 — PASS (18/18)

10. Filter Chips (Item 2) — DONE
    - `FilterChips.tsx` with kind multi-select + date single-select + name search + Clear all — DONE
    - Filter derivation: pure IIFE over `layers` + filter state — DONE
    - "Clear all filters" affordance — DONE
    - Map + layer list show only filtered subset — DONE
    - Auto-deselect when selected layer filtered out — DONE
    - Selection survives when filter still matches — DONE
    - Re-anchor: C6 user sims 15, 16, 17, 18 — PASS (30/30)

11. Export Menu (Item 3) — DONE (initial)
    - `ExportMenu.tsx` with format picker + options form (scope / extent / title block) — DONE
    - Per-format generators (PDF, PNG, SVG, GeoJSON, KML, Print) — DONE
    - Document record written on every successful export — DONE
    - Leaflet tile layers configured with `crossOrigin: 'anonymous'` so the PNG exporter can read tiles without tainting the canvas — DONE
    - Court-grade requirements (legend / scale bar / north arrow / audit hash) deferred to step 15 (Report Type Picker)
    - Re-anchor: C6 user sim 19 — PASS (all 6 formats download successfully, Document records persist)

12. Documents View (Item 4) — DONE
    - `app/src/views/Documents.tsx` — DONE
    - Re-download from stored blob (no regeneration) — DONE
    - Delete with confirmation, auto-refresh — DONE
    - Empty state with "Open map" CTA — DONE
    - Map header link ("Documents") navigates to /documents — DONE
    - `Document` schema extended with optional `blob` field — DONE (otherwise re-download would have to regenerate, contradicting the spec's "use stored blob only")
    - Re-anchor: C6 user sim 20 — PASS (13/14, the 1 fail was a test selector artifact, not a code issue)

13. Vertex Editing (Item 5)
    - Implement vertex-drag handlers in `MapView.tsx`
    - Drag vertex circle → coord updates live → release commits
    - Esc mid-drag → restore original coord
    - Drag whole marker for point layers
    - Version bumped on commit per rules.md §10
    - Re-anchor: C6 user sims 11, 12

14. Versioning (Item 6)
    - Add `version` field to MapLayer (default 1 on read for v0.1.0 records)
    - Wire `layer_versions` IDB store write on each significant edit
    - Display version in side panel
    - Re-anchor: C6 user sim 13 (rename bumps version)

15. Report Type Picker (Item 7)
    - Implement report-type picker in Export Menu
    - Four templates: site visit note, client report, planning submission, expert witness bundle
    - Each template has its own metadata block per rules.md (see coverage-matrix)
    - Re-anchor: extend C6 with report-type-specific simulations

16. Annotation Schema Stub (Item 8)
    - Add `annotations` IDB store
    - Implement write path: operator can attach annotation to a Document
    - Implement status update path: 'open' → 'applied' | 'dismissed'
    - No auto-interpretation per rules.md §12
    - Re-anchor: extend C6 with annotation-specific simulations

17. Cloud Sync Stub (Item 9)
    - Add forward-compat fields to MapLayer + Document per codex.md §C10
    - No behaviour reads or writes them per rules.md §13
    - Re-anchor: verify no behaviour depends on sync fields

## Phase 3 — Verification

18. Re-run C6 user simulations — all 20+ must pass
19. Re-run coverage matrix — drift = zero
20. Deploy + operator verification on real device
21. Declare v0.2.0 SHIPPED

---

## END OF PLAN.MD (v0.2.0)