Files
2026-10-23 22:37:55 +08:00

113 lines
8.1 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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*