docs(01-design-tokens-rams-foundation): create phase plan (4 plans, 3 waves)
This commit is contained in:
@@ -0,0 +1,188 @@
|
||||
# Roadmap: araharah
|
||||
|
||||
## Overview
|
||||
|
||||
araharah turns Telegram into a privacy-respecting turn-by-turn navigator for KL: a bot handles
|
||||
identity, search, and launch; a Telegram Mini App renders Rams-styled route guidance; Valhalla
|
||||
routing, self-hosted Photon lookup, OpenFreeMap tiles, and MapLibre GL JS v6 supply the OSM
|
||||
geodata layer; one Cloudflare Worker (static assets + webhook + `/api/*`) serves it all with
|
||||
KV-only TTL storage. The roadmap follows the research's strict dependency funnel — design tokens
|
||||
first (design fidelity is the flagged #1 sink for v1), then the bot/identity security floor,
|
||||
then the Mini App shell with geolocation, then KL destination search, then routing and route
|
||||
display, then live turn-by-turn guidance including backgrounded chat turn-cards, and finally a
|
||||
hardening pass that earns the private launch. Two phases deliberately surface the project's
|
||||
biggest unknowns early: WebView geolocation quirks (Phase 3) and KL search quality (Phase 4).
|
||||
|
||||
## Phases
|
||||
|
||||
**Phase Numbering:**
|
||||
- Integer phases (1, 2, 3): Planned milestone work
|
||||
- Decimal phases (2.1, 2.2): Urgent insertions (marked with INSERTED)
|
||||
|
||||
Decimal phases appear between their surrounding integers in numeric order.
|
||||
|
||||
- [ ] **Phase 1: Design Tokens + Rams Foundation** - Distill the Telemetry Rams system into a single token package and Rams-styled map basemap, with a mockup-vs-implementation approval artifact — before any screen is built
|
||||
- [ ] **Phase 2: Bot Skeleton + initData Security** - grammY bot on one Cloudflare Worker: /start, command menu, /privacy, and HMAC-validated identity with TTL-only KV storage
|
||||
- [ ] **Phase 3: Mini App Shell + Geolocation** - Telegram WebApp shell that boots, authenticates, and reads a reliable live location across the Android/iOS/Desktop client matrix
|
||||
- [ ] **Phase 4: Destination Search + KL Gazetteer** - Free-text KL search that resolves landmarks despite Malay abbreviations and typos, venue cards, and Mini App launch with destination preloaded
|
||||
- [ ] **Phase 5: Routing + Route Display** - Valhalla-backed route calculation shown as a Rams route line with quiet alternative cards; the full search→route→render loop lands
|
||||
- [ ] **Phase 6: Turn-by-Turn Guidance (Live Driving)** - Client guidance state machine: maneuver banner, missed-turn auto-recalculation, honest ETA, haptics, seamless resume, and backgrounded chat turn-cards
|
||||
- [ ] **Phase 7: Hardening + Private Launch** - Device-matrix QA, graceful failure states, privacy-by-construction audit, and golden-route regression before real drivers
|
||||
|
||||
## Phase Details
|
||||
|
||||
### Phase 1: Design Tokens + Rams Foundation
|
||||
**Goal**: The Telemetry Rams design system exists as one centralized, importable token set — including map basemap cartography — with a user-approved mockup-vs-implementation gallery proving the fidelity bar before any product screen is built.
|
||||
**Depends on**: Nothing (first phase)
|
||||
**Requirements**: DSGN-01, DSGN-02
|
||||
**Success Criteria** (what must be TRUE):
|
||||
1. Every rendered Rams component derives exclusively from the centralized token set (exacted palette, 8px grid, radius-0, typography) — an audit sweep finds zero off-token color/spacing/typography values in the component sheet (DSGN-01)
|
||||
2. A side-by-side gallery comparing the rendered token/component sheet against the `stitch_minimalist_route_navigator/` mockup screens exists and is approved by the user — establishing the DSGN-02 approval artifact mechanism reused by every later UI phase
|
||||
3. A Rams-styled MapLibre basemap (OpenFreeMap `liberty` style forked to Rams tokens: grayscale grounding, muted land/water, prepared accent for route highlighting) renders in a browser (DSGN-01, map cartography)
|
||||
4. Design authority is singular: the duplicate inline Tailwind token blocks and the conflicting root `DESIGN.md` typography are superseded by the token package as the one source of truth (resolves the CONCERNS.md design-source conflict)
|
||||
**Plans**: 4 plans
|
||||
|
||||
Plans:
|
||||
- [ ] 01-01-PLAN.md — Repo hygiene + Tailwind v4 token package (`theme/`) + self-hosted fonts + DESIGN.md supersession (D-01/02/04/05/06/07/16)
|
||||
- [ ] 01-02-PLAN.md — Component sheet: `theme/src/components.css` + `sheet.html` consuming tokens only (D-03/D-11)
|
||||
- [ ] 01-03-PLAN.md — Rams basemap: token-derived OpenFreeMap liberty fork + KL preview (D-08/09/10)
|
||||
- [ ] 01-04-PLAN.md — Off-token audit (D-13) + Playwright captures (D-14) + DSGN-02 approval gallery (D-12), blocking user checkpoint
|
||||
|
||||
Notes:
|
||||
- Repo hygiene lands here first: scrub `*:Zone.Identifier` artifacts, `.gitignore` for OS junk/`node_modules`/secrets (pre-dates any credential handling).
|
||||
- Project skill `.agents/skills/design-taste-frontend/` applies to all UI phases under its *existing brand/design system* special case: keep the Rams palette/type, app-screen house rules for dashboard-like surfaces, real-browser inspection for the gallery artifact. Telemetry Rams tokens are binding where skill defaults would differ.
|
||||
- Standard patterns (no research phase needed): mockups are the spec; token extraction from the mockup Tailwind config.
|
||||
**UI hint**: yes
|
||||
|
||||
### Phase 2: Bot Skeleton + initData Security
|
||||
**Goal**: Users can reach araharah through Telegram with a working command surface, and the backend's identity + privacy architecture is provably sound from the first deploy — the initData validator is the first backend artifact.
|
||||
**Depends on**: Phase 1
|
||||
**Requirements**: ONBD-01, PRIV-01, PRIV-02
|
||||
**Success Criteria** (what must be TRUE):
|
||||
1. A new user sends /start and receives a concise explanation plus an always-available command menu (/help, /privacy) that answers correctly (ONBD-01)
|
||||
2. /privacy gives an honest, visible statement of what araharah stores and does not store (PRIV-01) — the in-app "trip ended, data deleted" messaging half completes with guidance in Phase 6, riding this requirement's message design
|
||||
3. Tampered, stale, and replayed initData payloads are rejected with CI test vectors and known-good HMAC cases passing; only validated identities receive a one-time session token (security gate — the phase's exit criterion)
|
||||
4. A storage spot-check shows KV with TTL-only namespaces and zero persistent coordinates or user profiles — privacy by construction holds from the first line of backend code (PRIV-02; re-audited in Phase 7)
|
||||
**Plans**: TBD
|
||||
|
||||
Notes:
|
||||
- One Cloudflare Worker deployable (static assets + webhook + `/api/*`); KV `chat_sessions` (minutes TTL) is the first namespace; the `guidance_sessions` (~2h TTL) envelope is only designed with its consumer in Phase 5.
|
||||
- Standard patterns (no research phase needed): grammY + Workers hosting is first-class documented; verify exact grammY initData typings at phase start (research gap).
|
||||
**UI hint**: no
|
||||
|
||||
### Phase 3: Mini App Shell + Geolocation
|
||||
**Goal**: The Mini App opens inside Telegram, establishes a validated session, and obtains the user's live location reliably — with every fallback path that keeps location flowing when the primary path dies, verified on real devices.
|
||||
**Depends on**: Phase 2
|
||||
**Requirements**: GEO-01, GEO-02, GEO-03, PX-02
|
||||
**Success Criteria** (what must be TRUE):
|
||||
1. On a real Android phone and iOS phone, the user grants location and sees their live position rendered on the Rams basemap; the permission grant persists across session restarts via LocationManager (version-gated) (GEO-01)
|
||||
2. When in-app location fails (Desktop Telegram without geolocation, or denied permission), the chat "send location" keyboard fallback recovers the origin and the app proceeds with it (GEO-02)
|
||||
3. Location denial shows a deliberate denied state (never a blank map), and the app renders correctly under Telegram light and dark themes while the map keeps Rams cartography constant (PX-02, platform themes)
|
||||
4. No coordinate written anywhere persists: storage remains TTL-ephemeral only, spot-checkable at phase exit (GEO-03)
|
||||
5. Device-matrix exit pass: Android + iOS + Desktop + plain browser each demonstrate boot → session → position, exercising the full fallback chain (pitfall research device-matrix criterion)
|
||||
**Plans**: TBD
|
||||
|
||||
Notes:
|
||||
- Highest platform-integration uncertainty in the project — research recommends `/gsd-research-phase` (Android LocationManager stale-fix workaround, `getLiveData()` wrapper, WebView permission bridges, browser testing harness).
|
||||
- BackButton wiring and safe-area groundwork are built here as shell infrastructure; the observable PX-01/PX-03 behaviors are claimed by Phase 6 where the full state graph exists.
|
||||
**UI hint**: yes
|
||||
|
||||
### Phase 4: Destination Search + KL Gazetteer
|
||||
**Goal**: Users type a destination the way locals actually write it and get the right KL-metro landmark back, then step into the Mini App already aimed at their destination.
|
||||
**Depends on**: Phase 3
|
||||
**Requirements**: SRCH-01, SRCH-02, SRCH-03, ONBD-02, ONBD-03
|
||||
**Success Criteria** (what must be TRUE):
|
||||
1. Typing "KLCC" — plus the golden query set ("Sunway Pyramid", "DUKE", mall and kampung-style queries) — returns the right KL landmark in a shortlist (SRCH-01)
|
||||
2. Abbreviated, typo'd, and missing-space queries ("Jln Ampang" ↔ "Jalan Ampang", "Tmn", glued words) resolve to the same result as the canonical spelling (SRCH-02)
|
||||
3. Choosing a result sends a native venue card in chat confirming the destination before navigation opens (SRCH-03)
|
||||
4. Tapping through from the search result launches the Mini App with the destination preloaded — no re-entry in the webview (ONBD-02); adding araharah to the phone home screen and launching from there lands in the app ready to search (ONBD-03)
|
||||
5. The self-hosted Photon KL bake-off is concluded against the real-query acceptance corpus with the decision (and any gazetteer/fallback escalation) documented — the search-quality experiment closes, it doesn't stay open
|
||||
**Plans**: TBD
|
||||
|
||||
Notes:
|
||||
- Budgeted bake-off: research recommends `/gsd-research-phase` (gazetteer sourcing/structure ~200 entries, Malay normalizer, photon-vs-fallback decision; funds a GraphHopper MY dump on the VPS).
|
||||
- VPS provisioning (Photon + Valhalla hosting) begins here — free-first infrastructure mandate (Oracle Cloud Always Free candidate).
|
||||
**UI hint**: no
|
||||
|
||||
### Phase 5: Routing + Route Display
|
||||
**Goal**: The product exists end-to-end: current location to Rams-drawn route with quiet alternative choices, on routing infrastructure fast enough for the guidance phase to build on.
|
||||
**Depends on**: Phase 4
|
||||
**Requirements**: RTNG-01, RTNG-02
|
||||
**Success Criteria** (what must be TRUE):
|
||||
1. A user sees their calculated route drawn on the Rams-styled map — grayscale basemap grounding with the accent route line — from their current location to the chosen destination (RTNG-01)
|
||||
2. The user can choose among up to 3 alternatives presented as quiet Rams cards (time, distance, one-line difference) and the selection redraws (RTNG-02)
|
||||
3. The golden-route corpus (10–20 real KL origin/destination pairs) routes cleanly through self-hosted Valhalla (Malaysia extract) behind the Worker proxy — no dead ends, no geometry failures, latency and Worker subrequest budgets holding with instrumentation visible
|
||||
**Plans**: TBD
|
||||
|
||||
Notes:
|
||||
- GUID-05/06 upstream design obligations land here deliberately: the route model carries step geometry + snapped-progress support from day one, and the ephemeral `guidance_sessions` KV envelope (id, chat ref, route snapshot ref, ~2h TTL) is designed here so the backgrounded turn-card service in Phase 6 has its session contract already defined.
|
||||
- Standard patterns (no research phase needed): documented preprocess pipeline for Valhalla + the graph/tiles build; no exotic APIs.
|
||||
**UI hint**: yes
|
||||
|
||||
### Phase 6: Turn-by-Turn Guidance (Live Driving)
|
||||
**Goal**: While driving, araharah behaves like real navigation — prominent maneuvers, silent self-healing recalculation, honest ETAs, haptic cues, seamless resume — and guidance survives the app being minimized via best-effort chat turn-cards.
|
||||
**Depends on**: Phase 5
|
||||
**Requirements**: GUID-01, GUID-02, GUID-03, GUID-04, GUID-05, GUID-06, PX-01, PX-03
|
||||
**Success Criteria** (what must be TRUE):
|
||||
1. During a drive, the user sees a prominent next-maneuver banner (distance + arrow + street name) with a collapsible full maneuver list (GUID-01), ETA and remaining distance progressing with each location fix without visible whiplash (GUID-03), and a haptic cue at maneuver points (GUID-04)
|
||||
2. After a missed turn, the app silently recalculates from the current position — no asking, no blaming — and reroute storms are held back by the debounce/hysteresis state machine (GUID-02, verified via recorded-drive replays plus a real drive)
|
||||
3. Minimizing the app mid-drive switches the bot to pushing chat turn-cards (map snapshot + next maneuver + ETA, best-effort projection) for the remainder of the trip (GUID-05, served by the Phase 5-designed ephemeral guidance session); re-opening mid-trip resumes live guidance seamlessly at the progressed position (GUID-06)
|
||||
4. The Telegram BackButton walks the full app states (search → routes → guidance → back to search) and never dead-ends (PX-01 — full state graph only exists now); closing during guidance requires passing the "abandon route?" confirmation, with safe areas respected and vertical-swipe-close disabled during guidance (PX-03)
|
||||
5. Ending a trip deletes the ephemeral guidance session and shows the "trip ended, data deleted" messaging — completing the in-app half of PRIV-01's promise at the trip boundary
|
||||
**Plans**: TBD
|
||||
|
||||
Notes:
|
||||
- Highest behavioral uncertainty (reroute triggers, ETA smoothing, battery) — research recommends `/gsd-research-phase` (backgrounded turn-card "best-effort projection" framing + static map snapshot generation; product decision needed for what "good enough" means minimized).
|
||||
- Schedule slack budgeted here per research; backgrounded turn-cards are folded into this phase per roadmap instructions with the session contract pre-designed upstream (Phase 5).
|
||||
**UI hint**: yes
|
||||
|
||||
### Phase 7: Hardening + Private Launch
|
||||
**Goal**: Real KL drivers get an honest, robust experience: every failure state designed, the privacy promise holding under audit, performance within free-tier budgets, and a known-limitations document that tells the truth — then the launch.
|
||||
**Depends on**: Phase 6
|
||||
**Requirements**: PX-04
|
||||
**Success Criteria** (what must be TRUE):
|
||||
1. Guidance supports fullscreen and remains usable in landscape (driving posture) across the full real device matrix — Android, iOS, Desktop, browser (PX-04) — folded into the phase's device-matrix QA pass including the battery drain target (<10%/hr during guidance)
|
||||
2. Every empty/error/timeout/off-road/no-geometry state renders gracefully (no blank screens, no broken layouts); version-gating fallbacks behave sanely on older Telegram clients
|
||||
3. Privacy verification passes: an architecture audit shows no persistent per-user location history or profile anywhere — coordinates exist only in TTL-expiring KV, and logs carry no coordinate data (re-verifies PRIV-02, GEO-03 end-to-end)
|
||||
4. The golden-route regression pass is green, Worker budgets audit clean (subrequests/CPU, cache hit-rate), and the "known limitations" doc (OSM data gaps, no traffic confidence, no lane guidance) ships before the first real drivers
|
||||
**Plans**: TBD
|
||||
|
||||
Notes:
|
||||
- No exclusive feature requirements beyond PX-04 — this phase hardens the outcomes of Phases 1–6 and is the last chance to catch the "looks done but isn't" failures for a navigation tool whose empty states ARE the polish surface.
|
||||
**UI hint**: no
|
||||
|
||||
## Requirements Coverage
|
||||
|
||||
| Phase | Requirements |
|
||||
|-------|--------------|
|
||||
| 1 | DSGN-01, DSGN-02 |
|
||||
| 2 | ONBD-01, PRIV-01, PRIV-02 |
|
||||
| 3 | GEO-01, GEO-02, GEO-03, PX-02 |
|
||||
| 4 | SRCH-01, SRCH-02, SRCH-03, ONBD-02, ONBD-03 |
|
||||
| 5 | RTNG-01, RTNG-02 |
|
||||
| 6 | GUID-01, GUID-02, GUID-03, GUID-04, GUID-05, GUID-06, PX-01, PX-03 |
|
||||
| 7 | PX-04 |
|
||||
|
||||
**Coverage:** 22/22 v1 requirements mapped — no orphans, no duplicates. (PRIV-01's in-app trip-boundary messaging and PX-01/PX-03 groundwork are noted where they're staged, but each requirement maps to its owning phase exactly once.)
|
||||
|
||||
## v1.x Candidates (post-v1, not roadmap phases)
|
||||
|
||||
Per research: voice guidance (gated on iOS WKWebView TTS spike), live trip share via `sendLocation(live_period)`, toll vs toll-free toggle (Valhalla `use_tolls`), speed-limit display where OSM `maxspeed` exists. These hang off validated routing + guidance — plan a v1.x milestone after user validation, do not pull into the spine above.
|
||||
|
||||
## Progress
|
||||
|
||||
**Execution Order:**
|
||||
Phases execute in numeric order: 1 → 2 → 3 → 4 → 5 → 6 → 7
|
||||
|
||||
| Phase | Plans Complete | Status | Completed |
|
||||
|-------|----------------|--------|-----------|
|
||||
| 1. Design Tokens + Rams Foundation | 0/TBD | Not started | - |
|
||||
| 2. Bot Skeleton + initData Security | 0/TBD | Not started | - |
|
||||
| 3. Mini App Shell + Geolocation | 0/TBD | Not started | - |
|
||||
| 4. Destination Search + KL Gazetteer | 0/TBD | Not started | - |
|
||||
| 5. Routing + Route Display | 0/TBD | Not started | - |
|
||||
| 6. Turn-by-Turn Guidance (Live Driving) | 0/TBD | Not started | - |
|
||||
| 7. Hardening + Private Launch | 0/TBD | Not started | - |
|
||||
|
||||
---
|
||||
*Roadmap created: 2026-10-22*
|
||||
@@ -0,0 +1,151 @@
|
||||
<!-- refreshed: 2026-10-21 -->
|
||||
# Architecture
|
||||
|
||||
**Analysis Date:** 2026-10-21
|
||||
|
||||
## System Overview
|
||||
|
||||
This is a **pre-implementation / design-phase project**. There is no backend, runtime code, package manifest, build tooling, or test suite yet. The current "architecture" consists of:
|
||||
|
||||
1. **Planning documents** at repo root (`DESIGN.md`, `IDEAS.md`) describing the product vision and target stack.
|
||||
2. **Static HTML UI mockups** (one directory per screen) under `stitch_minimalist_route_navigator/`, each self-contained and openable directly in a browser.
|
||||
|
||||
```text
|
||||
┌──────────────────────────────────────────────────────────────┐
|
||||
│ Current State: Static UI Mockups │
|
||||
├──────────────────┬──────────────────┬────────────────────────┤
|
||||
│ Mockup screens │ Design system │ Planning docs │
|
||||
│ stich_.../*/ │ telemetry_rams/ │ DESIGN.md │
|
||||
│ code.html │ DESIGN.md │ IDEAS.md │
|
||||
└──────────────────┴──────────────────┴────────────────────────┘
|
||||
|
||||
┌──────────────────────────────────────────────────────────────┐
|
||||
│ Implied Target Architecture (from IDEAS.md) │
|
||||
├───────────────────┬──────────────────────┬───────────────────┤
|
||||
│ Frontend │ Backend │ Data / Infra │
|
||||
│ Telegram bot + │ OSRM routing │ Neon Postgres │
|
||||
│ optional PWA │ (traffic weighting) │ (PostGIS) │
|
||||
│ (Cloudflare │ RabbitMQ queue │ Cloudflare R2 │
|
||||
│ Pages) │ Resend email │ Maptiler tiles │
|
||||
└───────────────────┴──────────────────────┴───────────────────┘
|
||||
```
|
||||
|
||||
## Component Responsibilities
|
||||
|
||||
| Component | Responsibility | File |
|
||||
|-----------|----------------|------|
|
||||
| `active_route_guidance/` | Turn-by-turn navigation HUD mockup: maneuver strip, incident telemetry band, map corridor viewport | `stitch_minimalist_route_navigator/active_route_guidance/code.html` |
|
||||
| `navigate_map_overview/` | Full-map navigation screen mockup: route rendering, layer toggles, recenter control | `stitch_minimalist_route_navigator/navigate_map_overview/code.html` |
|
||||
| `telegram_live_traffic_feed/` | Telegram-bot-styled traffic feed mockup: inline commands (`/traffic`, `/hazard`, `/status`, `/clear`), dispatch confirm | `stitch_minimalist_route_navigator/telegram_live_traffic_feed/code.html` |
|
||||
| `community_incident_reporter/` | Incident-report flow mockup: hazard drawer, modal report, incident type selection | `stitch_minimalist_route_navigator/community_incident_reporter/code.html` |
|
||||
| `telemetry_rams/DESIGN.md` | Formal design system spec (design tokens: colors, typography, spacing, breakpoints, component rules) | `stitch_minimalist_route_navigator/telemetry_rams/DESIGN.md` |
|
||||
| `DESIGN.md` | High-level Rams design philosophy: palette, typography, iconography, interaction flows | `DESIGN.md` |
|
||||
| `IDEAS.md` | Product vision, core principles, target stack outline, gamification and future ideas | `IDEAS.md` |
|
||||
|
||||
## Pattern Overview
|
||||
|
||||
**Overall:** Design-system-driven static mockup pattern (no application architecture exists yet).
|
||||
|
||||
**Key Characteristics:**
|
||||
- Each mockup screen is a **single self-contained HTML file** (`code.html`) with inline `<style>` and inline `<script>`. No shared CSS/JS modules, no bundler, no imports between screens.
|
||||
- Styling is Tailwind via **CDN script** (`https://cdn.tailwindcss.com`) with a per-file inline `tailwind.config` object encoding the design tokens (colors, borderRadius, spacing). No Tailwind build step.
|
||||
- Fonts and icons are loaded from CDNs: **Google Fonts** (Space Grotesk for headlines/telemetry, Geist for body) and **Material Symbols Outlined** for iconography.
|
||||
- Imagery is either **inline SVG** (route vectors, directional glyphs drawn with `stroke-linecap="square"`) or **remote hosted URLs** (`lh3.googleusercontent.com/aida/...` logo images) — no local image assets besides `screen.png` captures.
|
||||
- Interactivity is **vanilla JS via inline `onclick` handlers** only (demo stubs — e.g., `alert('Reroute broadcast loaded.')`). No state management, no routing, no data layer.
|
||||
|
||||
## Layers
|
||||
|
||||
**Current (mockup-only) layers:**
|
||||
- Presentation: `stitch_minimalist_route_navigator/*/code.html` — Tailwind markup + inline SVG + demo JS
|
||||
- Design tokens: `stitch_minimalist_route_navigator/telemetry_rams/DESIGN.md` (YAML front matter: `colors`, `typography`, `spacing`) duplicated as inline `tailwind.config` in each mockup's `<head>`
|
||||
- Specs/docs: `DESIGN.md`, `IDEAS.md` (root)
|
||||
|
||||
**Implied target layers (per `IDEAS.md`):**
|
||||
- Frontend: Telegram Bot interface + optional PWA hosted on Cloudflare Pages
|
||||
- Transport: Telegram API (bot commands, inline queries, location sharing)
|
||||
- Services: OSRM routing with dynamic traffic weighting; RabbitMQ for event queueing; Resend for email
|
||||
- Data: Neon (Postgres + PostGIS) for event/route storage; Cloudflare R2 for map snapshot storage; Maptiler for basemap tiles
|
||||
- Observability: Prometheus + Grafana
|
||||
|
||||
## Data Flow
|
||||
|
||||
### Mockup Screen Flow (current)
|
||||
|
||||
1. Open `code.html` in a browser (or view companion `screen.png` capture)
|
||||
2. Tailwind CDN applies design tokens from the inline `tailwind.config`
|
||||
3. Inline `onclick` handlers fire demo stubs (e.g., `insertCommand('/hazard ...')`, `closeHazardDrawer()`) — no persistence
|
||||
|
||||
### Implied Report Flow (target, per `DESIGN.md`)
|
||||
|
||||
1. User sends `/report accident` (with location) via Telegram bot
|
||||
2. Bot confirms; event stored in database (Postgres/PostGIS)
|
||||
3. Event broadcast to nearby users via bot feedback loop
|
||||
|
||||
### Implied Navigation Flow (target, per `DESIGN.md`)
|
||||
|
||||
1. User sends `/navigate origin → destination`
|
||||
2. OSRM computes route with traffic weighting
|
||||
3. Bot replies with text directions + grayscale map snapshot with accent overlays
|
||||
|
||||
**State Management:**
|
||||
- None today. Mockup JS is stateless demo handlers only. Nothing implies persistence patterns yet.
|
||||
|
||||
## Key Abstractions
|
||||
|
||||
**Design token set ("Telemetry Rams" system):**
|
||||
- Purpose: Single source of truth for colors, typography, spacing, component rules
|
||||
- Examples: `stitch_minimalist_route_navigator/telemetry_rams/DESIGN.md`, duplicated inline in each `code.html` `<head>` as `tailwind.config`
|
||||
- Pattern: YAML-front-matter spec → inline Tailwind config (manual duplication — a known inconsistency risk)
|
||||
|
||||
**Screen directory contract:**
|
||||
- Each screen is one directory holding exactly `code.html` (the mockup) and `screen.png` (a visual capture)
|
||||
- Examples: all four screen directories under `stitch_minimalist_route_navigator/`
|
||||
|
||||
**Incident/traffic domain concepts (documented, not implemented):**
|
||||
- Event types appear consistently across docs and mockups: CONGESTION (traffic/orange), ACCIDENT/CRASH-BLOCK (red), POLICE RADAR / SPEED_TRAP (green)
|
||||
- Examples: `stitch_minimalist_route_navigator/telegram_live_traffic_feed/code.html` (`confirmDispatch('CONGESTION')`, `confirmDispatch('CRASH / BLOCK')`, `confirmDispatch('POLICE RADAR')`)
|
||||
|
||||
## Entry Points
|
||||
|
||||
**Static mockup entry points (operational today):**
|
||||
- Location: `stitch_minimalist_route_navigator/<screen>/code.html` for each of the four screens
|
||||
- Triggers: opening the file directly in a browser (`file://` works — all dependencies are CDN-hosted)
|
||||
- Responsibilities: render the screen for design review; demo-interactions via inline handlers
|
||||
|
||||
**No application entry points exist** — there is no `src/`, `main.*`, `index.*`, `server.*`, package manifest, or container config.
|
||||
|
||||
## Architectural Constraints
|
||||
|
||||
- **Runtime:** None required for mockups; plain browser. An internet connection is required (Tailwind CDN, Google Fonts, remote images).
|
||||
- **Global state:** None. Each mockup is fully isolated; no shared modules exist.
|
||||
- **Circular imports:** Not applicable (no modules).
|
||||
- **Token duplication:** The palette/typography/spacing defined in `telemetry_rams/DESIGN.md` is hand-copied into every mockup's inline `tailwind.config`. Any token change must be replicated N times until a real build pipeline exists.
|
||||
- **Windows Zone.Identifier files:** `*:Zone.Identifier` metadata files are scattered throughout and should be excluded from any future build/lint tooling.
|
||||
|
||||
## Anti-Patterns (recommendations for the target codebase)
|
||||
|
||||
### Per-file Tailwind config duplication
|
||||
|
||||
**What happens:** Each mockup re-declares the full design-token set inline.
|
||||
**Why it's wrong:** Tokens drift between screens; changing a color requires editing every file.
|
||||
**Do this instead:** When real frontend work begins, centralize tokens in a single Tailwind config / CSS variables file consumed by all screens (source it from `telemetry_rams/DESIGN.md`).
|
||||
|
||||
### Inline onclick demo handlers
|
||||
|
||||
**What happens:** Behavior lives in `onclick="..."` attributes calling inline functions (`alert()` stubs).
|
||||
**Why it's wrong:** Untestable and unrefactorable; acceptable only for visual demo mockups.
|
||||
**Do this instead:** Structure real code with separated modules, event listeners, and a typed frontend framework per `IDEAS.md`.
|
||||
|
||||
## Error Handling
|
||||
|
||||
**Strategy:** None exists. No backend, no error states implemented. The design system only reserves Functional Red (`#ED3F1C`) for warnings/hazards/terminal errors (`stitch_minimalist_route_navigator/telemetry_rams/DESIGN.md`).
|
||||
|
||||
## Cross-Cutting Concerns
|
||||
|
||||
**Logging:** Not implemented; target stack names Prometheus + Grafana (`IDEAS.md`).
|
||||
**Validation:** Not implemented; target implies Telegram command/location validation.
|
||||
**Authentication:** Not implemented; target is Telegram-identity-based (bot commands per user), no other auth mentioned.
|
||||
|
||||
---
|
||||
|
||||
*Architecture analysis: 2026-10-21*
|
||||
@@ -0,0 +1,148 @@
|
||||
# Codebase Concerns
|
||||
|
||||
**Analysis Date:** 2026-10-21
|
||||
|
||||
**Repo state:** Early-stage design-only project. No git repo, no package manifest, no tests, no backend. Content is two planning docs (`DESIGN.md`, `IDEAS.md`) plus the `stitch_minimalist_route_navigator/` directory of Stitch-generated HTML UI mockups (4 screens with `code.html` + `screen.png`, 1 design-system doc).
|
||||
|
||||
---
|
||||
|
||||
## Tech Debt
|
||||
|
||||
**Directory hygiene: Windows `*:Zone.Identifier` metadata files committed alongside assets**
|
||||
- Issue: Every downloaded asset carries an NTFS Alternate Data Stream export (`*:Zone.Identifier` files) from unzipping on Windows. Top-level `DESIGN.md` and `IDEAS.md` have no counterparts, but 10 of the mockup assets do (e.g., `stitch_minimalist_route_navigator/active_route_guidance/code.html:Zone.Identifier`).
|
||||
- Files: all `stitch_minimalist_route_navigator/*/*:Zone.Identifier` (10 files — one per `code.html` and per `screen.png` in the four screen directories)
|
||||
- Impact: Noise pollution in every glob/grep operation, misleading file listings, and potential pipeline breakage when tooling glob patterns accidentally match these files as HTML/PNG sources. Their one-time content even leaked a local Windows path (`X:\Donlod\...zip`) — a minor information-disclosure artifact.
|
||||
- Fix approach: Delete all `*:Zone.Identifier` files now (`find . -name "*:Zone.Identifier" -delete`). Once a git repo is initialized, add a `.gitignore` blocking the pattern and add a pre-commit or CI hygiene check. Never treat these files as content sources.
|
||||
|
||||
**No version control, no ignores file**
|
||||
- Issue: There is no `.git` directory and no `.gitignore` at the repo root. All work exists only on disk.
|
||||
- Files: repo root (`/home/C-Fu/araharah/`)
|
||||
- Impact: Any accidental delete loses the only copy of the mockups and design docs; no change history for iterating on screens; the Zone.Identifier debt described above has no automated guard.
|
||||
- Fix approach: `git init` as the very first implementation step, with a `.gitignore` covering `*:Zone.Identifier`, OS junk (`.DS_Store`, `Thumbs.db`), and future `node_modules/` / secrets.
|
||||
|
||||
**Four copies of the same ~5KB inline Tailwind theme config**
|
||||
- Issue: Each `code.html` embeds the full `tailwind.config={...}` design-token block (colors, fontSize, spacing, fontFamily) as a duplicate inline `<script id="tailwind-config">`. It is byte-for-byte identical across all four screens (tokens match `stitch_minimalist_route_navigator/telemetry_rams/DESIGN.md:2-148`), so ~20KB of the 94KB total is pure duplication.
|
||||
- Files: `stitch_minimalist_route_navigator/active_route_guidance/code.html`, `stitch_minimalist_route_navigator/community_incident_reporter/code.html`, `stitch_minimalist_route_navigator/navigate_map_overview/code.html`, `stitch_minimalist_route_navigator/telegram_live_traffic_feed/code.html`
|
||||
- Impact: Any token change (e.g., palette tweak) must be edited in four places; a single missed copy silently diverges the visual system between screens.
|
||||
- Fix approach: When prototype-grade tooling is introduced, extract the token block to a single shared config (Tailwind `.js` config or CSS custom properties) and reference it from a built stylesheet. Until then, enforce a note that these are throwaway artifacts not to be edited in place.
|
||||
|
||||
**Single-line minified HTML in mockups**
|
||||
- Issue: The `code.html` files are Stitch exports with entire documents collapsed onto one or two extremely long lines (e.g., head + body markup as a single line), only the `<style>` and comment blocks are broken out.
|
||||
- Files: all four `stitch_minimalist_route_navigator/*/code.html`
|
||||
- Impact: Impossible to diff meaningfully, painful to hand-edit, and grep context output is unusable (one "line" contains the whole document).
|
||||
- Fix approach: Treat these as generated, read-only reference artifacts. If they must be edited, run them through a formatter (Prettier) once and keep the formatted copy under version control going forward.
|
||||
|
||||
---
|
||||
|
||||
## Design-Source-of-Truth Conflicts (Fragile Areas)
|
||||
|
||||
**Two competing design systems in the same repo**
|
||||
- Issue: Root `DESIGN.md` specifies Helvetica Neue/Inter, 14px body / 18px headings / 24px titles, and a 5-color palette (`DESIGN.md:17-35`). Meanwhile `stitch_minimalist_route_navigator/telemetry_rams/DESIGN.md:59-148` specifies Space Grotesk + Geist, an entire Material-style token set (surface containers, fixed/variant colors), and the actual mockups implement the *latter* (their inline Tailwind config uses `Space Grotesk`/`Geist` and ~40 token colors, not Helvetica/Inter with 5 colors).
|
||||
- Files: `DESIGN.md`, `stitch_minimalist_route_navigator/telemetry_rams/DESIGN.md`
|
||||
- Impact: A future implementer reading the top-level `DESIGN.md` will code against the wrong typography and palette. The repo's "canonical" design doc contradicts its own reference implementation.
|
||||
- Safe modification: Decide which doc wins (recommend promoting `telemetry_rams/DESIGN.md` to root design authority since the mockups match it), mark the loser as superseded or delete it, and state a single-file-of-truth rule before any UI phase.
|
||||
|
||||
**Mockups violate their own zero-roundedness / anti-flat-glow rules**
|
||||
- Issue: `telemetry_rams/DESIGN.md:206-208` mandates "absolute zero roundedness (0px corner radius)" and rejects blurs/frosted glass (`DESIGN.md:196`), yet the mockups contain `rounded-full`/rounded classes (e.g., avatar circles, chips in `active_route_guidance/code.html`, ~5 occurrences) and a `backdrop-blur-xl shadow-[0_1px_8px_rgba(0,0,0,0.04)]` header in `active_route_guidance/code.html`.
|
||||
- Files: `stitch_minimalist_route_navigator/active_route_guidance/code.html` (header, avatar), `stitch_minimalist_route_navigator/community_incident_reporter/code.html`
|
||||
- Impact: Screens are a compromised reference; copying markup into the real app would import non-Rams ornament that the design doc forbids.
|
||||
- Safe modification: When implementing, treat the *design doc* token rules as binding and the *mockup markup* as layout reference only; scrub rounded/blur utilities during implementation.
|
||||
|
||||
---
|
||||
|
||||
## Mockup Fragility / Runtime Dependencies
|
||||
|
||||
**Runtime Tailwind CDN + third-party CDN single points of failure**
|
||||
- Issue: Every screen loads Tailwind as an uncompiled runtime script from `https://cdn.tailwindcss.com` (officially "not for production"), plus Google Fonts (Geist, Space Grotesk), Material Symbols Outlined, and a `lh3.googleusercontent.com` logo image. There is no vendoring, no build step, and no `package.json`; the screens render correctly only with internet access to these CDNs.
|
||||
- Files: `<head>` of all four `stitch_minimalist_route_navigator/*/code.html`
|
||||
- Trigger: Open offline, or when the ephemeral Google-hosted logo URL expires.
|
||||
- Workaround: None in-repo. This is fine for mockups but disqualifies the files from production use as-is.
|
||||
- Fix approach: For the real app, use a compiled Tailwind build (this happens naturally once any framework/tooling phase runs). Download the logo asset locally if it is to be reused.
|
||||
|
||||
**Hardcoded mock data and dead-end interactions**
|
||||
- Issue: Navigation/route data, telemetry numbers, hazard cards, and traffic feed messages are hardcoded `const` arrays/objects inside each screen; handlers are inline `onclick` stubs (`confirmDispatch('CONGESTION')`, `toggleHazardCard('ACCIDENT')` in `navigate_map_overview/code.html`; `insertCommand('/hazard ')` and `alert('Reroute broadcast loaded.')` in `telegram_live_traffic_feed/code.html`). No fetch calls, no map tiles, no routing engine — the "map" is a static styled panel.
|
||||
- Files: all four `stitch_minimalist_route_navigator/*/code.html` (`<script>` block at end of each file)
|
||||
- Impact: The mockups give no signal about the hard part (OSRM routing, live Telegram feed, geographic event storage in PostGIS); estimating implementation effort from these screens alone will be badly optimistic.
|
||||
- Fix approach: Treat mock data shapes as informal UI contracts (the `const` structures are a reasonable starting point for real data models) but plan backend/integration phases before promising any of the flows in `DESIGN.md:69-73`.
|
||||
|
||||
**Shell-specific assumptions baked in**
|
||||
- Issue: The screens carry `<meta name="shell-type" content="mobile_stack">`, `user-scalable=no`, fixed `884px`-min-height bodies, and hidden scrollbars (`::-webkit-scrollbar{display:none}`) — targeting a specific mobile embed/stitch render shell rather than standalone browsers.
|
||||
- Files: `<head>`/`<style>` of all four `stitch_minimalist_route_navigator/*/code.html`
|
||||
- Impact: Accessibility regression (`user-scalable=no` blocks pinch zoom; contrast and zoom rules conflict), and layout breaks if opened directly on desktop or inside a nonstandard webview.
|
||||
- Fix approach: Strip `user-scalable=no` and shell-only metas when porting; these are mockup artifacts, not app requirements.
|
||||
|
||||
---
|
||||
|
||||
## Architecture / Roadmap Reality Gaps
|
||||
|
||||
**Heavyweight target stack vs. zero implemented code**
|
||||
- Issue: `IDEAS.md:55-73` specifies a full production architecture: Telegram Bot + PWA, Neon Postgres+PostGIS, OSRM with dynamic traffic weighting, Maptiler tiles, RabbitMQ queue, Cloudflare R2, Prometheus/Grafana, Resend email. Nothing in the repo implements even one of these components — there is no source code at all, no `package.json`, and no CI.
|
||||
- Files: `IDEAS.md`, repo root
|
||||
- Impact: Highest-value concern: the gap between the mockups (static UI shells) and the vision (distributed multi-service system) is the entire engineering project. Prioritizing infrastructure (RabbitMQ, Grafana, R2) before a walking-skeleton bot + OSRM round-trip would be premature.
|
||||
- Fix approach: Sequence phases as: git init → walking-skeleton Telegram bot echoing commands → OSRM route round-trip → PostGIS event storage → then queue/monitoring/storage. Treat unneeded services (RabbitMQ, Resend, Prometheus) as explicitly deferred, not part of an MVP.
|
||||
|
||||
**Undefined design ambiguity: "minimal single-file" vs. scalable app**
|
||||
- Issue: Nothing in the repo states what runtime the eventual product uses (plain web app?, PWA?, Telegram WebApp embed?). The mockups' inline CSS/JS monolith pattern will not scale: 4 screens already total ~98KB of duplicated tokens and copy-pasted utility classes; at 10–20 screens this pattern guarantees drift described in the Tailwind-duplication section.
|
||||
- Files: `IDEAS.md:57-58` ("Telegram-first: ... optional PWA"), `stitch_minimalist_route_navigator/*`
|
||||
- Impact: Blocks any implementation phase from starting correctly; the first framework decision will retroactively invalidate markup assumptions from all mockups.
|
||||
- Fix approach: Make the runtime/format decision (e.g., Next.js PWA served in Telegram WebApp, React + compiled Tailwind, shared token file) in a dedicated setup phase before porting any mockup.
|
||||
|
||||
---
|
||||
|
||||
## Security Considerations
|
||||
|
||||
**Leaked local path in committed metadata**
|
||||
- Risk: `*:Zone.Identifier` files record source download URLs; the one inspectable case contains `ReferrerUrl=X:\Donlod\...zip`, disclosing a filesystem path pattern.
|
||||
- Files: `stitch_minimalist_route_navigator/*/*:Zone.Identifier`
|
||||
- Current mitigation: None (no git repo, no CI, no scrubbing step).
|
||||
- Recommendations: Delete the files (see Tech Debt #1); if a git repo is initialized without cleaning, this path is forever in history.
|
||||
|
||||
**No secrets to leak — but no key management either**
|
||||
- Risk: Trivially low today (no code), but the target stack requires Telegram bot tokens, Maptiler keys, and Neon credentials with no designed home for them.
|
||||
- Files: none yet
|
||||
- Current mitigation: None.
|
||||
- Recommendations: Establish `.env` + `.env.example` + `secretlint` toggle in `.gitignore` during the first setup phase, *before* any real credentials exist.
|
||||
|
||||
**Nondeterministic third-party scripts running on every mockup open**
|
||||
- Risk: `cdn.tailwindcss.com` bundles and executes a JIT compiler in-page; any CDN compromise or the service's eventual shutdown changes/breaks behavior silently. Low stakes while these are mockups, but relevant the moment anyone shares them with stakeholders as "the product."
|
||||
- Files: all four `stitch_minimalist_route_navigator/*/code.html` `<head>`
|
||||
- Recommendations: Keep communicating they are mockups; for any public demo, pin/snapshot the CDN output locally first.
|
||||
|
||||
## Performance Bottlenecks
|
||||
|
||||
Not yet applicable — no runtime code exists. For the record: the mockups render fine despite the runtime-Tailwind approach, but that approach bleeds ~300KB of compiler JS before first paint, which would be a bottleneck in the real app and is eliminated by compiled Tailwind.
|
||||
|
||||
## Scaling Limits
|
||||
|
||||
**Mockup pattern scales to zero screens**
|
||||
- Problem: Per-file token duplication on 4 screens is already at the maintainability ceiling; the repo cannot accommodate 10+ screens without guaranteed divergence.
|
||||
- Cause: No shared stylesheet/config; Stitch exports are atomic single files.
|
||||
- Files: all four `stitch_minimalist_route_navigator/*/code.html`
|
||||
- Improvement path: Extract tokens and shared chrome into the real app's component/config layer during the first implementation phase.
|
||||
|
||||
## Dependencies at Risk
|
||||
|
||||
**`cdn.tailwindcss.com` (runtime CDN)**
|
||||
- Risk: Unpinned, production-discouraged, service availability not guaranteed; a change or outage breaks all four mockups at once.
|
||||
- Impact: Mockups stop rendering properly; no local fallback exists.
|
||||
- Migration plan: Compiled Tailwind via any JS tooling in the first build phase; for the repo's mockups, snapshot locally if they need to survive long-term.
|
||||
|
||||
**Google Fonts + `lh3.googleusercontent.com` assets**
|
||||
- Risk: Fonts load only online; the AI-generated logo URL is ephemeral and is referenced identically in all four files — if it dies, branding breaks everywhere simultaneously with no local replacement.
|
||||
- Files: `stitch_minimalist_route_navigator/active_route_guidance/code.html` and the three sibling `<head>`s
|
||||
- Migration plan: Download the logo into the repo asset tree; self-host fonts (or subset) in the real app.
|
||||
|
||||
## Missing Critical Features
|
||||
|
||||
**Everything is missing by design** — no code, no tests, no CI, no manifest, no git, no `README`. The notable early gaps to plan explicitly:
|
||||
- Problem: No `README.md` explaining the repo's purpose, no license, no git history, no developer tooling config (editor/lint/format), no `package.json` even for tooling.
|
||||
- Blocks: Onboarding anyone (or any future agent session) requires re-deriving context from `IDEAS.md`/`DESIGN.md` every time; the Zone.Identifier debt and doc conflicts above go unnoticed indefinitely.
|
||||
- Fix approach: Preface the first phase with "project setup": git init, README capturing the Rams design intent and pointing to the authoritative design doc, `.gitignore`, and license.
|
||||
|
||||
## Test Coverage Gaps
|
||||
|
||||
Not applicable — there is nothing to test yet. When the first real code lands, note that the repo has zero testing conventions to inherit from; `TESTING.md` will need to be generated fresh alongside the first implementation phase.
|
||||
|
||||
---
|
||||
|
||||
*Concerns audit: 2026-10-21*
|
||||
@@ -0,0 +1,133 @@
|
||||
# Coding Conventions
|
||||
|
||||
**Analysis Date:** 2026-10-21
|
||||
|
||||
> **Scope caveat:** This is a pre-implementation design repository. There is **no source code,
|
||||
> no package manifest, no linter/formatter config, and no build system** in the repo yet
|
||||
> (no `package.json`, `.eslintrc*`, `.prettierrc*`, `tsconfig.json`, or `.gitignore` exists).
|
||||
> The only code is static HTML/Tailwind mockups under
|
||||
> `stitch_minimalist_route_navigator/`. Conventions below are extracted from those mockups
|
||||
> and the design-system docs, and should be treated as the de-facto starting point for any
|
||||
> future implementation code.
|
||||
|
||||
## Established Document Conventions
|
||||
|
||||
**Design system declaration:**
|
||||
- The design system lives in `stitch_minimalist_route_navigator/telemetry_rams/DESIGN.md`
|
||||
as a YAML frontmatter block (`name`, `colors`, `typography`, `spacing`) followed by
|
||||
prose sections (Brand & Style, Colors, Typography, Layout & Spacing, Elevation & Depth,
|
||||
Shapes, Components).
|
||||
- Core philosophy docs are plain prose at repository root: `DESIGN.md` (Rams principles,
|
||||
8px grid, color palette, component rules) and `IDEAS.md` (vision, architecture targets,
|
||||
gamification ideas). Both end with the motto line
|
||||
"Good design is as little design as possible." — Dieter Rams.
|
||||
|
||||
**Token vocabulary (use these names verbatim in any new code):**
|
||||
- Colors, kebab-case: `signal-orange` (#EB8008), `functional-red` (#ED3F1C),
|
||||
`olive-green` (#736B1E), `soft-beige` (#D9D2C6), `matte-black` (#1A1A1A),
|
||||
`chassis-subtle` (#CCC4B5), `surface-dark` (#121212), `pure-white` (#FFFFFF).
|
||||
Full Material-style surface/on-surface scale is declared in the frontmatter of
|
||||
`stitch_minimalist_route_navigator/telemetry_rams/DESIGN.md`.
|
||||
- Typography scale, kebab-case: `display-lg`, `headline-lg`, `headline-md`, `headline-sm`,
|
||||
`body-lg`, `body-md`, `body-sm`, `label-lg`, `label-md`, `label-sm`, `telemetry-num`.
|
||||
- Spacing, kebab-case: `gutter`, `gutter-desktop`, `margin`, `margin-desktop`,
|
||||
`space-xs` … `space-2xl`. All dimensions MUST be multiples of 4px/8px.
|
||||
|
||||
## Naming Patterns
|
||||
|
||||
**Directories:**
|
||||
- `snake_case`, name = the screen/feature being mocked up:
|
||||
`stitch_minimalist_route_navigator/active_route_guidance/`,
|
||||
`stitch_minimalist_route_navigator/navigate_map_overview/`,
|
||||
`stitch_minimalist_route_navigator/community_incident_reporter/`,
|
||||
`stitch_minimalist_route_navigator/telegram_live_traffic_feed/`.
|
||||
|
||||
**Files (fixed within every screen directory):**
|
||||
- `code.html` — the generated mockup markup for that screen.
|
||||
- `screen.png` — the rendered screenshot of the same screen. Never rename these;
|
||||
tooling and review flows key on the pair `<screen_dir>/code.html` + `<screen_dir>/screen.png`.
|
||||
- `DESIGN.md` (where present) — design-system doc for that screen group.
|
||||
|
||||
**Design tokens / classes:** kebab-case (`bg-matte-black`, `text-signal-orange`,
|
||||
`border-functional-red`). Do not introduce camelCase or snake_case class names.
|
||||
|
||||
## HTML Mockup Style (observed in `code.html` files)
|
||||
|
||||
**Structure:**
|
||||
- One self-contained HTML file per screen; first `<head>` line is a dense set of
|
||||
`<meta>`/preconnect/font links, incl. Google Fonts `Geist` + `Space Grotesk` and
|
||||
`Material Symbols Outlined`.
|
||||
- Tailwind is loaded via CDN (`https://cdn.tailwindcss.com`) with an inline
|
||||
`tailwind.config` script that extends `colors`, `borderRadius`, `spacing`, fonts.
|
||||
Every one of the four `code.html` files duplicates this exact config block — keep it
|
||||
in sync if tokens change.
|
||||
- Body uses semantic structure: `<header>` (fixed, h-16), `<main>` (flex-1), with content
|
||||
sections as `<section>` blocks; each major section preceded by an UPPER_SNAKE
|
||||
descriptive comment, e.g. `<!-- Turn-by-Turn Maneuver HUD (Matte Black Primary Chassis) -->`
|
||||
(`stitch_minimalist_route_navigator/active_route_guidance/code.html:10`,
|
||||
`<!-- Incident Telemetry Band -->` at line 44).
|
||||
- Fine-grained comments use PascalCase-ish descriptive style:
|
||||
`<!-- Lane Assignment Matrix -->`, `<!-- Position Puck (Dieter Rams Instrument Style) -->`.
|
||||
|
||||
**Visual rules enforced by the design system (from `telemetry_rams/DESIGN.md`):**
|
||||
- Zero border radius (`0px`) on all containers, buttons, cards, badges, inputs.
|
||||
- No shadows-with-blur, no frosted glass, no faux 3D; hierarchy via `1px`/`2px` solid
|
||||
`#1A1A1A` rules and background shifts (`soft-beige` → `chassis-subtle`).
|
||||
- Uppercase labels with expanded tracking (`tracking-wider`/`tracking-widest` on
|
||||
`label-*` classes); alphanumeric reference badges in the form `SEC-04 // SPEED`,
|
||||
`CH-08`, `NEXT MANEUVER // T-01`.
|
||||
- Icons: Material Symbols or inline `<svg>` with uniform stroke weights (2px standard,
|
||||
3–4px in HUD), `stroke-linecap="square"`, `stroke-linejoin="miter"`.
|
||||
- Color semantics are strict: orange = navigation/primary action, red = hazards/errors only,
|
||||
olive green = safe/confirmation, map imagery grayscale.
|
||||
|
||||
**Comment density:** section-level comments only — no per-element commentary. Keep this.
|
||||
|
||||
## JavaScript (inline in mockups only)
|
||||
|
||||
- Vanilla, no framework, small inline `<script>` block at end of body.
|
||||
- Functions are `camelCase`, verb-first, one per interaction:
|
||||
`initBraunConsole`, `updatePreview`
|
||||
(`stitch_minimalist_route_navigator/community_incident_reporter/code.html:159-177`);
|
||||
`toggleHazardCard`, `reportHazardModal`, `closeHazardDrawer`, `confirmDispatch`,
|
||||
`triggerQuickDispatch`, `pulseRecenter`, `toggleLayers`
|
||||
(`stitch_minimalist_route_navigator/navigate_map_overview/code.html:266-323`);
|
||||
`insertCommand` (`stitch_minimalist_route_navigator/telegram_live_traffic_feed/code.html:235`).
|
||||
- Interaction is triggered via inline `onclick="…"` on buttons (mockups are
|
||||
demonstration-only; do not carry this pattern into production code — use real event
|
||||
listeners/framework handlers when real code exists).
|
||||
|
||||
## Where Conventions Are NOT Yet Established
|
||||
|
||||
The following have no governance in the repo and must be decided/pinned when real code
|
||||
starts:
|
||||
|
||||
- **Languages/runtime:** no manifest declares TypeScript/JavaScript versions, Node, or
|
||||
package manager (no `package.json`, `go.mod`, `pyproject.toml` anywhere).
|
||||
- **Formatting & linting:** no Prettier/ESLint/Biome/editorconfig. HTML mockups are
|
||||
generated with minified head lines and expanded body lines; treat as generator output,
|
||||
not hand-formatted style.
|
||||
- **Module layout / imports:** no application code, no `src/`, no import graph.
|
||||
- **Error handling, logging, validation:** no code exists to define patterns for these.
|
||||
- **Git hygiene:** the workspace directory is not yet a git repository; when initialized,
|
||||
add a `.gitignore` and commit `DESIGN.md`, `IDEAS.md`, `stitch_minimalist_route_navigator/*`.
|
||||
- **Path casing:** any backend service (Telegram bot, OSRM, Neon/Postgres — the stack
|
||||
sketched in `IDEAS.md:55-73`) should follow the existing `snake_case` directory naming
|
||||
for consistency.
|
||||
|
||||
## Prescriptive Guidance for New Code
|
||||
|
||||
1. **New mockup screen:** create `stitch_minimalist_route_navigator/<new_screen_snake_case>/`
|
||||
with `code.html` and `screen.png`. State which design tokens it uses; do not invent
|
||||
new colors without adding them to the frontmatter of
|
||||
`stitch_minimalist_route_navigator/telemetry_rams/DESIGN.md` first.
|
||||
2. **New design token:** update the YAML block in
|
||||
`stitch_minimalist_route_navigator/telemetry_rams/DESIGN.md`, then replicate the token
|
||||
into the inline `tailwind.config` of **all four** existing `code.html` files.
|
||||
3. **First real implementation code:** before writing it, codify the above — add a package
|
||||
manifest, formatter/linter config, and a source directory; mirror `camelCase` for
|
||||
functions, `kebab-case` for classes/CSS tokens, `snake_case` for directories.
|
||||
|
||||
---
|
||||
|
||||
*Convention analysis: 2026-10-21*
|
||||
@@ -0,0 +1,104 @@
|
||||
# External Integrations
|
||||
|
||||
**Analysis Date:** 2026-10-21
|
||||
|
||||
## Project Maturity Note
|
||||
|
||||
There is **no running integration code** in this repository yet — no backend, no SDK packages, no environment files. This document is based on what is *actually wired* in the static mockups plus the integration architecture explicitly declared in `IDEAS.md` ("Architecture Overview") and `DESIGN.md` ("Interaction Flows"). Items marked **[actual]** are live CDN dependencies; items marked **[planned]** are targets for the first implementation and should be verified/re-selected when that phase is planned.
|
||||
|
||||
## APIs & External Services
|
||||
|
||||
**Bot Transport (planned — the product's primary "frontend"):**
|
||||
- Telegram Bot API — commands and inline queries for incident reports and navigation (`IDEAS.md`: "Telegram-first")
|
||||
- SDK/Client: not chosen yet; no package installed
|
||||
- Auth: bot token (env var to be introduced; none exists)
|
||||
- Command surface from `DESIGN.md` / `IDEAS.md`: `/report accident|traffic|hazard` with location share, `/navigate origin → destination`, geohash-style broadcast of nearby events
|
||||
|
||||
**Routing (planned):**
|
||||
- OSRM — route computation with "dynamic traffic weighting" (`IDEAS.md`; also `DESIGN.md` flow: `/navigate origin → destination → OSRM route → text directions + map snapshot`)
|
||||
- SDK/Client: none; OSRM is a plain HTTP API
|
||||
- Auth: none required for self-hosted; hosting decision (self-host vs public server) not yet made
|
||||
|
||||
**Map Tiles (planned):**
|
||||
- Maptiler — map tiles for grayscale map snapshots (`IDEAS.md`, `DESIGN.md` "Map Snapshots: Grayscale tiles with accent overlays")
|
||||
- SDK/Client: none; HTTP tile API
|
||||
- Auth: API key (to be added to env config)
|
||||
|
||||
**CDN services actually referenced by the mockups [actual]:**
|
||||
- `cdn.tailwindcss.com` — Tailwind Play CDN script, in all four screens (`*`/`code.html`)
|
||||
- `fonts.googleapis.com` + `fonts.gstatic.com` — Geist, Space Grotesk, Material Symbols Outlined
|
||||
- `lh3.googleusercontent.com/aida/...` — placeholder screenshot URLs embedded in mockups (tool-generated assets, should be replaced by project-generated images before reuse)
|
||||
|
||||
**Email (planned, low priority):**
|
||||
- Resend — transactional email (`IDEAS.md`). Purpose is not specified further; may not be needed for the MVP.
|
||||
|
||||
## Data Storage
|
||||
|
||||
**Databases:**
|
||||
- Neon — serverless Postgres with PostGIS extension for spatial queries (`IDEAS.md`) [planned]
|
||||
- Connection: env var to be introduced (none exists)
|
||||
- Client/ORM: none chosen yet
|
||||
- Spatial needs: storing incident reports with coordinates + "broadcast nearby" radius queries (PostGIS ` geography` point search)
|
||||
|
||||
**File Storage:**
|
||||
- Cloudflare R2 — blob storage for map snapshots/UAV-style images (`IDEAS.md`) [planned]
|
||||
- Current mockup screens store images as static `screen.png` files locally; no storage integrated
|
||||
|
||||
**Caching:**
|
||||
- None integrated; none planned explicitly. Route/traffic data caching is implied if OSRM traffic weighting is implemented, but not documented.
|
||||
|
||||
## Authentication & Identity
|
||||
|
||||
**Auth Provider:**
|
||||
- None [actual]
|
||||
- Planned: Telegram identity is the implicit identity layer — the bot sees `chat_id`/`user_id` directly from Telegram (`IDEAS.md` gamification: points and leaderboards via Telegram bot). No separate auth system is documented; a first implementation should treat Telegram user IDs as the primary key and require no passwords.
|
||||
|
||||
## Monitoring & Observability
|
||||
|
||||
**Error Tracking:**
|
||||
- None [actual]
|
||||
|
||||
**Metrics (planned):**
|
||||
- Prometheus + Grafana — monitoring stack named in `IDEAS.md`; exporters/what-to-observe not yet defined.
|
||||
|
||||
**Logs:**
|
||||
- Not detected. No logging framework or convention exists yet.
|
||||
|
||||
## CI/CD & Deployment
|
||||
|
||||
**Hosting (planned):**
|
||||
- Cloudflare Pages — for the optional PWA (`IDEAS.md`). Backend bot hosting platform is **undecided** (no doc names one).
|
||||
|
||||
**CI Pipeline:**
|
||||
- None [actual]. No workflow/CI config files exist.
|
||||
|
||||
## Webhooks & Callbacks
|
||||
|
||||
**Incoming:**
|
||||
- None [actual]
|
||||
- Planned: Telegram webhook for bot updates (polling vs webhook not yet decided — choose during first backend phase)
|
||||
|
||||
**Outgoing:**
|
||||
- None [actual]
|
||||
- Planned: none required by design; bot notifications to users are bot API calls, not webhooks
|
||||
|
||||
## Environment Configuration
|
||||
|
||||
**Required env vars (none exist yet — this is the target list for the first backend phase):**
|
||||
- Telegram bot token
|
||||
- Neon database URL (with `?sslmode=require` and PostGIS-enabled DB)
|
||||
- Maptiler API key
|
||||
- OSRM base URL (+ optional traffic-weighting config)
|
||||
- Cloudflare R2 credentials (account ID, access key, secret, bucket) — **only if** snapshot storage is implemented in R2
|
||||
- Resend API key (optional; likely defer avoid until email feature is justified)
|
||||
|
||||
**Secrets location:**
|
||||
- Nothing exists. `.env` files are not present and should **not** be committed when introduced; no `.gitignore` exists yet — create one before adding any secret to disk (the repo is not currently a git repository).
|
||||
|
||||
## Gamification (planned feature, needs platform choices)
|
||||
|
||||
- Points for validated reports + leaderboards served through the Telegram bot (`IDEAS.md`). Requires: user scoring tables in Neon Postgres; no external service implied beyond Telegram itself.
|
||||
|
||||
---
|
||||
|
||||
*Integration audit: 2026-10-21*
|
||||
@@ -0,0 +1,89 @@
|
||||
# Technology Stack
|
||||
|
||||
**Analysis Date:** 2026-10-21
|
||||
|
||||
## Project Maturity
|
||||
|
||||
This is an **early-stage, design-only project**. There is no running application code yet — no backend, no package manager, no build tooling. The repository contains:
|
||||
|
||||
- Concept and design-system documents: `DESIGN.md`, `IDEAS.md`
|
||||
- A design-system extension: `stitch_minimalist_route_navigator/telemetry_rams/DESIGN.md` (frontmatter-structured design tokens for colors, typography, spacing)
|
||||
- Static HTML UI mockup screens (one `code.html` + `screen.png` per screen) — these are the **only executable code** in the repo
|
||||
- Planning outputs: `.planning/` (not product code)
|
||||
|
||||
The stack below is split into (A) **what actually exists today** and (B) **what the design docs imply for the first implementation**. Executors should treat (A) as the working environment and (B) as planned targets, not existing facts.
|
||||
|
||||
## Languages
|
||||
|
||||
**Primary:**
|
||||
- HTML 5 — the four mockup screens: `stitch_minimalist_route_navigator/active_route_guidance/code.html`, `stitch_minimalist_route_navigator/navigate_map_overview/code.html`, `stitch_minimalist_route_navigator/community_incident_reporter/code.html`, `stitch_minimalist_route_navigator/telegram_live_traffic_feed/code.html` (each self-contained, inline `<script>` Tailwind config, minimal inline JS for markup behavior)
|
||||
|
||||
**Secondary:**
|
||||
- Markdown — design docs (`DESIGN.md`, `IDEAS.md`, `stitch_minimalist_route_navigator/telemetry_rams/DESIGN.md`)
|
||||
|
||||
**Implied (target implementation per `IDEAS.md`):**
|
||||
- A backend language/runtime for the Telegram bot (not yet chosen in any doc; nothing in the repo constrains it)
|
||||
|
||||
## Runtime
|
||||
|
||||
**Environment:**
|
||||
- None installed. No `package.json`, no `requirements.txt`, no lockfile, no `.nvmrc`, no CI config, no test config anywhere in the repo.
|
||||
- Mockups run by opening `code.html` directly in a browser (CDN-based dependencies, no local dev server required).
|
||||
|
||||
## Frameworks
|
||||
|
||||
**Core (in use today, via CDN in mockups):**
|
||||
- Tailwind CSS via Play CDN (`https://cdn.tailwindcss.com`) — loaded as a `<script>` tag with an inline `tailwind.config` block defining the full "Telemetry Rams" theme (colors like `signal-orange`, `matte-black`, `soft-beige`; fonts; spacing/border-radius tokens). Present in all four mockup screens.
|
||||
- Google Fonts CDN — `Geist` (body) and `Space Grotesk` (headings/telemetry), plus Material Symbols Outlined for icons (`https://fonts.googleapis.com/css2?...`). Present in all four mockup screens.
|
||||
|
||||
**Testing:**
|
||||
- Not detected. No test framework, no test files.
|
||||
|
||||
**Build/Dev:**
|
||||
- Not detected. No bundler, no formatter, no linter config. Mockups are standalone static files.
|
||||
- The Play CDN is explicitly a prototyping tool — a first implementation phase should migrate mockup designs to a committed Tailwind setup (build pipeline or v4 binary) before production use.
|
||||
|
||||
## Key Dependencies
|
||||
|
||||
**Critical (runtime CDN dependencies of the mockups):**
|
||||
- `cdn.tailwindcss.com` — theming engine for all screens
|
||||
- `fonts.googleapis.com` / `fonts.gstatic.com` — Geist, Space Grotesk, Material Symbols
|
||||
- Mockup images are hosted/lifted from Google-hosted sample assets (`lh3.googleusercontent.com/aida/...` URLs appear in some screens' `<img>`/`src` attributes) — placeholders from the Stitch tooling, not project data
|
||||
|
||||
**Infrastructural (planned only — see `IDEAS.md` "Architecture Overview"; none is wired up):**
|
||||
- Telegram Bot API — frontend transport (`IDEAS.md`: "Telegram-first")
|
||||
- Neon Postgres + PostGIS — event/user storage (`IDEAS.md`)
|
||||
- OSRM — routing engine with dynamic traffic weighting (`IDEAS.md`, restated in `DESIGN.md`: `/navigate origin → destination → OSRM route`)
|
||||
- Maptiler — map tile provider for grayscale snapshots (`IDEAS.md`, `DESIGN.md`)
|
||||
- Cloudflare Pages — optional PWA hosting (`IDEAS.md`); Cloudflare R2 — image/snapshot storage (`IDEAS.md`)
|
||||
- RabbitMQ — event queue for broadcast-nearby flows (`IDEAS.md`)
|
||||
- Prometheus + Grafana — monitoring (`IDEAS.md`)
|
||||
- Resend — email (`IDEAS.md`)
|
||||
|
||||
## Configuration
|
||||
|
||||
**Environment:**
|
||||
- No `.env*` files, no config files exist. Nothing to document; note that a first backend phase will need to introduce one (e.g., Telegram bot token, Neon connection string, Maptiler key) — treat secret handling from day one since none exists yet.
|
||||
|
||||
**Build:**
|
||||
- No build config files. Tailwind config lives inline per-mockup in `<script id="tailwind-config">`; the canonical design-token source of truth is `stitch_minimalist_route_navigator/telemetry_rams/DESIGN.md` (YAML frontmatter with `colors`, `typography`, `spacing` blocks).
|
||||
|
||||
## Platform Requirements
|
||||
|
||||
**Development:**
|
||||
- Any modern browser to view the mockups; any text editor. No Node/Python runtime is required by current code.
|
||||
|
||||
**Production (target per `IDEAS.md`):**
|
||||
- Telegram bot process (runtime/tooling TBC), Neon Postgres (with PostGIS extension enabled), OSRM instance or hosted API, Maptiler API key, Cloudflare Pages + R2, RabbitMQ broker, Prometheus/Grafana stack, Resend account.
|
||||
|
||||
## Design-System Constraints (binding for future code)
|
||||
|
||||
All future implementation must inherit from `stitch_minimalist_route_navigator/telemetry_rams/DESIGN.md`:
|
||||
- Palette: Signal Orange `#EB8008`, Functional Red `#ED3F1C`, Olive Green `#736B1E`, Soft Beige `#D9D2C6`, Matte Black `#1A1A1A` (as defined in `DESIGN.md` and in the inline Tailwind config of every mockup)
|
||||
- Typography: Space Grotesk for headings/telemetry numbers, Geist for body/labels; uppercase + expanded letter-spacing for labels
|
||||
- Geometry: 8px baseline grid, **zero border-radius**, no shadows/blur/glass (per `telemetry_rams/DESIGN.md` "Elevation & Depth", "Shapes")
|
||||
- Interfaces are mobile-first (mockups are `shell-type: mobile_tab` / `mobile_stack`), designed for Telegram-embedded panels and a possible PWA
|
||||
|
||||
---
|
||||
|
||||
*Stack analysis: 2026-10-21*
|
||||
@@ -0,0 +1,116 @@
|
||||
# Codebase Structure
|
||||
|
||||
**Analysis Date:** 2026-10-21
|
||||
|
||||
## Directory Layout
|
||||
|
||||
```
|
||||
araharah/
|
||||
├── .planning/ # GSD planning artifacts (this analysis)
|
||||
│ └── codebase/ # Codebase map documents
|
||||
├── DESIGN.md # Design philosophy: palette, typography, iconography, flows
|
||||
├── IDEAS.md # Product vision, principles, implied target stack
|
||||
└── stitch_minimalist_route_navigator/ # UI mockup suite ("Telemetry Rams" screens)
|
||||
├── active_route_guidance/
|
||||
│ ├── code.html # Turn-by-turn navigation HUD mockup
|
||||
│ └── screen.png # Visual capture of the screen
|
||||
├── community_incident_reporter/
|
||||
│ ├── code.html # Incident report flow mockup
|
||||
│ └── screen.png # Visual capture
|
||||
├── navigate_map_overview/
|
||||
│ ├── code.html # Full-map navigation overview mockup
|
||||
│ └── screen.png # Visual capture
|
||||
├── telegram_live_traffic_feed/
|
||||
│ ├── code.html # Telegram bot traffic feed mockup
|
||||
│ └── screen.png # Visual capture
|
||||
├── telemetry_rams/
|
||||
│ └── DESIGN.md # Formal design system spec (tokens + component rules)
|
||||
│ # (no screen.png — this is the design system, not a screen)
|
||||
└── */:Zone.Identifier # Windows download metadata — ignore everywhere
|
||||
```
|
||||
|
||||
## Directory Purposes
|
||||
|
||||
**Root (`/`):**
|
||||
- Purpose: Planning documents for a not-yet-implemented product
|
||||
- Contains: `DESIGN.md` (85 lines, design philosophy) and `IDEAS.md` (95 lines, vision + implied target stack)
|
||||
- Key files: `DESIGN.md`, `IDEAS.md`
|
||||
|
||||
**`stitch_minimalist_route_navigator/`:**
|
||||
- Purpose: Self-contained static HTML mockups of the app's four key screens, generated with the "Telemetry Rams" design system (Rams-minimalist telemetry aesthetic)
|
||||
- Contains: One subdirectory per screen; each screen dir holds `code.html` + `screen.png`
|
||||
- Key files: `active_route_guidance/code.html` (189 lines), `navigate_map_overview/code.html` (344 lines), `telegram_live_traffic_feed/code.html` (302 lines), `community_incident_reporter/code.html` (274 lines)
|
||||
|
||||
**`stitch_minimalist_route_navigator/telemetry_rams/`:**
|
||||
- Purpose: Canonical design-system definition (YAML front matter with `colors`, `typography`, `spacing`; then component specs)
|
||||
- Contains: `DESIGN.md` (241 lines) — the only non-root, non-screen documentation
|
||||
- Key files: `stitch_minimalist_route_navigator/telemetry_rams/DESIGN.md`
|
||||
|
||||
**`.planning/`:**
|
||||
- Purpose: GSD planning artifacts; hosts `.planning/codebase/` documents (written by this analysis)
|
||||
- Generated: Yes (GSD tooling)
|
||||
- Committed: Yes (treat as project documentation)
|
||||
|
||||
## Key File Locations
|
||||
|
||||
**Entry Points:**
|
||||
- `stitch_minimalist_route_navigator/{screen}/code.html`: Open directly in a browser; each is a standalone mockup. No build step required (Tailwind/fonts load from CDN).
|
||||
- No application entry points exist (`no src/`, no `index.*`, no `main.*`, no package manifest).
|
||||
|
||||
**Configuration:**
|
||||
- No config files exist (no `package.json`, `tsconfig.json`, `.eslintrc`, `.env*`, lockfile, or CI config detected).
|
||||
- Design configuration lives in prose/YAML: `stitch_minimalist_route_navigator/telemetry_rams/DESIGN.md`.
|
||||
|
||||
**Core Logic (current):**
|
||||
- All interactivity is inline demo JS inside each `code.html` (e.g., `insertCommand('/hazard ...')`, `toggleLayers()`, `confirmDispatch()`, `closeHazardDrawer()`). See `navigate_map_overview/code.html` and `telegram_live_traffic_feed/code.html` for the richest handler sets.
|
||||
|
||||
**Testing:**
|
||||
- No test files or test framework present. Not applicable yet.
|
||||
|
||||
## Naming Conventions
|
||||
|
||||
**Files:**
|
||||
- Screens use lowercase `snake_case` directory names naming the screen purpose: `active_route_guidance`, `navigate_map_overview`, `telegram_live_traffic_feed`, `community_incident_reporter`
|
||||
- Fixed per-screen filenames: `code.html` (mockup source) and `screen.png` (capture)
|
||||
- Top-level docs use `UPPER-SNAKE.md`: `DESIGN.md`, `IDEAS.md`
|
||||
|
||||
**Directories:**
|
||||
- `snake_case` throughout (`stitch_minimalist_route_navigator`, `telemetry_rams`, `.planning/codebase`)
|
||||
|
||||
**In-code naming (mockups):**
|
||||
- CSS utility classes map to design tokens: `signal-orange`, `matte-black`, `soft-beige`, `functional-red`, `olive-green`, `chassis-subtle`, `surface-*` variants
|
||||
- JS demo functions use camelCase: `insertCommand`, `toggleLayers`, `confirmDispatch`, `closeHazardDrawer`, `updatePreview`
|
||||
- Section reference badges follow an uppercase `SEC-XX // LABEL` convention (e.g., `SEC-STACK // EXEC`, `CH-08`)
|
||||
|
||||
## Where to Add New Code
|
||||
|
||||
**New mockup screen:**
|
||||
- Create `stitch_minimalist_route_navigator/<screen_name_snake_case>/` containing `code.html` (self-contained, Tailwind CDN + inline `tailwind.config` with the Telemetry Rams tokens + inline SVG glyphs) and a `screen.png` capture
|
||||
- Follow the register-band layout documented in `telemetry_rams/DESIGN.md` (top/center/lower registers, 8px grid, 0px radius)
|
||||
|
||||
**Applying design tokens:**
|
||||
- Copy token values from `stitch_minimalist_route_navigator/telemetry_rams/DESIGN.md` (colors, typography, spacing) into the new screen's inline `tailwind.config`; keep the five core colors verbatim (`signal-orange: #EB8008`, `functional-red: #ED3F1C`, `olive-green: #736B1E`, `soft-beige: #D9D2C6`, `matte-black: #1A1A1A`)
|
||||
|
||||
**Documentation:**
|
||||
- Product-level ideas/stack changes → `IDEAS.md` (root)
|
||||
- Design philosophy changes → `DESIGN.md` (root)
|
||||
- Formal token/component spec changes → `stitch_minimalist_route_navigator/telemetry_rams/DESIGN.md`
|
||||
|
||||
**Future implementation code (when project leaves design phase):**
|
||||
- No conventional locations exist yet. The implied target stack in `IDEAS.md` (Telegram bot backend, Neon Postgres, OSRM, Cloudflare Pages/R2) will need a conventional `src/` or service layout to be established by the first planning phase.
|
||||
|
||||
## Special Directories
|
||||
|
||||
**`.planning/`:**
|
||||
- Purpose: GSD planning/orchestration artifacts
|
||||
- Generated: Yes, by GSD commands
|
||||
- Committed: Yes
|
||||
|
||||
**`*:Zone.Identifier` files:**
|
||||
- Purpose: None (Windows download metadata attached to every HTML/PNG/MD file)
|
||||
- Generated: Yes (OS artifact)
|
||||
- Committed: Accidentally present — should be excluded from version control and any future lint/build globbing (add to `.gitignore`: `*:Zone.Identifier`)
|
||||
|
||||
---
|
||||
|
||||
*Structure analysis: 2026-10-21*
|
||||
@@ -0,0 +1,108 @@
|
||||
# Testing Patterns
|
||||
|
||||
**Analysis Date:** 2026-10-21
|
||||
|
||||
> **Status: No tests exist yet.** There are no test files, no test runner configuration,
|
||||
> no package manifest, and no CI pipeline in this repository. This document records what
|
||||
> is verifiably absent today and prescribes the testing conventions the project should
|
||||
> adopt when real implementation code begins, based on the stack targets declared in
|
||||
> `IDEAS.md`.
|
||||
|
||||
## Test Framework
|
||||
|
||||
**Runner:**
|
||||
- None installed. No `package.json`, no `vitest.config.*` / `jest.config.*` /
|
||||
`playwright.config.*` exists anywhere in the repository.
|
||||
- Run commands: Not applicable — nothing to run.
|
||||
|
||||
**Assertion Library:** None.
|
||||
|
||||
**Application code under test:** None. The only executable artifacts are inline scripts
|
||||
inside the generated mockup files (`stitch_minimalist_route_navigator/*/code.html`),
|
||||
which are demonstration-only and not structured for testing.
|
||||
|
||||
## Test File Organization
|
||||
|
||||
**Current state:** Not established. No `tests/`, `__tests__/`, `*.test.*`, or `*.spec.*`
|
||||
files exist.
|
||||
|
||||
**Prescribed convention (for future code):**
|
||||
- Place tests adjacent to the code they cover (`*.test.ts` next to the module) once a
|
||||
source directory exists.
|
||||
- There are no `--paths` subtrees pinned yet; the whole repo is effectively design docs +
|
||||
mockups (`DESIGN.md`, `IDEAS.md`, `stitch_minimalist_route_navigator/`).
|
||||
|
||||
## Recommended Stack Mapping (targets from `IDEAS.md`)
|
||||
|
||||
The planned architecture in `IDEAS.md:55-73` implies these test layers when implemented:
|
||||
|
||||
| Planned component | Where it's described | Suggested test approach |
|
||||
|---|---|---|
|
||||
| Telegram bot commands (`/report`, `/navigate`, `/accident`) | `IDEAS.md:19-27`, `DESIGN.md:67-73` | Unit tests on command parsing/state machines; integration tests against a Telegram Bot API test token or a stubbed client |
|
||||
| OSRM route fetch + traffic weighting | `IDEAS.md:63`, `DESIGN.md:71` | Contract tests against a recorded/stubbed OSRM response; regenerate fixtures when branching logic changes |
|
||||
| Neon Postgres + PostGIS report storage & nearby broadcast | `IDEAS.md:61`, `DESIGN.md:69` | Integration tests against an ephemeral Postgres + PostGIS extension (e.g., testcontainers-style setup in CI) |
|
||||
| Map snapshot generation (Maptiler tiles, R2 storage) | `IDEAS.md:64-69` | Golden-image tests only if snapshots are rendered locally; otherwise HTTP-mock the tile/R2 clients |
|
||||
| RabbitMQ queue consumers | `IDEAS.md:67` | Unit-test handlers with in-memory queue; defer broker-level tests to a single CI integration job |
|
||||
|
||||
## Mocking
|
||||
|
||||
**Framework:** None (no tooling yet).
|
||||
|
||||
**Prescribed patterns for future code:**
|
||||
- Mock only true boundaries: Telegram Bot API client, OSRM HTTP client, Maptiler tile
|
||||
fetcher, RabbitMQ producer, R2 uploader. Do **not** mock internal handlers, parsers,
|
||||
or design-token usage.
|
||||
- Prefer injectable clients over module-level singletons so tests can pass fakes;
|
||||
when the bot entry point is created, keep a thin wiring layer and a pure core.
|
||||
|
||||
## Fixtures and Factories
|
||||
|
||||
**Test Data:** None exists.
|
||||
|
||||
**Prescribed convention:**
|
||||
- Create a `fixtures/` (or `test/fixtures/`) directory for recorded OSRM responses,
|
||||
Telegram update payloads, and tile responses. Store raw payloads, not hand-typed
|
||||
paraphrases, so contract drift is catchable.
|
||||
- Use small factory functions (e.g., `makeIncidentReport(overrides)`) over large literal
|
||||
blocks once domain types exist.
|
||||
|
||||
## Coverage
|
||||
|
||||
**Requirements:** None enforced (no runner, therefore no coverage tooling).
|
||||
|
||||
**View Coverage:** Not applicable until a runner is configured; when it is, wire coverage
|
||||
into the runner config rather than a separate tool.
|
||||
|
||||
## Manual Verification (what exists today)
|
||||
|
||||
Since there is no automated checking, the only "testing" currently possible is manual:
|
||||
|
||||
- **Visual review:** each mockup has a rendered screenshot pair
|
||||
(`stitch_minimalist_route_navigator/<screen>/code.html` + `<screen>/screen.png`) —
|
||||
four screens: `active_route_guidance`, `navigate_map_overview`,
|
||||
`community_incident_reporter`, `telegram_live_traffic_feed`. Compare `code.html`
|
||||
rendering against `screen.png` after any token or config edit (the inline
|
||||
`tailwind.config` block is duplicated across all four files and must stay in sync).
|
||||
- **Interactivity smoke check:** mockups contain small inline JS handlers — e.g.,
|
||||
`reportHazardModal`, `confirmDispatch`, `triggerQuickDispatch`
|
||||
(`stitch_minimalist_route_navigator/navigate_map_overview/code.html:288-314`) and
|
||||
`insertCommand`
|
||||
(`stitch_minimalist_route_navigator/telegram_live_traffic_feed/code.html:235`).
|
||||
These are demo-only; verifying them means opening the HTML in a browser and clicking
|
||||
through buttons. Do not invest in automated tests for these scripts; they will be
|
||||
replaced by real implementation code.
|
||||
|
||||
## Gaps That Should Become Early Phases
|
||||
|
||||
1. **Test scaffold phase:** first real-code phase should add a package manifest with a
|
||||
test runner + lint config in the same commit, before business logic.
|
||||
2. **CI job:** once a runner exists, add a minimal pipeline (install → lint → test) — no
|
||||
CI config exists today (`.github/workflows/`, etc. absent).
|
||||
3. **Design-token regression:** consider a lightweight check that the four `code.html`
|
||||
`tailwind.config` blocks match the token table in
|
||||
`stitch_minimalist_route_navigator/telemetry_rams/DESIGN.md` (a snapshot/diff test is
|
||||
sufficient; heavy visual-diff tooling is disproportionate for a mockup repo).
|
||||
|
||||
---
|
||||
|
||||
*Testing analysis: 2026-10-21*
|
||||
@@ -0,0 +1,147 @@
|
||||
---
|
||||
phase: 01-design-tokens-rams-foundation
|
||||
plan: 01
|
||||
type: execute
|
||||
wave: 1
|
||||
depends_on: []
|
||||
files_modified:
|
||||
- package.json
|
||||
- .gitignore
|
||||
- DESIGN.md
|
||||
- theme/package.json
|
||||
- theme/src/tokens.css
|
||||
- theme/src/theme.css
|
||||
- theme/fonts/geist/Geist-Regular.woff2
|
||||
- theme/fonts/geist/Geist-Medium.woff2
|
||||
- theme/fonts/geist/Geist-SemiBold.woff2
|
||||
- theme/fonts/geist/Geist-Bold.woff2
|
||||
- theme/fonts/space-grotesk/SpaceGrotesk-Bold.woff2
|
||||
- theme/fonts/space-grotesk/SpaceGrotesk-SemiBold.woff2
|
||||
- theme/fonts/space-grotesk/SpaceGrotesk-Regular.woff2
|
||||
autonomous: true
|
||||
requirements: [DSGN-01]
|
||||
user_setup: []
|
||||
must_haves:
|
||||
decisions: [D-01, D-02, D-04, D-05, D-06, D-07, D-15, D-16, D-17]
|
||||
truths:
|
||||
- "Tokens exist as CSS custom properties importable by any later phase (npm script or plain CSS import)"
|
||||
- "Building the theme produces a compiled dist CSS containing Tailwind v4 utilities wired via @theme"
|
||||
- "Zero Google Fonts CDN references in the package self-hosted fonts serve both typefaces"
|
||||
- "Root DESIGN.md declares itself superseded for specific values and points to the token package"
|
||||
artifacts:
|
||||
- path: "theme/src/tokens.css"
|
||||
provides: "All color/spacing/typography tokens as CSS variables + @theme (D-01, D-02)"
|
||||
contains: "signal-orange"
|
||||
- path: "theme/src/theme.css"
|
||||
provides: "Fonts @font-face declarations + @import of tokens (D-16, D-10)"
|
||||
contains: "@font-face"
|
||||
- path: "theme/package.json"
|
||||
provides: "tailwindcss v4 CLI deps + build/audit/gallery scripts (D-15, D-17)"
|
||||
contains: "@tailwindcss/cli"
|
||||
- path: ".gitignore"
|
||||
provides: "OS junk, node_modules, secrets exclusions"
|
||||
contains: "node_modules"
|
||||
key_links:
|
||||
- from: "theme/src/theme.css"
|
||||
to: "theme/src/tokens.css"
|
||||
via: "CSS @import"
|
||||
pattern: "@import.*tokens\\.css"
|
||||
- from: "theme/package.json"
|
||||
to: "theme/src/theme.css"
|
||||
via: "build script"
|
||||
pattern: "@tailwindcss/cli"
|
||||
---
|
||||
|
||||
<objective>
|
||||
Create the centralized Telemetry Rams token package (Tailwind v4 CSS-first), self-host the two typefaces, and resolve the repo's design-source conflict. This is the single source of truth every later phase imports.
|
||||
|
||||
Purpose: DSGN-01 requires all screens render from one token set; today tokens are hand-duplicated into 4 mockup `tailwind.config` blocks and two conflicting DESIGN.md typography claims (per CONTEXT.md D-05, D-06).
|
||||
Output: `theme/` package with tokens + fonts + build scripts, repo hygiene (.gitignore, Zone.Identifier scrub), superseded-designation banner on root DESIGN.md.
|
||||
</objective>
|
||||
|
||||
<read_first>
|
||||
@planning/phases/01-design-tokens-rams-foundation/01-CONTEXT.md
|
||||
@planning/codebase/STACK.md
|
||||
@planning/codebase/CONCERNS.md
|
||||
@stitch_minimalist_route_navigator/telemetry_rams/DESIGN.md
|
||||
@DESIGN.md
|
||||
</read_first>
|
||||
|
||||
<interfaces>
|
||||
Token vocabulary (Copy VERBATIM from the frontmatter of `stitch_minimalist_route_navigator/telemetry_rams/DESIGN.md` — D-02 requires 1:1 mockup mapping):
|
||||
|
||||
Core brand colors: `signal-orange: #EB8008`, `matte-black: #1A1A1A`, `soft-beige: #D9D2C6`, `functional-red: #ED3F1C`, `olive-green: #736B1E`, `chassis-subtle: #CCC4B5`, `surface-dark: #121212`, `pure-white: #FFFFFF`
|
||||
Material neutrals: surface #fff8f0 / on-surface #1e1b14 / on-surface-variant #564335 / outline #897363 / outline-variant #dcc1af / transparent variants per frontmatter (copy all keys from lines 3–49)
|
||||
Spacing: `space-xs 0.25rem` … `space-2xl 3rem` + `gutter` / `gutter-desktop` / `margin` / `margin-desktop` (lines 138–148)
|
||||
Typography scale: `display-lg`, `display-lg-mobile`, `headline-lg`, `headline-lg-mobile`, `headline-md`, `headline-sm`, `body-lg`, `body-md`, `body-sm`, `label-lg`, `label-md`, `label-sm`, `telemetry-num` with exact px/weight/tracking values (lines 59–137)
|
||||
No-radius rule: all `--radius-*: 0px` (Shapes section)
|
||||
</interfaces>
|
||||
|
||||
<tasks>
|
||||
|
||||
<task type="auto">
|
||||
<name>task 1: Repo hygiene + package scaffold</name>
|
||||
<files>.gitignore, package.json, theme/package.json</files>
|
||||
<action>
|
||||
1. Scrub Zone.Identifier artifacts (CONCERNS.md debt): `find . -name "*:Zone.Identifier" -type f -delete` (run from repo root). Confirm count 0 afterward.
|
||||
2. Create root `.gitignore` containing (exact entries): `node_modules/`, `dist/`, `theme/dist/`, `.env`, `.env.*`, `!*.example`, `*.local`, `theme/screenshots/`, `OS junk`: `.DS_Store`, `Thumbs.db`, `desktop.ini`.
|
||||
3. Create root `package.json`: name `araharah`, private true, type `module`, workspaces `["theme"]`, scripts delegating to theme (`"build": "npm run build --workspace theme"`, `"sheet": "npm run sheet --workspace theme"`, `"gallery": "npm run gallery --workspace theme"`, `"audit": "npm run audit --workspace theme"`, `"capture": "npm run capture --workspace theme"`).
|
||||
4. Create `theme/package.json`: name `@araharah/theme`, type `module`, devDependencies `tailwindcss@^4` and `@tailwindcss/cli@^4`, dependencies `playwright` (needed by plan 03), plus scripts:
|
||||
- `"build": "tailwindcss -i ./src/theme.css -o ./dist/rams.css --minify"` (D-17 local-only)
|
||||
- `"send": "mkdir -p dist/fonts && cp -r fonts/geist fonts/space-grotesk dist/"` (fonts copied alongside build so sheet.css/font paths resolve)
|
||||
- `"gallery", "audit", "capture", "sheet" script stubs are created by later plans 02–04 — do NOT add them here except as documented below in tasks of those plans.` (Correction: create only `build` and `send` in this plan; later plans append their scripts.)
|
||||
</action>
|
||||
<verify><automated>test ! -f .gitignore || grep -q "node_modules" .gitignore; test -f theme/package.json && grep -q "@tailwindcss/cli" theme/package.json && find . -name "*:Zone.Identifier" | grep -c . || echo "zone-files=0"</automated></verify>
|
||||
<done>.gitignore exists with node_modules/.env entries; theme/package.json declares tailwindcss v4 CLI; zero `*:Zone.Identifier` files remain in the repo.</done>
|
||||
</task>
|
||||
|
||||
<task type="auto">
|
||||
<name>task 2: Token package (tokens.css + theme.css + fonts)</name>
|
||||
<files>theme/src/tokens.css, theme/src/theme.css, theme/fonts/**</files>
|
||||
<read_first>@stitch_minimalist_route_navigator/telemetry_rams/DESIGN.md</read_first>
|
||||
<action>
|
||||
1. Download Geist and Space Grotesk woff2 (weights: Geist 400/500/600 + Space Grotesk 700 needed by D-10/labels; Geist Regular, Medium, SemiBold, Bold + Space Grotesk Regular, SemiBold, Bold) from the `fontsource` npm CDN unpkg distribution (`npm i @fontsource-variable/geist @fontsource-variable/space-grotesk` to fetch then extract woff2 files, OR direct unpkg `.woff2` fetches). Place files under `theme/fonts/geist/` and `theme/fonts/space-grotesk/` with names recorded in frontmatter.
|
||||
2. Write `theme/src/tokens.css` (per D-01, D-02, D-04, D-07): one `@theme` block declaring EVERY token from telemetry_rams/DESIGN.md frontmatter, names verbatim: colors as `--color-*`, spacing as `--spacing-*`, typography via `--font-sans/mono` aliasing (Geist/Space Grotesk), radius `--radius-DEFAULT: 0px` (zero roundedness per design doc Shapes), and label type scale preserved as Tailwind v4 text custom classes via `@utility` or as plain CSS custom properties under `:root` — pick `@theme` for colors/spacing/fonts, `:root`-level custom properties for the typography scale entries (each as a compound var, e.g. `--type-display-lg` composed of font/size/weight/line-height/tracking).
|
||||
3. Enforce the 8px-base rule: spacing values in the frontmatter are already grid-conformant; copy verbatim (D-07 forbids recomputation).
|
||||
4. Write `theme/src/theme.css`:
|
||||
- `@import "tailwindcss";`
|
||||
- `@import "tokens.css";`
|
||||
- seven `@font-face` blocks (font-family Geist / Space Grotesk, font-weight per file, `src: url(../fonts/…/*.woff2) format('woff2')`, `font-display: block;` non-flash per Rams aesthetics).
|
||||
- Dual Telegram light/dark slot pre-slotting (D-04): add `:root { --shell-bg: var(--color-surface); }` and `@media (prefers-color-scheme: dark) { :root { --shell-bg: var(--color-surface-dark); } }` — only shell-level slots (background, on-surface text pair) are themeable, map cartography stays Rams-constant.
|
||||
5. Run `npm run build --workspace theme` and verify `theme/dist/rams.css` exists and contains `signal-orange` and `.font-geist` font stack.
|
||||
</action>
|
||||
<verify><automated>npm run build --workspace theme && test -f theme/dist/rams.css && grep -c "signal-orange" theme/dist/rams.css | awk '$1>=3{exit 0}{exit 1}' && grep -q "@font-face" theme/dist/rams.css</automated></verify>
|
||||
<tdd>false</tdd>
|
||||
<done>tokens.css declares ~40-token vocabulary verbatim from mockup config (D-02), theme.css @font-faces self-hosted Geist + Space Grotesk (D-16), shell theme slots pre-arranged (D-04), and `npm run build --workspace theme` produces dist/rams.css containing all token names with no console errors.</done>
|
||||
</task>
|
||||
|
||||
<task type="auto">
|
||||
<name>task 3: DESIGN.md superseding banner</name>
|
||||
<files>DESIGN.md, README.md</files>
|
||||
<read_first>@DESIGN.md</read_first>
|
||||
<action>
|
||||
1. Insert at the very top of root `DESIGN.md` a 3-line banner (before any existing heading, no H1 style change so prose stays visible):
|
||||
`> ⚠ SUPERSEDED FOR SPECIFICS — the centralized token set is the single source of truth for all numeric values (colors, sizes, spacing). This document is kept for Rams design philosophy only. Consult the token package (see README.md) for specific value definitions. Conflicting typography claims in this document (Helvetica/Inter, 5-color palette) are superseded by the token package.` (per D-05)
|
||||
2. Create or append to `README.md` a one-paragraph "Design system" section: live in `theme/`, consume via `@import 'theme/src/tokens.css'`, build via `npm run build`. Do NOT restate hex codes or px sizes in the README (D-07: docs never restate numeric values — write "palette" and "the token set" descriptively, with no hex/px numbers).
|
||||
</action>
|
||||
<verify><automated>head -5 DESIGN.md | grep -q "SUPERSEDED" && ! grep -qE '#[0-9A-Fa-f]{6}|(\d+px)' README.md</automated></verify>
|
||||
<done>DESIGN.md first line declares supersession; README references the package without numerically restating any design value (D-07).</done>
|
||||
</task>
|
||||
|
||||
</tasks>
|
||||
|
||||
<verification>
|
||||
- `npm run build --workspace theme` exits 0 and emits `theme/dist/rams.css`
|
||||
- `grep -c "signal-orange" theme/dist/rams.css` ≥ 3
|
||||
- `find . -name "*:Zone.Identifier" | wc -l` = 0
|
||||
- `head -3 DESIGN.md` mentions SUPERSEDED
|
||||
- `grep -r "fonts.googleapis" theme/` returns no matches (D-16)
|
||||
</verification>
|
||||
|
||||
<success_criteria>
|
||||
Token package exists, builds, and is importable by any later phase; fonts self-hosted; design-source conflict resolved via superseding banner + non-numeric README; repo git hygiene established. Unblocks component sheet (02), basemap (03).
|
||||
</success_criteria>
|
||||
|
||||
<output>
|
||||
After completion, create `.planning/phases/01-design-tokens-rams-foundation/01-01-SUMMARY.md`
|
||||
</output>
|
||||
@@ -0,0 +1,126 @@
|
||||
---
|
||||
phase: 01-design-tokens-rams-foundation
|
||||
plan: 02
|
||||
type: execute
|
||||
wave: 2
|
||||
depends_on: ["01-01"]
|
||||
files_modified:
|
||||
- theme/src/sheet.html
|
||||
- theme/src/components.css
|
||||
- theme/package.json
|
||||
- theme/dist/rams.css
|
||||
autonomous: true
|
||||
requirements: [DSGN-01]
|
||||
user_setup: []
|
||||
must_haves:
|
||||
decisions: [D-03, D-11]
|
||||
truths:
|
||||
- "A rendered component sheet displays every component type the 4 mockup screens show, styled exclusively by the token package"
|
||||
- "The sheet includes the Legibility specimen (typography scale) per D-11"
|
||||
- "Building the sheet via Tailwind v4 CLI emits a dist CSS that contains zero off-token values (numbers only from tokens.css)"
|
||||
artifacts:
|
||||
- path: "theme/src/sheet.html"
|
||||
provides: "Component sheet demo page consuming tokens (D-03, D-11)"
|
||||
contains: "signal-orange"
|
||||
- path: "theme/src/components.css"
|
||||
provides: "Component classes defined against tokens, not raw hex/px values"
|
||||
contains: "var(--color-signal-orange)"
|
||||
- path: "theme/package.json"
|
||||
provides: "Appends `sheet` build script"
|
||||
contains: "\"sheet\""
|
||||
key_links:
|
||||
- from: "theme/src/sheet.html"
|
||||
to: "theme/dist/rams.css"
|
||||
via: "<link rel=stylesheet>"
|
||||
pattern: "rams\\.css"
|
||||
- from: "theme/src/components.css"
|
||||
to: "theme/src/tokens.css"
|
||||
via: "var(--color-*) / var(--spacing-*) references only"
|
||||
pattern: "var\\(--"
|
||||
---
|
||||
|
||||
<objective>
|
||||
Create the Rams component sheet — buttons, cards, chips/badges, the maneuver banner, inputs, checkboxes/toggles, and the typography specimen — all styled exclusively from the token package. This is the artifact DSGN-01's audit sweep (plan 04) measures and the gallery (plan 04) screenshots.
|
||||
|
||||
Purpose: D-03 — "the sheet itself proves token completeness." Scope is strictly mockup-derived (D-11: no invented components).
|
||||
Output: `theme/src/sheet.html` + `theme/src/components.css` + a `sheet` npm script.
|
||||
</objective>
|
||||
|
||||
<read_first>
|
||||
@planning/phases/01-design-tokens-rams-foundation/01-CONTEXT.md
|
||||
@planning/phases/01-design-tokens-rams-foundation/01-01-SUMMARY.md
|
||||
@stitch_minimalist_route_navigator/telemetry_rams/DESIGN.md
|
||||
@stitch_minimalist_route_navigator/active_route_guidance/code.html
|
||||
@stitch_minimalist_route_navigator/navigate_map_overview/code.html
|
||||
@stitch_minimalist_route_navigator/community_incident_reporter/code.html
|
||||
@stitch_minimalist_route_navigator/telegram_live_traffic_feed/code.html
|
||||
</read_first>
|
||||
|
||||
<interfaces>
|
||||
From plan 01-01:
|
||||
- `theme/src/tokens.css` — `@theme` colors (`--color-signal-orange`, `--color-matte-black`, `--color-soft-beige`, `--color-functional-red`, `--color-olive-green`, `--color-chassis-subtle`, `--color-surface-dark`, …), spacing (`--spacing-xs` … `--spacing-2xl`), fonts (`--font-sans` = Geist stack, `--font-display` = Space Grotesk stack).
|
||||
- `theme/src/theme.css` — imports tokens + `@font-face` declarations; build target is `theme/dist/rams.css`.
|
||||
- Typography scale exists as `:root` custom properties under `--type-display-lg` … `--type-telemetry-num` (compound font/size/weight/line-height/tracking).
|
||||
|
||||
Rendered mockup components to mirror (D-11 scope, observed across the four code.html screens):
|
||||
- Primary action button: bg `signal-orange`, label `matte-black` uppercase label-lg, `2px solid` matte-black border, 0px radius; hover/focus inverts to matte-black bg / signal-orange text (per telemetry_rams/DESIGN.md Components).
|
||||
- Secondary action: bg soft-beige, matte-black label, 2px border; hover bg chassis-subtle.
|
||||
- Telemetry card: 1px solid matte-black perimeter, soft-beige bg, sharp corners; header plate with label-sm uppercase category + reference badge (`SEC-04 // SPEED`); content in telemetry-num typography.
|
||||
- Chips: rectangular blocks — traffic = signal-orange bg / matte-black text; hazard = functional-red bg / white text; safe = olive-green bg / white text; all label-sm.
|
||||
- Maneuver banner strip: inverted matte-black container, 32x32 signal-orange arrow (3px stroke), headline-md soft-beige street, Space Grotesk bold distance.
|
||||
- Input: soft-beige bg, 2px solid matte-black border; focus = 3px signal-orange border, no glow/blur/animation.
|
||||
- Checkbox 18×18 2px matte-black border with 8×8 signal-orange fill when checked; two-way horizontal toggle [ OFF | ON ] with inverted active box.
|
||||
- Typography specimen: every scale entry (`display-lg` → `label-sm` + `telemetry-num`).
|
||||
</interfaces>
|
||||
|
||||
<tasks>
|
||||
|
||||
<task type="auto">
|
||||
<name>task 1: components.css — component layer built only from tokens</name>
|
||||
<files>theme/src/components.css</files>
|
||||
<action>
|
||||
1. Create `theme/src/components.css`. Use Tailwind v4 `@layer components { … }` with utility classes constructed from `var(--color-*)` / `var(--spacing-*)` / `--type-*` references ONLY. NO raw hex values, NO raw px paddings/margins/font-sizes, NO border-radius other than 0 (D-11 fidelity hard requirement; plan 04's audit script flags any violation).
|
||||
2. Component classes to define (names kebab-case): `.btn-primary`, `.btn-secondary`, `.input-field`, `.card`, `.card-header`, `.chip-traffic`, `.chip-hazard`, `.chip-safe`, `.maneuver-banner`, `.maneuver-arrow`, `.checkbox`, `.toggle`, plus typography helpers `.text-display-lg` through `.text-label-sm` and `.text-telemetry-num` consuming the `--type-*` custom properties.
|
||||
3. Import it from `theme/src/theme.css` after tokens: add `@import "components.css";` as the last import so build picks it up.
|
||||
4. Border geometry: 1px and 2px solid borders use `var(--color-matte-black)`; focus rings replace border color with `var(--color-signal-orange)` at 3px — zero blur/glow/transition.
|
||||
</action>
|
||||
<verify><automated>grep -cE "var\\(--" theme/src/components.css | awk '$1>=15{exit 0}{exit 1}'; ! grep -E "#[0-9A-Fa-f]{3,6}\b" theme/src/components.css || echo FAIL-off-token-hex; ! grep -E "border-radius:\s*(?!0)" theme/src/components.css -P || echo FAIL-radius</automated></verify>
|
||||
<done>components.css defines all 14 component/typography classes using only token references; zero hex literals; zero non-zero border-radius (grep-verifiable).</done>
|
||||
</task>
|
||||
|
||||
<task type="auto">
|
||||
<name>task 2: sheet.html — rendered component sheet page</name>
|
||||
<files>theme/src/sheet.html, theme/package.json</files>
|
||||
<action>
|
||||
1. Create `theme/src/sheet.html`: a minimal static demo page. `<link rel="stylesheet" href="./dist/rams.css">`. Sections in order, one per mockup-derived component family (D-11): Typography specimen → Buttons → Inputs → Chips/Badges → Telemetry card → Maneuver banner → Checkboxes & Toggle. Each section gets a label-sm uppercase section header with a technical reference badge (matching card-header pattern).
|
||||
2. Use plain semantic HTML + the component classes (no Tailwind utility soup in the markup — the classes are the API later phases copy).
|
||||
3. Representative content mirrors the mockups without inventing new components: e.g., chip texts "CONGESTION", "CRASH / BLOCK", "POLICE RADAR" exactly as seen in `telegram_live_traffic_feed/code.html`; card reference badge "SEC-04 // SPEED".
|
||||
4. Add `"sheet": "tailwindcss -i ./src/sheet.css -o ./dist/sheet.css --minify || true && open ./src/sheet.html"` is WRONG shape — instead append to `theme/package.json` scripts: `"sheet": "npm run build && echo 'open theme/src/sheet.html in browser ( Consumes theme/dist/rams.css )'"`. Simplest correct wiring: sheet.html links the built dist/rams.css directly, so `npm run build` then opening sheet.html works with no extra CLI step.
|
||||
</action>
|
||||
<verify><automated>npm run build --workspace theme >/dev/null && test -f theme/src/sheet.html && grep -q "dist/rams.css" theme/src/sheet.html && grep -c "chip-\\|btn-\\|card\\|maneuver\\|checkbox\\|toggle" theme/src/sheet.html | awk '$1>=7{exit 0}{exit 1}'</automated></verify>
|
||||
<done>sheet.html renders all 7 component families using only components.css classes; page loads dist/rams.css; no Google Fonts CDN link present in sheet.html (D-16); npm run build passes after components.css import.</done>
|
||||
</task>
|
||||
|
||||
</tasks>
|
||||
|
||||
<threat_model>
|
||||
## Trust Boundaries
|
||||
| Boundary | Description |
|
||||
|----------|-------------|
|
||||
| none cross-user | Static sheet, dev-only artifact; no network input |
|
||||
</threat_model>
|
||||
|
||||
<verification>
|
||||
- `npm run build --workspace theme` → 0 exit
|
||||
- `grep -rn "fonts.googleapis" theme/src/` → empty
|
||||
- `grep -cE "var\\(--" theme/src/components.css` ≥ 15
|
||||
- visual: open `theme/src/sheet.html` in a browser — components visibly mirror mockup styling (font, colors, sharp corners)
|
||||
</verification>
|
||||
|
||||
<success_criteria>
|
||||
Component sheet renders every mockup-derived component family with style sourced 100% from token variables. It is the demonstrable artifact for DSGN-01's "every rendered component derives from tokens" and the input target for the audit sweep (plan 04).
|
||||
</success_criteria>
|
||||
|
||||
<output>
|
||||
After completion, create `.planning/phases/01-design-tokens-rams-foundation/01-02-SUMMARY.md`
|
||||
</output>
|
||||
@@ -0,0 +1,119 @@
|
||||
---
|
||||
phase: 01-design-tokens-rams-foundation
|
||||
plan: 03
|
||||
type: execute
|
||||
wave: 2
|
||||
depends_on: ["01-01"]
|
||||
files_modified:
|
||||
- theme/basemap/liberty-rams.json
|
||||
- theme/basemap/build.mjs
|
||||
- theme/basemap/index.html
|
||||
- theme/package.json
|
||||
autonomous: true
|
||||
requirements: [DSGN-01]
|
||||
user_setup: []
|
||||
must_haves:
|
||||
decisions: [D-08, D-09, D-10]
|
||||
truths:
|
||||
- "A Rams-styled MapLibre basemap renders in a browser: grayscale/muted land + water, desaturated roads, muted labels, zero signal-orange in the basemap"
|
||||
- "Basemap values are derived from the token package, not hand-tuned hex in the style JSON (D-09)"
|
||||
- "Map labels use the self-hosted Space Grotesk / Geist assets (D-10)"
|
||||
artifacts:
|
||||
- path: "theme/basemap/build.mjs"
|
||||
provides: "Generates liberty-rams.json by reading token values from theme/src/tokens.css"
|
||||
contains: "tokens.css"
|
||||
- path: "theme/basemap/liberty-rams.json"
|
||||
provides: "Forked OpenFreeMap liberty style with Rams cartography"
|
||||
contains: "glyphs"
|
||||
- path: "theme/basemap/index.html"
|
||||
provides: "MapLibre GL browser view proving the basemap renders (success criterion 3)"
|
||||
contains: "maplibre-gl"
|
||||
key_links:
|
||||
- from: "theme/basemap/build.mjs"
|
||||
to: "theme/src/tokens.css"
|
||||
via: "parse token custom properties"
|
||||
pattern: "tokens\\.css"
|
||||
- from: "theme/basemap/index.html"
|
||||
to: "theme/basemap/liberty-rams.json"
|
||||
via: "MapLibre style URL"
|
||||
pattern: "liberty-rams\\.json"
|
||||
---
|
||||
|
||||
<objective>
|
||||
Fork the OpenFreeMap `liberty` basemap style into a Rams-constant cartography output: grayscale/muted grounding, desaturated roads, muted labels in Rams type, `signal-orange` reserved exclusively for the future route line (not used in the basemap itself). Prove it renders in a browser with MapLibre GL.
|
||||
|
||||
Purpose: D-08 (full Rams pass on basemap), D-09 (derived from tokens, not hand-tuned), D-10 (Rams font assets for labels), roadmap success criterion 3.
|
||||
Output: `theme/basemap/` — build script, generated style JSON, browser proof page.
|
||||
</objective>
|
||||
|
||||
<read_first>
|
||||
@planning/phases/01-design-tokens-rams-foundation/01-CONTEXT.md
|
||||
@planning/phases/01-design-tokens-rams-foundation/01-01-SUMMARY.md
|
||||
@stitch_minimalist_route_navigator/telemetry_rams/DESIGN.md
|
||||
</read_first>
|
||||
|
||||
<interfaces>
|
||||
Derivation targets (map token → cartography role per D-08 / telemetry_rams/DESIGN.md "Grayscale Map Grounding"):
|
||||
- Land/background ground tone: between `soft-beige` (#D9D2C6) and `chassis-subtle` (#CCC4B5)
|
||||
- Water: desaturated mid-gray derived from `matte-black` mixed toward low-saturation (rgba derived, NOT brand hues)
|
||||
- Roads: desaturated, hierarchy by weight only (major roads slightly darker than minor)
|
||||
- Buildings: light gray within the `#D9D2C6 → #1A1A1A` calibrated gray band
|
||||
- Labels: `matte-black` at reduced opacity; fonts Space Grotesk (major) / Geist (minor) — same assets as theme/fonts (D-10)
|
||||
- `signal-orange` (#EB8008), `functional-red` (#ED3F1C), `olive-green` (#736B1E) must NOT appear in the basemap — accent is reserved exclusively for the route line rendered in Phase 5 (D-08).
|
||||
|
||||
Style input: `https://tiles.openfreemap.org/styles/liberty` style JSON (fetch at build time and fork; do not vendor the full original JSON — build.mjs fetches, transforms, writes).
|
||||
</interfaces>
|
||||
|
||||
<tasks>
|
||||
|
||||
<task type="auto">
|
||||
<name>task 1: basemap build script deriving style from tokens</name>
|
||||
<files>theme/basemap/build.mjs, theme/basemap/liberty-rams.json</files>
|
||||
<action>
|
||||
1. Create `theme/basemap/build.mjs` (Node ESM, no external deps beyond node builtins): fetches `https://tiles.openfreemap.org/styles/liberty` style JSON, transforms it, writes `theme/basemap/liberty-rams.json`.
|
||||
2. Derivation step: parse `theme/src/tokens.css` extracting the `--color-*` custom property values (deterministic regex `-\-color-([a-z0-9-]+):\s*(#[0-9A-Fa-f]{6})`). Compute the Rams cartography palette IN SCRIPT (D-09: derived, not hand-tuned): desaturate all land/road/water/building colors to the calibrated gray band via a small `desaturate(hex, satMultiplier)` helper (pure function: convert hex→HSL, multiply saturation toward ~0.06–0.12, adjust lightness per role per Interfaces table). Map transformed values onto the liberty style's `layers[].paint` color properties (`background`, `water`, `road-*`, `building-*`, `landcover-*`, `bridge-*`).
|
||||
3. FONT STEP: replace liberty's glyph/name font stacks. Point the style's `glyphs` to the OpenFreeMap hosted glyphs endpoint (keep `https://tiles.openfreemap.org/fonts/{fontstack}/{range}.pbf` to avoid self-hosting pbf glyphs in Phase 1), and rewrite every `layout["text-font"]` value to `"Space Grotesk Medium"` for major label layers (place-city, place-subtown and above) and `"Noto Sans Regular"` fallback chain ending `"Space Grotesk Regular"`… — IMPORTANT constraint: OpenFreeMap glyphs server only serves font stacks it hosts. If `Space Grotesk` is not available on the glyphs endpoint, detect a 404 at build time and fall back to the closest hosted stack, recording the substitution in a `"metadata"` block (`"rams-font-substitutions": {...}`) — this keeps D-10 satisfied in spirit (Rams typography for labels) with honest fallback provenance.
|
||||
4. Common concerns: signal-orange/functional-red/olive-green token names are excluded from the derivation set (guard: throw if any of those 3 hex values end up anywhere in the output layers' paint properties).
|
||||
5. Add npm script to `theme/package.json`: `"basemap": "node basemap/build.mjs"`.
|
||||
6. Run it; verify `theme/basemap/liberty-rams.json` exists, is valid JSON, has `version: 8`, `glyphs`, `sources`, `layers[0].paint` uses a transformed neutral.
|
||||
</action>
|
||||
<verify><automated>npm run basemap --workspace theme && node -e "const s=require('./theme/basemap/liberty-rams.json'); if(!s.layers||!s.glyphs) process.exit(1); const rgx=/EB8008|ED3F1C|736B1E/i; const bad=JSON.stringify(s.layers).match(rgx); if(bad){process.exit(2)} console.log('OK layers='+s.layers.length)"</automated></verify>
|
||||
<done>build.mjs derives all basemap colors from tokens.css (no hardcoded cartography hex in the script beyond token parsing), output JSON is a valid MapLibre style, and none of the 3 accent colors appear anywhere in the layer paint properties.</done>
|
||||
</task>
|
||||
|
||||
<task type="auto">
|
||||
<name>task 2: browser proof page (dummy route + rendered basemap)</name>
|
||||
<files>theme/basemap/index.html, theme/package.json</files>
|
||||
<action>
|
||||
1. Create `theme/basemap/index.html`: static MapLibre GL viewer (CDN unpkg `maplibre-gl@^4`), `<style>` sets page chrome to Rams tokens (`var(--color-surface)` background etc. — import `../dist/rams.css`), init map centered ~3.1513, 101.6958 (KLCC / KL metro, per project region), zoom ~13, style = `./liberty-rams.json`.
|
||||
2. Draw a placeholder route polyline in `signal-orange` (raw tolerance: the ROUTE line is exactly where signal-orange is allowed per D-08) with a thick 6px stroke so the visual "grayscale guiderail + orange vector" intent is previewable, labeled in a README comment as consumed by Phase 5.
|
||||
3. Add `"basemap:dev": "npx serve theme/basemap || true"`? No extra server dep — just use `python3 -m http.server` invocation pattern for the verify command instead; document the open command in index.html's comment header. Add npm script `"basemap:preview": "cd theme/basemap && python3 -m http.server 8123"`.
|
||||
4. Layer order: route layer added LAST in the layer stack so it sits above mapcar/roads but below any label overlap is not required here — keep simple.
|
||||
</action>
|
||||
<verify><automated>test -f theme/basemap/index.html && grep -q "maplibre" theme/basemap/index.html && grep -q "liberty-rams.json" theme/basemap/index.html && grep -qE "3\.15|101\.69" theme/basemap/index.html</automated></verify>
|
||||
<done>index.html loads liberty-rams.json, centers KLCC, draws a signal-orange route placeholder, and is checkable via `npm run basemap:preview --workspace theme` → http://localhost:8123 (human eyes verify the grayscale+muted+Rams feel, success criterion 3).</done>
|
||||
</task>
|
||||
|
||||
</tasks>
|
||||
|
||||
<threat_model>
|
||||
## Trust Boundaries
|
||||
| Boundary | Description |
|
||||
|----------|-------------|
|
||||
| basemap build → OpenFreeMap API | build.mjs fetches external style JSON across network |
|
||||
</threat_model>
|
||||
|
||||
<verification>
|
||||
- `npm run basemap --workspace theme` → 0 exit, liberty-rams.json regenerated
|
||||
- No accent hex (#EB8008 / #ED3F1C / #736B1E) anywhere in layers' paint
|
||||
- index.html renders the basemap via the preview script
|
||||
- `grep -c "tokens.css" theme/basemap/build.mjs` ≥ 1 (derivation provenance)
|
||||
</verification>
|
||||
|
||||
<success_criteria>
|
||||
Rams basemap derived from (not decorated with) the token package renders in a browser at KL metro with muted grayscale grounding, Rams label fonts, and zero accent-color leaks into cartography. Route accent visually confirmed against the grayscale base (success criterion 3 of the roadmap).
|
||||
</success_criteria>
|
||||
|
||||
<output>
|
||||
After completion, create `.planning/phases/01-design-tokens-rams-foundation/01-03-SUMMARY.md`
|
||||
</output>
|
||||
@@ -0,0 +1,172 @@
|
||||
---
|
||||
phase: 01-design-tokens-rams-foundation
|
||||
plan: 04
|
||||
type: execute
|
||||
wave: 3
|
||||
depends_on: ["01-02", "01-03"]
|
||||
files_modified:
|
||||
- theme/scripts/audit.mjs
|
||||
- theme/scripts/screenshot.mjs
|
||||
- theme/gallery.html
|
||||
- theme/package.json
|
||||
- package.json
|
||||
autonomous: false
|
||||
requirements: [DSGN-02]
|
||||
user_setup: []
|
||||
must_haves:
|
||||
decisions: [D-12, D-13, D-14]
|
||||
truths:
|
||||
- "The automated audit sweep scans the built CSS and flags every color/spacing/typography/radius value not in the token set — zero off-token values is evidence, not an eyeball claim (D-13)"
|
||||
- "A static side-by-side gallery page renders implementation components against all four mockup screens' rendered output (D-12)"
|
||||
- "Gallery captures are produced by a committed Playwright real-browser screenshot script (D-14)"
|
||||
- "User has viewed the gallery and basemap preview and explicitly approved (DSGN-02 approval artifact)"
|
||||
artifacts:
|
||||
- path: "theme/scripts/audit.mjs"
|
||||
provides: "Automated off-token audit (D-13): parses tokens.css allowlist, scans built dist CSS"
|
||||
- path: "theme/scripts/screenshot.mjs"
|
||||
provides: "Playwright capture script committed for reuse by later UI phases (D-14)"
|
||||
- path: "theme/gallery.html"
|
||||
provides: "DSGN-02 mockup-vs-implementation gallery — same pattern every later UI phase extends (D-12)"
|
||||
min_lines: 80
|
||||
- path: "theme/package.json"
|
||||
provides: "Wires `audit` and `capture` scripts"
|
||||
contains: "audit"
|
||||
key_links:
|
||||
- from: "theme/scripts/audit.mjs"
|
||||
to: "theme/src/tokens.css"
|
||||
via: "parse @theme/`:root` token values as the allowlist"
|
||||
pattern: "tokens\\.css"
|
||||
- from: "theme/scripts/audit.mjs"
|
||||
to: "theme/dist/rams.css"
|
||||
via: "scan built CSS for off-token literals; exit 1 on any"
|
||||
pattern: "rams\\.css"
|
||||
- from: "theme/scripts/screenshot.mjs"
|
||||
to: "theme/screenshots/"
|
||||
via: "Playwright chromium captures of sheet.html, 4 mockups, basemap preview"
|
||||
pattern: "screenshots"
|
||||
- from: "theme/gallery.html"
|
||||
to: "theme/screenshots/*"
|
||||
via: "<img> side-by-side comparison rows"
|
||||
pattern: "screenshots/"
|
||||
---
|
||||
|
||||
<objective>
|
||||
Prove token fidelity by script and by the user's eyes: wire the automated off-token audit (D-13 — "zero off-token values" becomes evidence, not an assertion), build the Playwright capture toolchain (D-14), assemble the side-by-side mockup-vs-implementation gallery (D-12), and run the DSGN-02 approval checkpoint — the fidelity-bar gate every later UI phase reuses.
|
||||
|
||||
Purpose: DSGN-02's approval-artifact mechanism is born here; no product screen (Phase 2+) is built before the user approves this gallery.
|
||||
Output: audit script + capture script + gallery page + approved DSGN-02 record.
|
||||
</objective>
|
||||
|
||||
<execution_context>
|
||||
@$HOME/.config/opencode/get-shit-done/workflows/execute-plan.md
|
||||
@$HOME/.config/opencode/get-shit-done/templates/summary.md
|
||||
</execution_context>
|
||||
|
||||
<context>
|
||||
@.planning/ROADMAP.md
|
||||
@.planning/phases/01-design-tokens-rams-foundation/01-CONTEXT.md
|
||||
|
||||
<interfaces>
|
||||
From plan 01-01: `theme/src/tokens.css` (@theme colors/spacing/fonts + `:root` `--type-*` entries), `theme/dist/rams.css` via `npm run build --workspace theme`. Root package.json already defines workspace delegates `build`, `sheet`, `gallery`, `audit`, `capture` (created in 01-01).
|
||||
From plan 01-02: `theme/src/sheet.html` renders all 7 mockup-derived component families; `theme/src/components.css` uses only `var(--*)` references.
|
||||
From plan 01-03: `theme/basemap/index.html` renders the Rams Liberty fork over KL (basemap at `theme/basemap/liberty-rams.json`).
|
||||
Mockups: `stitch_minimalist_route_navigator/<screen>/code.html` (CDN Tailwind — needs network) with committed `screen.png` fallbacks per screen; read-only per D-06 — screenshot them via `file://`, never edit.
|
||||
</interfaces>
|
||||
</context>
|
||||
|
||||
<tasks>
|
||||
|
||||
<task type="auto" tdd="true">
|
||||
<name>task 1: Off-token audit script (D-13)</name>
|
||||
<files>theme/scripts/audit.mjs, theme/package.json</files>
|
||||
<behavior>
|
||||
- Test: a scratch stylesheet using ONLY token values → audit exits 0
|
||||
- Test: a scratch stylesheet containing `color: #00ff00; border-radius: 12px; font-family: Arial; box-shadow: ...` → audit exits 1 and lists each offending declaration file:line
|
||||
- Test: audit of `theme/dist/rams.css` (real build from the sheet) → exit 0
|
||||
</behavior>
|
||||
<action>
|
||||
1. `theme/scripts/audit.mjs` — Node ESM, zero runtime deps:
|
||||
a. Parse `theme/src/tokens.css` to extract the allowlist: `--color-*` hex values, `--spacing-*` values, `--type-*` names/families, `--radius-*` (must all be 0). Fail loud (exit 2) with a clear message if tokens.css parses to < 40 color tokens (drift guard).
|
||||
b. Scan inputs (default `theme/dist/rams.css`; accept extra file args): flag any `#hex` literal not in the allowlist, any `font-family:` not in {Geist, Space Grotesk, ui-monospace/system fallbacks from tokens}, any `border-radius` other than 0, any `box-shadow:` or `filter: blur` / `backdrop-filter` presence (Rams Shapes: no shadows/blur/glass).
|
||||
c. Print each violation as `file:line: declaration`. Exit 1 if any, 0 if none.
|
||||
2. Wire in `theme/package.json`: `"audit": "node ./scripts/audit.mjs ./dist/rams.css"`. Root `audit` delegate already exists — verify it resolves.
|
||||
Grep-gate hygiene: use exit-code based verification, never `grep -c X == 0` over unfiltered files.
|
||||
</action>
|
||||
<verify>
|
||||
<automated>npm run build --workspace theme && npm run audit && echo AUDIT-CLEAN</automated>
|
||||
</verify>
|
||||
<done>Audit REJECTS an injected off-token stylesheet (proven during TDD RED) and passes clean against the real sheet build (DSGN-01 evidence, automated per D-13)</done>
|
||||
</task>
|
||||
|
||||
<task type="auto">
|
||||
<name>task 2: Playwright capture script + gallery page (D-14, D-12)</name>
|
||||
<files>theme/scripts/screenshot.mjs, theme/gallery.html, theme/package.json, .gitignore</files>
|
||||
<action>
|
||||
1. `npm i playwright --workspace theme` + `npx playwright install chromium` (playwright dep already declared in 01-01's theme/package.json).
|
||||
2. `theme/scripts/screenshot.mjs` (wired as root+theme `capture` script):
|
||||
- Serve `theme/` via its own tiny static server (node http) so `./dist/rams.css` resolves; capture `theme/src/sheet.html` → `theme/screenshots/sheet-full.png` (390 viewport, fullPage).
|
||||
- Capture each of the 4 mockups via `file://` with network enabled, viewport 390×844, wait networkidle + 800ms settle → `theme/screenshots/mockup-<screen>.png`. If a mockup shot fails (CDN hiccup), fall back to tracking that screen's committed `screen.png` in the gallery instead — never edit mockups (D-06).
|
||||
- Capture `theme/basemap/index.html` → `theme/screenshots/basemap-kl.png` (1280×800, wait for `map.on('idle')` or first render + 2s).
|
||||
3. `.gitignore`: ensure `theme/screenshots/` is excluded (regenerated artifacts). Wire `"capture": "node ./scripts/screenshot.mjs"`; root delegate `capture` already exists.
|
||||
4. `theme/gallery.html` — static page, CDN-free, built from tokens only. Record in a leading HTML comment that this page is the DSGN-02 template mechanism every later UI phase extends:
|
||||
- Header: "DSGN-02 Approval Gallery — Rams implementation vs mockups"
|
||||
- Comparison rows, one per mockup screen: left = mockup capture, right = `sheet-full.png` (or per-section crops); final row = `basemap-kl.png`.
|
||||
- Token ledger: table listing the typography scale + hero color token NAMES with rendered swatches/specimens only — no numeric restatement (D-07: docs never restate values).
|
||||
- Approval strip stating scope: fidelity bar + basemap direction; interactive flows out of scope (per CONTEXT deferred).
|
||||
</action>
|
||||
<verify>
|
||||
<automated>npm run capture && for f in theme/screenshots/*.png; do [ "$(stat -c%s "$f")" -lt 10240 ] && exit 1; done && test -f theme/gallery.html && grep -q "screenshots/" theme/gallery.html && npm run audit && echo GALLERY-TOOLS-OK</automated>
|
||||
</verify>
|
||||
<done>≥6 non-blank captures (sheet, 4 mockups, basemap); gallery references them; audit still clean</done>
|
||||
</task>
|
||||
|
||||
<task type="checkpoint:human-verify" gate="blocking">
|
||||
<name>task 3: DSGN-02 approval checkpoint</name>
|
||||
<what-built>
|
||||
- Centralized Tailwind v4 token package (D-01/D-02), rendered component sheet (D-03/D-11), automated off-token audit — clean (D-13), Rams Liberty basemap over KL (D-08/D-09/D-10), Playwright captures (D-14), and the side-by-side approval gallery at `theme/gallery.html` (D-12).
|
||||
</what-built>
|
||||
<action>Present the completed gallery and basemap preview to the user per the how-to-verify steps below; record the decision and wait for the resume signal before any later-phase work relies on DSGN-02.</action>
|
||||
<how-to-verify>
|
||||
1. In your shell: `npx http-server theme -p 4444` (from repo root; gallery needs a static server for fonts + relative CSS).
|
||||
2. Browse `http://localhost:4444/gallery.html` — side-by-side comparisons; judge fidelity of sheet vs mockups token-by-token.
|
||||
3. Browse `http://localhost:4444/basemap/index.html` — Rams Liberty over KL; check grayscale/muted land + water, desaturated roads, no orange anywhere (route accent reserved per D-08, rendered in Phase 5).
|
||||
4. Optionally compare against originals: `stitch_minimalist_route_navigator/<screen>/screen.png`.
|
||||
5. Confirm the automated ground for "zero off-token values": `npm run audit` (executed during this plan; output shown in the summary).
|
||||
</how-to-verify>
|
||||
<resume-signal>Type "approved" (fidelity bar met, basemap direction good) — or list specific screens/components/basemap aspects to fix and iterate before DSGN-02 is recorded.</resume-signal>
|
||||
</task>
|
||||
|
||||
</tasks>
|
||||
|
||||
<threat_model>
|
||||
## Trust Boundaries
|
||||
| Boundary | Description |
|
||||
|----------|-------------|
|
||||
| workstation browser → CDN Tailwind (mockup pages only) | Mockup screenshots fetch CDN scripts; all new design artifacts are CDN-free |
|
||||
| audit.mjs → local files | Dev-only script reads repo files only |
|
||||
|
||||
## STRIDE Threat Register
|
||||
| Threat ID | Category | Component | Disposition | Mitigation Plan |
|
||||
|-----------|----------|-----------|-------------|-----------------|
|
||||
| T-1-05 | I/T | screenshot.mjs CDN fetches | accept | Only the captured mockup pages (read-only per D-06) use CDN; captures are local gitignored artifacts. Gallery itself is CDN-free per D-16. |
|
||||
| T-1-06 | D | approval artifact provenance | mitigate | theme/gallery.html committed as the durable DSGN-02 mechanism — later UI phases extend the same file; approval decision recorded in phase summary |
|
||||
| T-1-07 | T | audit.mjs tampering | mitigate | Audit fails loud (exit 2) if token allowlist shrinks below 40 colors; violations exit 1 — no silent passes |
|
||||
</threat_model>
|
||||
|
||||
<verification>
|
||||
- `npm run audit` clean from a clean checkout after `npm run build --workspace theme`
|
||||
- `npm run capture` produces ≥6 non-blank screenshots
|
||||
- `theme/gallery.html` renders side-by-side with ≥4 captures referenced
|
||||
- User approval recorded (checkpoint passed)
|
||||
</verification>
|
||||
|
||||
<success_criteria>
|
||||
- DSGN-01 audit sweep is automated and passing (D-13)
|
||||
- DSGN-02 approval artifact exists; mechanism template documented for reuse (D-12)
|
||||
- Playwright capture script committed and working (D-14)
|
||||
- Design source of truth singular: package owns every numeric value (D-07)
|
||||
</success_criteria>
|
||||
|
||||
<output>
|
||||
After completion, create `.planning/phases/01-design-tokens-rams-foundation/01-04-SUMMARY.md`
|
||||
</output>
|
||||
@@ -0,0 +1,224 @@
|
||||
# Feature Research
|
||||
|
||||
**Domain:** Privacy-respecting, Telegram-first GPS navigation (turn-by-turn navigator as a Telegram Mini App, KL metro first)
|
||||
**Researched:** 2026-10-22
|
||||
**Confidence:** MEDIUM-HIGH (platform API details HIGH — verified against official Telegram docs; ecosystem/competitor findings MEDIUM — web sources; KL-local conventions MEDIUM — single-domain sources plus community knowledge, flagged where LOW)
|
||||
|
||||
## Feature Landscape
|
||||
|
||||
The reference products are Waze, Google Maps, OsmAnd, Organic Maps, and (as the Telegram-native analog) bots that send location/venue cards. Because araharah is a *driving assistant delivered inside a chat app*, the table-stakes set has two layers: (a) what any turn-by-turn navigator owes the user, and (b) what any Telegram experience owes the user. Both layers must be present or users bounce back to Waze — which, notably, is the dominant nav app among Klang Valley drivers, so the comparison is unavoidable.
|
||||
|
||||
### Table Stakes (Users Expect These)
|
||||
|
||||
#### Guidance & Routing Core
|
||||
|
||||
| Feature | Why Expected | Complexity | Notes |
|
||||
|---------|--------------|------------|-------|
|
||||
| Destination search with local POI/spelling tolerance | First interaction with the product. Typing "klsentral" or "KLCC" must produce the right place, or the product is dead in 10 seconds | HIGH | Nominatim is exact-ish but poor at typos; **Photon** (Komoot) is built for fuzzy/autocomplete over OSM and is the opinionated choice. Hard-constrain to KL-metro viewbox. Add a curated local gazetteer for landmark aliases (see KL section). |
|
||||
| Current-location origin (geolocation) | No one types their own address; map apps start "from here" | MEDIUM | Telegram Mini App `LocationManager` (Bot API 8.0+, Nov 2024) triggers the native permission dialog. MUST have graceful fallback: "Send location" attachment button in chat (Telegram reply keyboard `request_location`) for denied permissions. |
|
||||
| Route calculation + map display of route | The literal core value | MEDIUM | OSRM (per IDEAS.md) is fine for fastest-route + alternatives; **Valhalla** if toll avoidance/eco-cost is needed via costing options (`use_tolls`, `use_highways`). Route = polyline + per-step maneuvers + distance/time. |
|
||||
| Alternative routes (2–3 shortlist, tappable) | Every consumer nav app shows a route choice screen; showing exactly one route feels broken | MEDIUM | OSRM `alternatives=2`; present as compact cards (time, distance, headline difference "saves 8 min via DUKE"). Rams-minimal presentation is a *feature* here — Waze's route screen is cluttered; ours should be 2–3 cards max. |
|
||||
| Turn-by-turn maneuver list + next-maneuver banner | Expected shape of driving guidance | MEDIUM | Next-maneuver banner prominent (distance + arrow icon + street name), full list collapsible. Straightforward rendering of OSRM steps. |
|
||||
| Missed-turn detection and automatic recalculation | THE signal that an app is "real navigation". Waze's identity is aggressive instant rerouting; users will distrust a navigator that says "you're off route" without fixing it | MEDIUM–HIGH | Detect by snapping GPS track against route polyline; off-route threshold (~30–50m for a few seconds) triggers re-route from current snapped position. Needs map-matching of moving points — modest but easy to get wrong (jitter, tunnels, elevated highways over regular roads in KL). |
|
||||
| ETA display + progression | Users sanity-check the ETA constantly ("still 25 min?") | LOW | Remaining time/distance recomputed from current step position; update on each location fix. Google's "glanceable directions" proved the minimal ETA+maneuver+remaining-time triad is the lock-screen pattern users expect. |
|
||||
| Voice guidance (spoken turns) | Driving use case; users look at road not screen | HIGH | Web Speech API (`speechSynthesis`) works in Android webviews but is historically unreliable in iOS WKWebView — iOS Telegram users may get silence. Include mute-by-default, haptic cues on turns (Telegram `HapticFeedback`), and consider OS-side TTS test on first launch. Telegram `sendVoice` (bot TTS → opus message) is a platform-native fallback worth designing for. |
|
||||
| Speed limit display | ubiquitously expected from Google/Waze on majors | MEDIUM | OSM `maxspeed` in Malaysia is patchy off federal/highway routes (research shows OSM completeness in MY is uneven). Ship as "where data exists" — display nothing rather than wrong values. Vector tile + server-side maxspeed lookup. |
|
||||
| Live location sharing on request (arrival ETA message) | In Telegram context, users send "I'm coming" to whoever is waiting | LOW | Native: `sendLocation(live_period)` + `editMessageLiveLocation` — the bot can update a live-location thread with ETA text; zero new UI. |
|
||||
| Destination card (venue message) in chat | Before the route, the chat should show WHERE we're going | LOW | Native `sendVenue` renders a beautiful native card — free table stakes for the Telegram layer of UX. |
|
||||
|
||||
#### Telegram Layer (the chat/webview is the OS)
|
||||
|
||||
| Feature | Why Expected | Complexity | Notes |
|
||||
|---------|--------------|------------|-------|
|
||||
| /start onboarding + global commands (/help, /settings) | Telegram-recommended baseline; the whole product starts here | LOW | `/start` → 3-sentence explanation + "OK, where to?" with inline-keyboard examples. Global commands are Telegram ecosystem convention. |
|
||||
| Destination follow-up flow via chat ("ketik nama tempat") | The bot chat is the search UX in v0 of the funnel | LOW | Free-text → result list (inline keyboard) → "Open navigation" Mini App button with `startapp` param carrying the destination ID. |
|
||||
| Mini App launch with context (destination preloaded) | Users will not re-enter the destination in the webview | LOW (if flows designed together) | Pass destination via `?startapp=` deep-link / `initData`. Verified. |
|
||||
| BackButton wired to app state (route list → guidance → search) | Telegram-webview-native navigation; broken/gone BackButton = users swipe the app away entirely | LOW | `Telegram.WebApp.BackButton.show()/onClick()`; mandatory per Telegram design guideline to mimic native feel. |
|
||||
| Theme integration (light/dark) | Telegram Mini App design rule; a nav app opened at night with a white webview chrome is jarring | MEDIUM | Read `themeParams`, `colorScheme`, CSS vars; map tiles stay constant; non-map chrome adapts. Rams palette maps well onto dark mode (Matte Black #1A1A1A is already in the palette). |
|
||||
| Respect safe areas + fullscreen + landscape | Driving apps are landscape-capable; Telegram 8.0 added full-screen geo tools precisely for this | LOW–MEDIUM | `requestFullscreen()`, `safeAreaInset`, `disableVerticalSwipes()` (prevent accidental minimize while driving), `enableClosingConfirmation()` during active guidance ("abandon route?" on close attempt). |
|
||||
| Haptics on turn alerts | Replaces voice as the "eyes-on-road" cue; platform affordance exists | LOW | `WebApp.HapticFeedback.notificationOccurred()`. |
|
||||
|
||||
#### KL/Malaysia conventions
|
||||
|
||||
| Feature | Why Expected | Complexity | Notes |
|
||||
|---------|--------------|------------|-------|
|
||||
| Landmark-first search ("KLCC", "Sunway Pyramid", "1U", "Imbi", "PWTC") | Local habit: Malaysians navigate to named icons/monuments rather than street addresses; OSM Malaysia completeness is mediocre but major POIs exist | MEDIUM | Curated gazetteer (a few hundred entries: malls, transport hubs, landmarks, "Seputeh"/"Damansara Heights" colloquial district names) layered ahead of generic geocoding. This is the single most KL-specific correctness feature. |
|
||||
| Malay/name abbreviation tolerance ("Jalan"↔"Jln", "Taman"↔"Tmn") | Everyday usage; results lists must match even if the user types the short form | MEDIUM | Query normalization layer (synonym/abbreviation expansion) before geocode. Photon does fuzzy-stem matching; abbreviation mapping must be explicit (Jln, Tmn, Jln Persekutuan → FT-prefixed federal routes, "KL"→"Kuala Lumpur"). |
|
||||
| Toll-aware route option ("avoid tolls") | Klang Valley is dense with tolled highways (Plus, Sprint, LITRAK, DUKE); commuters deliberately avoid them, and toll-free trip prices differ significantly | MEDIUM (easy with Valhalla; clunky with OSRM) | With Valhalla: `use_tolls=0` costing. With OSRM: much harder (no clean toll exclusion) — an argument for Valhalla or OSRM dual-profiles. Present as "Toll / Toll-free" toggle, not a settings menu (Rams). |
|
||||
| Traffic-relevant display (congestion-aware ETA) | Users compare against Waze; a static ETA in Klang Valley traffic is fiction by definition | HIGH | Honest scoping: v1 without traffic data should show *predicted* ETA from road classes, but must not pretend it's live. Minimal honest version: re-ETA from observed pace (moving average of user's own speed = free, accurate-to-them, and privacy-friendly). Live public traffic is a differentiator below. |
|
||||
| Speed-camera awareness (AES) (v1.x borderline) | Waze popular in MY partly BECAUSE of AES camera pings | MEDIUM but data-dependent | AES camera locations are partially in OSM; scraping/curating is legally gray. Defer — it's the incident-report family, explicitly out of v1 scope (PROJECT.md). Keep on the record for v2 with the reports cluster. |
|
||||
|
||||
### Differentiators (Competitive Advantage)
|
||||
|
||||
These are where araharah wins, and every one of them flows from "privacy-respecting Rams bot + Telegram-native" — that is, they are only differentiators because the competitors (Waze/Google) structurally can't copy them.
|
||||
|
||||
| Feature | Value Proposition | Complexity | Notes |
|
||||
|---------|-------------------|------------|-------|
|
||||
| **Radical "no tracking" clarity in-product** | Users of Waze/Google have no idea what's logged. araharah can SHOW the user the words "we delete your destination when the trip ends, we never associate trips with you" — inside the product, not a privacy policy | LOW | A `/privacy` command + a 3-line statement on the Mini App landing + a visible "trip ended, deleted" confirmation. Costs almost nothing. Is the brand promise made visible. |
|
||||
| **Self-erasing guidance state** | Server keeps only a short-lived route session token; no history, no profile. Concretely differentiable vs "Google knows everywhere you've been" | MEDIUM | Architecture-level (stateless routing + ephemeral server-side session). Must be stated in the ARCHITECTURE research, but the *feature* is the visible promise. |
|
||||
| **Turn-cards in the chat when guidance is backgrounded** (the hybrid) | Waze can't message you in a chat; our guidance literally lives where the user already is. Full control: since Telegram webviews pause JS when backgrounded, the bot takes over — sends a chat card with map snapshot + next maneuver + ETA every ~2–3 min or at maneuver points | MEDIUM–HIGH | Server-side guidance session pushes `sendPhoto` with a static map snapshot (route + position marker) + text turns. Telegram-native `sendLocation(live_period)` is a zero-build coarse version. This is the marquee differentiator: **navigation that lives in Telegram instead of an app overlay**. |
|
||||
| **Rams-minimal UI (calm navigation)** | Waze = candy, ads, noise. Google Maps += POI popups. A quiet, high-contrast, icon-first guidance screen is genuinely differentiated *and* safer while driving (less visual noise = fewer glances) | MEDIUM (design-execution risk, already flagged as #1 in PROJECT.md) | The design system exists; the feature is *fidelity discipline*: no banners, no distraction, one maneuver at a time. |
|
||||
| **Home-screen shortcut access to the navigator** | "Mini app but behaves like an app" — deep link `add to home screen` makes araharah launchable without opening a chat (still inside Telegram webview runtime) | LOW | `WebApp.addToHomeScreen()` (Bot API 8.0+); pairs with homescreen `?startapp` deep-links. Cheap, big UX upside. |
|
||||
| **Opt-in traffic intelligence ("you make the map better")** | Privacy-first version of Waze's crowd data: aggregate ONLY opt-in, anonymized, coarse speed pings to weight traffic | HIGH (v2-worthy but a v1 architecture stub helps) | v1 needs only: measure aggregate performance vs OSM speeds server-side for opt-in users, improve ETA. Frame honestly at opt-in time ("help improve routing, 1-min-placeless pings"). This is the seed of v2 incident reports done right. |
|
||||
| **Trip-sharing via Telegram (this trip only)** | Send live-traveling thread to family via the *native* `sendLocation live` they already get — no account, no persistent tracking, "share once, expires" | LOW | Wrapping existing Telegram primitives gives a genuinely safety-valuable sharing flow without building any location-stream backend of our own. |
|
||||
| **Offline-calm fallback via Vector tiles caching** (deferred candidate) | KL tunnels/parking; the webview can hold tile caches (WebApp DeviceStorage, Bot API 9.0+) for recent tiles | MEDIUM | Park as v1.x; note mini-app storage is per-origin and size-limited. |
|
||||
|
||||
### Anti-Features (Commonly Requested, Often Problematic)
|
||||
|
||||
Deliberately NOT building these is not laziness, it is the product thesis (Rams: "less, but better"), and several are behaviorally toxic in a *driving* context specifically.
|
||||
|
||||
| Feature | Why Requested | Why Problematic | Alternative |
|
||||
|---------|---------------|-----------------|-------------|
|
||||
| In-app ads / POI promo cards / sponsored pins | Monetization reflex, Waze does this | Directly contradicts the brand promise; adds attention load to a *driving* surface; builds a profile per user to serve ads (breaks privacy commitment) | No monetization in v1 (already decided). If ever needed, transparent supporter banner OFF guidance screens or Bot Stars premium, never on the guidance surface |
|
||||
| Gamification: points/levels/candy/moods | Waze-heritage feature, social stickiness | Depends on incident-report social structure (out of scope); dopamine loops that reward app-time not safe driving; Rams-violating visual noise | Emotional payoff via product honesty: "you just helped improve this route for everyone" micro-acknowledgment of opt-in pings |
|
||||
| Push notification re-engagement ("You haven't driven with us in a while!") | Perfecting DAU metrics | Drive-away behavior for a privacy brand, Rams-minimalism violation, no utility | Telegram itself is opt-in messaging; only transactional messages (guidance cards, cancellation confirmations) |
|
||||
| Live incident reports / social commenting (v1) | The emotional appeal of Waze | Huge moderation scope, real-time infra, and dilutes perfecting the navigation core first; explicitly deferred in PROJECT.md Out of Scope | v1: report nothing. Architecture should leave a clean seam for v2 (opt-in aggregated speeds) |
|
||||
| Account/sign-up, phone number request, email | Standard SaaS onboarding reflex | Anti-differentiator; everything already exists via Telegram identity | `initData` validation server-side, that is ALL (already the plan). Never call `requestContact()` |
|
||||
| Fat JSON payload/feature-rich settings menus (route aversion toggles, max speed preferences, per-type avoidance) | Power users request them | Rams principle: hidden decision complexity → settings sprawl; driving apps must not bury the ONE decision (route choice) under options | Three choices max: fastest / toll-free / shorter-dist; everything else derived from defaults |
|
||||
| Offline maps (!) | Asked for in every nav product, especially OSM-ecosystem reviewers | Architecturally contrary to a Telegram webview app; tiles+lengthy download UX conflicts with chat-first lightweight promise | Trip-aware tile prefetch in-session (small radius), not offline product |
|
||||
| "Chat with an AI assistant" flavor onboarding | LLM-era reflex | Confuses the mental model (navigation is stateful precision, chat is flexible) with token costs and latency | Deterministic, byte-sized onboarding, command-native |
|
||||
| Echoing user's location messages into group chats/social features | Attractive for carpool/ETA groups | Crosses individual-user privacy boundary for a feature whose users didn't opt in to being broadcast—must be user-initiated share only | Trip-sharing feature (differentiator above) — always explicitly user-triggered |
|
||||
|
||||
## Feature Dependencies
|
||||
|
||||
```
|
||||
Telegram search UX (commands, followup flow)
|
||||
└─requires──> Destination search (gazetteer + geocode)
|
||||
└─requires──> KL spec: gazetteer + abbreviations, tolls map defaults
|
||||
└──enhances──> Venue message (sendVenue)
|
||||
|
||||
Mini App launch (startapp deep-link)
|
||||
└─requires──> Telegram search UX (you need a destination to carry)
|
||||
& ──requires──> LocationManager (geolocation permission, origin)
|
||||
|
||||
LocationManager (origin)
|
||||
└─requires──> Privacy UX (permission fallback path)
|
||||
|
||||
Route calculation
|
||||
└─requires──> Destination search ✔ & Current location ✔
|
||||
└──enhances──> Speed limit display (routes intersect maxspeed data)
|
||||
|
||||
Toll-free routing option
|
||||
└─requires──> Valhalla-like costing (or OSRM multi-profile), tile rendering compatible
|
||||
|
||||
Turn-by-turn guidance
|
||||
└─requires──> Route calculation
|
||||
└──requires──> Missed-turn detection ──requires──> Recalculation
|
||||
└──requires──> ETA progression
|
||||
└──enhances──> Voice guidance ──requires──> TTS support (with fallback), haptics
|
||||
|
||||
Backgrounded chat turn-cards (hybrid guidance)
|
||||
└─requires──> Turn-by-turn guidance ✔
|
||||
└─requires──> Server-side guidance session (ephemeral state) ← privacy-positive
|
||||
└─requires──> Static map snapshot renderer (chat photos)
|
||||
|
||||
Mini App theming + BackButton + haptics
|
||||
└─no feature deps (platform affordances, standalone wiring)
|
||||
|
||||
Home-screen shortcut
|
||||
└─enhances──> search entry point (deep link with no chat needed)
|
||||
|
||||
Opt-in traffic weighting
|
||||
└─requires──> Server aggregator + strong privacy UI statement
|
||||
└──conflicts-in-v1──> reliability of guidance focus (scope creep risk)
|
||||
|
||||
Incident reports / social / gamification
|
||||
└─requires──> Opt-in traffic weighting + moderation + groups model (v2 depends on this base)
|
||||
```
|
||||
|
||||
### Dependency Notes
|
||||
|
||||
- **Guidance requires search + geolocation**: the funnel must be built in this order or nothing demonstrates value.
|
||||
- **Recalculation depends on off-route detection**, which depends on having route geometry server-side or client-side — the chat-card fallback complicates this (server must re-match); architecture research should treat "guidance session state" as a first-class component.
|
||||
- **Toll-free routing conflicts with OSRM-only choice** — the routing engine decision (STACK research) is constrained by this one feature requiring good costing customization.
|
||||
- **Voice guidance conflicts with iOS webview reliability** — do not make voice the only modality; haptics + turn-cards carry the same information.
|
||||
- **Privacy features are not feature-isolated**: "no tracking" is visible only if the architecture research confirms ephemeral server-side sessions; otherwise it's a lie.
|
||||
|
||||
## MVP Definition
|
||||
|
||||
### Launch With (v1)
|
||||
|
||||
- [ ] **/start onboarding + /help** — the Telegram UX starts here; zero-cost
|
||||
- [ ] **Destination search (Photon/gazetteer, KL-bounded, alias + abbreviation normalizer)** — a local POI failure here kills everything downstream
|
||||
- [ ] **Venue card in chat (sendVenue)** — native, instant trust and clarity that we understood the destination; also "Arrive location" visually in chat
|
||||
- [ ] **Mini App launch with destination in `startapp`** — the webview must not make the user re-input
|
||||
- [ ] **Geolocation via LocationManager + chat location-send fallback** — the origin side of the funnel
|
||||
- [ ] **Route draw + alternatives (2–3 cards, time/distance) + Mini App route-choice screen**
|
||||
- [ ] **Turn-by-turn guidance screen (next-maneuver banner + collapsible full list)**
|
||||
- [ ] **Missed-turn detection + auto recalculation** — the "is this real navigation" test
|
||||
- [ ] **ETA + remaining distance progression** — minimum viable "live" feel
|
||||
- [ ] **Haptic turn cues** — cheap, eyes-free, no TTS risk
|
||||
- [ ] **BackButton, close-confirmation during active guidance, disable swipe-close** — platform behavioral hygiene
|
||||
- [ ] **Theme integration (light/dark) + Rams map colors** — direct PROJECT.md "design fidelity" requirement
|
||||
- [ ] **Home-screen shortcut + deep link `startapp` retrieval** — one call + one param parse, major retained-UX payoff
|
||||
- [ ] **Privacy statement visible in-product (Mini App onboard + /privacy)** — brand promise made concrete
|
||||
|
||||
### Add After Validation (v1.x)
|
||||
|
||||
- [ ] **Voice guidance with tested webview TTS + mute-by-default** — once driving flow is reliable; important for real point-A-to-point-B daily use
|
||||
- [ ] **Backgrounded chat turn-cards w/ static map snapshot + server-side guidance session** — this is the flip-side of the hybrid; requires an ephemeral background session design (authentic differentiator, worth planning as its own phase rather than bolting on)
|
||||
- [ ] **Live-trip share via sendLocation/editMessageLiveLocation** — single feature, high family-safety utility
|
||||
- [ ] **Toll-free route toggle (if engine switch justified; Valhalla costing)** — matters to many KL commuters; ship once route core is solid
|
||||
- [ ] **Speed limit display where OSM has maxspeed** — incremental accuracy on majors
|
||||
- [ ] **Home-screen tiles caching / modest offline trip radius** — stub for future robustness
|
||||
|
||||
### Future Consideration (v2+)
|
||||
|
||||
- [ ] **Opt-in anonymized crowd speed/aggregated data → smarter ETAs** — only after the privacy brand is established and the core trips are proven; the moderation/consent/alert infrastructure for incidents follows this
|
||||
- [ ] **Incident reports + broadcasts (already deferred per PROJECT.md)** — big scope including moderation
|
||||
- [ ] **Regional groups/carpool social (already deferred)** — unvalidated hypothesis per PROJECT.md Out of Scope
|
||||
- [ ] **Speed-camera (AES) layer** — only with legal clarity; lives with the incident family
|
||||
|
||||
## Feature Prioritization Matrix
|
||||
|
||||
| Feature | User Value | Implementation Cost | Priority |
|
||||
|---------|------------|---------------------|----------|
|
||||
| Telegram onboarding (/start, /help, commands) | HIGH | LOW | P1 |
|
||||
| KL-accurate destination search w/ aliases | HIGH | HIGH | P1 |
|
||||
| Mini App launch + BackButton + theme | HIGH | LOW–MED | P1 |
|
||||
| Geolocation (LocationManager + fallback) | HIGH | MEDIUM | P1 |
|
||||
| Route + alternatives screen | HIGH | MEDIUM | P1 |
|
||||
| Turn-by-turn map guidance | HIGH | MEDIUM–HIGH | P1 |
|
||||
| Missed-turn recalculation | HIGH | MEDIUM–HIGH | P1 |
|
||||
| ETA progression | HIGH | LOW | P1 |
|
||||
| Haptic turn cues | MED | LOW | P1 |
|
||||
| In-product privacy statement | MED (brand-critical) | LOW | P1 |
|
||||
| Home-screen shortcut | MED | LOW | P1 |
|
||||
| Venue cards in chat | MED | LOW | P1 |
|
||||
| Voice guidance | HIGH | HIGH | P2 (v1.x) |
|
||||
| Backgrounded chat turn-cards | HIGH | HIGH | P2 (v1.x) |
|
||||
| Live-trip share | MED–HIGH | LOW | P2 |
|
||||
| Toll-free routing toggle | MED–HIGH (KL) | MEDIUM | P2 |
|
||||
| Speed limit display | MED | MEDIUM | P2 |
|
||||
| Opt-in traffic weighting | MED (sets v2) | HIGH | P3 |
|
||||
| Incident reports / social | MED | HIGH | P3 (v2, per scope) |
|
||||
|
||||
**Priority key:** P1 = must have for launch; P2 = should have, add when possible; P3 = future consideration.
|
||||
|
||||
## Competitor Feature Analysis
|
||||
|
||||
| Feature | Waze | Google Maps | OsmAnd | Our Approach |
|
||||
|---------|------|-------------|--------|--------------|
|
||||
| Missed-turn recalculation | Instant, aggressive; the fastest in class | Instant, calm | Good, slower | Auto-instant; the "is this real navigation" bar |
|
||||
| Alternatives on route screen | Up to 3, plus Waze community flavor | 2–3 + date/arrival estimates | List form | 2–3 quiet Rams cards; time + distance + one-line reason |
|
||||
| Voice guidance | Full characterful TTS | Full TTS | Yes (recorded + TTS) | v1.x; mute-by-default, haptic-first, webview-TTS honest fallback |
|
||||
| ETA accuracy in KL traffic | Best-in-class (crowd-sourced) | Very good | Weak (no traffic) | v1 honest local self-paced ETA; opt-in aggregate traffic later |
|
||||
| Speed limit + cameras | Speed limits everywhere + AES pings (crowd) | Patchy speed limits, no speeds in MY? infrared source dependence | Maxspeed from OSM | Show where OSM is confident; no camera layer in v1 (defer with reports) |
|
||||
| Social / incident reports | Core-identity feature (reports, chat, feeds) | Incorporated lightly (accidents/fog/police icons) | Community map editor only | Deliberately absent v1; opt-in crowd-speed is the v2 social replacement, privacy-first |
|
||||
| Privacy story | Profiled, sold-into Google ecosystem | Full behavioral pipeline | Excellent (offline-capable, no tracking) | Best-in-class *and visible*: ephemeral session, stored nothing, stated on every screen entry |
|
||||
| Form factor | Native app store install | Native app | Native app | Telegram chat + Mini App — zero install, destination search where conversation lives |
|
||||
| Toll awareness | Routed with tolls, options | Good toll toggle | OSM routing tagging support | Expected KL feature; togglable, one prominent toggle |
|
||||
|
||||
## Sources
|
||||
|
||||
- **Telegram Mini App Web Apps platform docs** (core.telegram.org/bots/webapps) — BackButton, LocationManager (Bot API 8.0, Nov 2024), full-screen/safe-area/`addToHomeScreen`/`startapp` deep-linking/`themeParams`/`HapticFeedback`/DeviceStorage, disable/enable vertical swipes, closing confirmation — verified against the current released API docs — **HIGH confidence**
|
||||
- **Telegram Bot Features guide** (core.telegram.org/bots/features) — commands, global commands (/start,/help,/settings), reply/inline keyboards, `sendVenue` location/venue messages, live location + `editMessageLiveLocation`, privacy mode — **HIGH confidence**
|
||||
- **Waze vs Google Maps comparisons 2025–2026** (ZDNet 2026-07, PCMag 2026-07, USA Today 2025-07) — rerouting-aggressiveness, speed-limit display behavior, Waze popularity with drivers — **MEDIUM confidence** (third-party review articles)
|
||||
- **OSM Malaysia quality studies** (ResearchGate "Quality of OSM in Malaysia" preliminary assessment) — OSM completeness in MY described as "...good relative positioning in road features, but still poor in terms of completeness (POI coverage)" — **MEDIUM-HIGH confidence** (peer-reviewed-adjacent research)
|
||||
- **Telegram live locations blog** (telegram.org/blog/live-locations) — live-location primitive behavior — **HIGH confidence**
|
||||
- **Routing engine capability notes** (GitHub OSRM/Valhalla issues + ecosystem articles) — OSRM does not have native toll-exclusion costing; Valhalla costing supports `use_tolls` etc. — **MEDIUM confidence** (engineer-sourced, not yet doc-fetched)
|
||||
- **Domain knowledge / training-data reasoning** (flagged LOW, verify at phase research): webview TTS iOS reliability (WKWebView speechSynthesis quirks), exact OSM maxspeed completeness levels per KL arterial, exact AES camera data availability in OSM — **LOW confidence**, needs phase-specific verification before planning voice/speed features
|
||||
|
||||
---
|
||||
*Feature research for: Privacy-respecting Telegram-first GPS navigation app (ararahah, KL metro)*
|
||||
*Researched: 2026-10-22*
|
||||
Reference in New Issue
Block a user