ambek .planning

This commit is contained in:
araharah-executor
2026-10-23 22:37:55 +08:00
parent e512104d5e
commit 275879a18b
54 changed files with 9921 additions and 0 deletions
@@ -0,0 +1,112 @@
# Phase 3: Mini App Shell + Geolocation - Context
**Gathered:** 2026-10-22
**Status:** Ready for planning
<domain>
## Phase Boundary
The Telegram Mini App boots inside Telegram, validates its session through Phase 2's /api/session gate, acquires live location reliably across Android/iOS/Desktop/browser with a full fallback chain (Telegram-native → WebView → chat keyboard), and renders the user's position on the Rams basemap under Telegram light + dark themes. Every failure surface is deliberate (never blank); no coordinate persists anywhere. BackButton + safe-area groundwork land here; the observable PX-01/PX-03 behaviors are Phase 6's. Search/routes/guidance are later phases.
</domain>
<decisions>
## Implementation Decisions
### Mini App stack + repo layout
- **D-01:** Frontend is TypeScript + Vite, **no UI framework** — MapLibre GL JS v6 bundled, interactivity via small focused modules (the mockups' pattern, productionized). This stack is the foundation Phases 4–6 build on.
- **D-02:** App source lives in a `web/` npm workspace beside `theme/` and `bot/`; root package.json gains `web:*` delegate scripts. Theme is consumed as a **build-time dependency** (`theme/dist/rams.css` imported into the Vite build, not via CDN) — completing Phase 1's self-hosted/CDN-free decision for the app path.
- **D-03:** Post-initData validation, the session token is held **memory-only** (module scope), never written to localStorage/sessionStorage/cookies. Revalidation happens on every fresh boot (Telegram revives webviews) and whenever the 900s TTL stalls mid-session. Research may stress-test this invariant across webview reload quirks, but the invariant itself is locked.
### Location acquisition strategy
- **D-04:** Primary chain: Telegram-native `WebApp.getLocation()` first (Android LocationManager with version-gated paths), fall back to `navigator.geolocation` inside the WebView, then the chat-keyboard "send location" fallback (bot-side; app consumes it). Research details the Android stale-fix and iOS WKWebView quirks — the CHAIN is locked, the per-link mechanics are research's.
- **D-05:** Cadence is **gated streaming**: one-shot fixes during browsing/search; continuous watch only during guidance (Phase 6 builds the streaming state machine). Map recenters on each fix; the position marker always shows the freshest fix.
- **D-06:** Denied/no-geolocation presents a deliberate Rams-styled denied state — explains why location matters, offers retry, points to Telegram's attach → Location path as the manual fallback (GEO-02). No silent banners.
- **D-07:** Coordinates live in **memory only** while the app runs. Zero persistence across every storage API (localStorage, sessionStorage, cookies, IndexedDB, service-worker caches). This zero-persistence assertion is part of the phase's GEO-03 spot-check, stress-tested by research against every storage surface the app touches.
### Shell UX + screens
- **D-08:** Phase 3's screen surface is map-first and single: full-bleed Rams basemap, position dot, follow/recenter control, minimal status strip reflecting session/location state. Route lines, layer toggles, search furniture belong to later phases — nothing placeholder-shaped.
- **D-09:** Boot choreography has staged deliberate states: validating session → acquiring location → live — each Rams-styled, none blank (extends the neutral-denied rule from PX-02).
- **D-10:** Map survives theme flips Rams-constant (Phase 1 D-04 slots pay off); only shell surfaces re-theme via the Telegram theme params. Safe-area handling + BackButton wiring land here as infrastructure.
### Dev/test harness
- **D-11:** A **Mock-Telegram harness** for the daily loop: a local module injecting a fake `window.Telegram.WebApp` (dev-signed initData, BackButton events, theme params with light/dark switch, sample location streams) plus a runner page booting the real app off-Telegram in a plain browser. Real-device batteries are spent at the device-matrix exit gate, not during daily dev.
- **D-12:** Local dev topology is **wrangler dev** on 8787 serving web/dist statics + `/api/*` + webhook with local KV simulation; remote staging used sparingly right before real-device verification sessions.
### Worker static-asset wiring
- **D-13:** Statics served by the **Workers `[assets]` binding** (wrangler config), from `web/dist`'s build output; Worker fetch still owns `/api/*` + webhook first. Completes the one-deployable architecture from the roadmap.
- **D-14:** Build inlines everything the app needs: CSS from theme, MapLibre, basemap style JSON (from `theme/basemap/liberty-rams.json`), self-hosted fonts copied at build time into `web/dist`. Tiles remain OpenFreeMap's endpoint at runtime; no CDN fallbacks.
- **D-15:** Deployment stays one command (`npm run deploy` = build web → wrangler deploy with assets). Same ergonomics as Phase 2. Hashed filenames from Vite play naturally with Cloudflare's asset caching.
### OpenCode's Discretion
- Exact per-link mechanics of the location chain (Telegram API calls, permission bridging) — research's domain
- Boot-state copy, exact mock initData signing mechanics, recenter-toggle visual details (within the Rams system)
- `assets` config tuning (binding name, not_found_handling, asset prefixes)
- How the reserved exit-gate Playwright matrix extends theme/scripts/screenshot.mjs
</decisions>
<specifics>
## Specific Ideas
- The app should feel like the navigate_map_overview mockup distilled: calm, map-dominant, nothing decorative.
- Allowed fallbacks compose as a chain, not a menu — user should perceive one honest app.
- Mock harness borrow: dev initData signing already exists conceptually in bot/scripts (HTTP world), and the hand-rolled test runner pattern (theme) prevails.
</specifics>
<canonical_refs>
## Canonical References
**Downstream agents MUST read these before planning or implementing.**
### Phase scope + decisions
- `.planning/ROADMAP.md` §Phase 3 — goal, 5 success criteria incl. device-matrix exit, research recommendation
- `.planning/REQUIREMENTS.md` §GEO-01/02/03, PX-02 (this phase's requirements)
- `.planning/phases/02-bot-skeleton-initdata-security/02-CONTEXT.md` — identity floor /api/session contract details (opaque token, 900s TTL, rotation)
- `.planning/phases/01-design-tokens-rams-foundation/01-CONTEXT.md` — theme package contract (Rams-constant map, D-04 theme slots)
### Codebase
- `theme/dist/rams.css`, `theme/src/components.css`, `theme/src/tokens.css` — consumption surface
- `theme/basemap/liberty-rams.json` — the map style to load
- `bot/src/webhook.ts`, `bot/src/kv/sessions.ts` — the /api/session contract the web app calls
- `stitch_minimalist_route_navigator/navigate_map_overview/code.html` — layout reference (read-only)
- `AGENTS.md` — repo conventions
</canonical_refs>
<code_context>
## Existing Code Insights
### Reusable Assets
- `theme/dist/rams.css` + `components.css` — the app imports these directly (build-time)
- `theme/basemap/liberty-rams.json` + `build.mjs` — map style + derivation upstream of a loaded style object
- `theme/fonts/*` self-hosted woff2 — copied at build time into web/dist
- `theme/scripts/screenshot.mjs` — Playwright toolchain for exit-gate device-matrix extension
- Phase 2's `/api/session` — the auth endpoint, deploy scripts + .dev.vars conventions
### Established Patterns
- npm workspaces with delegate scripts (theme/, bot/)
- Hand-rolled node test runner (audit.test.mjs shape)
- TDD discipline; zero-persistence privacy invariant (KV TTL-only)
### Integration Points
- web/dist → wrangler `[assets]` binding on the existing `araharah-bot` Worker
- `WebApp.getLocation()` / navigator.geolocation → module that also feeds Phase 5's route snapping and Phase 6's guidance loop
- BackButton jumps to full state graph in Phase 6
</code_context>
<deferred>
## Deferred Ideas
- Scripted Playwright device-matrix spec (mock-based) — extend theme/scripts toolchain at the exit gate
- Placeholder-shaped search drawer / route furniture — later phases by design
- Real-device TestFlight/Play Beta channels — out of scope; device-matrix exit pass suffices for v1
</deferred>
---
*Phase: 03-mini-app-shell-geolocation*
*Context gathered: 2026-10-22*