/ plans / roadmap.org
roadmap.org
  1  #+title: Mission Control Dashboard - Implementation Roadmap
  2  #+author: PRD Generator
  3  #+date: [2026-04-02 Thu]
  4  #+startup: indent
  5  #+options: toc:t num:t
  6  
  7  * Roadmap Overview
  8  
  9  This file breaks down the PRD into independently-grabbable Radicle issues
 10  using tracer-bullet vertical slices.
 11  
 12  ** Tracer Bullet Strategy
 13  
 14  Each issue is designed to:
 15  - Be independently implementable in 20-60 minutes
 16  - Produce visible progress on the map
 17  - Work end-to-end (even if minimal)
 18  - Stand on its own as a commit
 19  
 20  ** Issue Categories
 21  
 22  | Category | Description                               | Issues |
 23  |----------+-------------------------------------------+--------|
 24  | Setup    | Project scaffolding, dependencies, config |    1-4 |
 25  | Phase 1  | Aircraft polling with OpenSky             |   5-11 |
 26  | Phase 2  | Mission assets over WebSocket             |  12-18 |
 27  | Phase 3  | Transit vehicles via SSE                  |  19-24 |
 28  | Polish   | Integration, UI refinement, docs          |  25-27 |
 29  | Future   | Stretch goals                             |  28-32 |
 30  
 31  * Setup Issues
 32  
 33  ** Issue 001: Scaffold TanStack Start Project [#DONE]
 34     :PROPERTIES:
 35     :RADICLE-KEY: MC-001
 36     :TRACER-BULLET: yes
 37     :END:
 38  
 39     - [X] Project created with `npx @tanstack/cli@latest create mission-control`
 40     - [X] Dev server runs and shows default starter page
 41     - [X] TypeScript configured with strict mode
 42     - [X] Routing structure works (`/` route renders)
 43     - [X] No type errors in editor
 44     - [X] Closed: Radicle issue 9bc5329 (and duplicate 1e87efc)
 45  
 46  ** Issue 002: Install Dependencies
 47     :PROPERTIES:
 48     :RADICLE-KEY: MC-002
 49     :TRACER-BULLET: yes
 50     :END:
 51  
 52     - [X] Install leaflet + react-leaflet
 53     - [X] Install xstate + @xstate/react (connection lifecycle machines)
 54     - [X] Install @xstate/store (shared application state — see [[file:../doc/decisions/adr_001_state_store_selection.org][ADR-001]])
 55     - [X] Install @types/leaflet (dev)
 56     - [X] Verify no type errors
 57     - [X] Commit: "feat: install mapping and state libraries"
 58  
 59  ** Issue 003: Configure Project Structure
 60     :PROPERTIES:
 61     :RADICLE-KEY: MC-003
 62     :TRACER-BULLET: yes
 63     :END:
 64  
 65     - [X] Create src/types/ directory
 66     - [X] Create src/components/ directory
 67     - [X] Create src/machines/ directory (XState connection lifecycle)
 68     - [X] Create src/stores/ directory (@xstate/store shared state)
 69     - [X] Create src/server/ directory (TanStack server functions)
 70     - [X] Configure tsconfig paths (optional)
 71     - [X] Commit: "chore: set up project structure"
 72  
 73     See [[file:../doc/decisions/adr_001_state_store_selection.org][ADR-001]] for state management architecture.
 74  
 75  ** Issue 004: Set Up Root Layout
 76     :PROPERTIES:
 77     :RADICLE-KEY: MC-004
 78     :TRACER-BULLET: yes
 79     :END:
 80  
 81     - [X] Update __root.tsx with proper head meta
 82     - [X] Add Leaflet CSS to document head
 83     - [X] Configure document structure
 84     - [X] Verify app renders correctly
 85     - [X] Commit: "feat: set up root layout"
 86  
 87  * Phase 1: Aircraft Polling
 88  
 89  ** Issue 005: Define Aircraft Type
 90     :PROPERTIES:
 91     :RADICLE-KEY: MC-005
 92     :TRACER-BULLET: yes
 93     :END:
 94  
 95     - [ ] Create src/types/aircraft.ts
 96     - [ ] Define Aircraft interface with all fields
 97     - [ ] Mark nullable fields appropriately
 98     - [ ] Export types for use across project
 99     - [ ] Commit: "feat: define aircraft type"
100  
101  ** Issue 006: Create Server Function for OpenSky
102     :PROPERTIES:
103     :RADICLE-KEY: MC-006
104     :TRACER-BULLET: yes
105     :END:
106  
107     - [ ] Create src/server/opensky.ts
108     - [ ] Define bounding box for Switzerland
109     - [ ] Implement parseStateVector()
110     - [ ] Handle null/undefined fields
111     - [ ] Commit: "feat: create OpenSky server function"
112  
113  ** Issue 007: Build Aircraft Polling Machine
114     :PROPERTIES:
115     :RADICLE-KEY: MC-007
116     :TRACER-BULLET: yes
117     :END:
118  
119     - [ ] Create src/machines/aircraftPollingMachine.ts
120     - [ ] Define context (aircraft, error, lastUpdated)
121     - [ ] Implement fetching/wainting states
122     - [ ] Add 10s after delay
123     - [ ] Commit: "feat: create aircraft polling XState machine"
124  
125  ** Issue 008: Create Aircraft Marker Component
126     :PROPERTIES:
127     :RADICLE-KEY: MC-008
128     :TRACER-BULLET: yes
129     :END:
130  
131     - [ ] Create src/components/AircraftMarker.tsx
132     - [ ] Implement aircraft icon with L.divIcon
133     - [ ] Add popup with telemetry
134     - [ ] Handle null latitude/longitude
135     - [ ] Add click handler for selection
136     - [ ] Commit: "feat: create aircraft marker component"
137  
138  ** Issue 009: Create Aircraft CSS
139     :PROPERTIES:
140     :RADICLE-KEY: MC-009
141     :TRACER-BULLET: yes
142     :END:
143  
144     - [ ] Create src/aircraft.css
145     - [ ] Style aircraft icon
146     - [ ] Ensure clean rendering
147     - [ ] Commit: "feat: add aircraft marker styles"
148  
149  ** Issue 010: Integrate Polling Machine into Map
150     :PROPERTIES:
151     :RADICLE-KEY: MC-010
152     :TRACER-BULLET: yes
153     :END:
154  
155     - [ ] Update src/components/Map.tsx
156     - [ ] Wire up useMachine hook
157     - [ ] Render AircraftMarker components
158     - [ ] Implement telemetry sidebar
159     - [ ] Commit: "feat: integrate aircraft polling into map"
160  
161  ** Issue 011: Add Polling State Display
162     :PROPERTIES:
163     :RADICLE-KEY: MC-011
164     :TRACER-BULLET: yes
165     :END:
166  
167     - [ ] Show polling state (fetching/waiting) in sidebar
168     - [ ] Display last update time
169     - [ ] Show aircraft count
170     - [ ] Handle and display errors
171     - [ ] Commit: "feat: display polling state in sidebar"
172  
173  * Phase 2: WebSocket Mission Assets
174  
175  ** Issue 012: Define Mission Types
176     :PROPERTIES:
177     :RADICLE-KEY: MC-012
178     :TRACER-BULLET: yes
179     :END:
180  
181     - [ ] Create src/types/mission.ts
182     - [ ] Define MissionAsset interface
183     - [ ] Define MissionAlert interface
184     - [ ] Define MissionMessage type
185     - [ ] Commit: "feat: define mission types"
186  
187  ** Issue 013: Build Mission WebSocket Machine
188     :PROPERTIES:
189     :RADICLE-KEY: MC-013
190     :TRACER-BULLET: yes
191     :END:
192  
193     - [ ] Create src/machines/missionWebSocketMachine.ts
194     - [ ] Define context (assets, alerts, connected)
195     - [ ] Implement connecting/reconnecting/streaming states
196     - [ ] Add fromCallback WebSocket actor
197     - [ ] Commit: "feat: create WebSocket XState machine"
198  
199  ** Issue 014: Create Mission Marker Component
200     :PROPERTIES:
201     :RADICLE-KEY: MC-014
202     :TRACER-BULLET: yes
203     :END:
204  
205     - [ ] Create src/components/MissionMarker.tsx
206     - [ ] Implement three icons (drone/vehicle/sensor)
207     - [ ] Add popup with status/battery
208     - [ ] Commit: "feat: create mission marker component"
209  
210  ** Issue 015: Create Alerts Sidebar Component
211     :PROPERTIES:
212     :RADICLE-KEY: MC-015
213     :TRACER-BULLET: yes
214     :END:
215  
216     - [ ] Create src/components/AlertsSidebar.tsx
217     - [ ] Implement severity-based styling
218     - [ ] Show no alerts state
219     - [ ] Commit: "feat: create alerts sidebar"
220  
221  ** Issue 016: Update Map to Include Mission Assets
222     :PROPERTIES:
223     :RADICLE-KEY: MC-016
224     :TRACER-BULLET: yes
225     :END:
226  
227     - [ ] Import missionWebSocketMachine
228     - [ ] Render MissionMarker components
229     - [ ] Wire up AlertsSidebar
230     - [ ] Commit: "feat: add mission assets to map"
231  
232  ** Issue 017: Create WebSocket Server (VPS)
233     :PROPERTIES:
234     :RADICLE-KEY: MC-017
235     :TRACER-BULLET: yes
236     :END:
237  
238     - [ ] Set up project on VPS
239     - [ ] Initialize Node.js project
240     - [ ] Install ws package
241     - [ ] Create server.js with asset simulation
242     - [ ] Start and verify server
243     - [ ] Commit: "feat: create WebSocket server for mission assets"
244  
245  ** Issue 018: Test WebSocket Connection
246     :PROPERTIES:
247     :RADICLE-KEY: MC-018
248     :TRACER-BULLET: yes
249     :END:
250  
251     - [ ] Configure VPS IP in machine
252     - [ ] Verify connection in browser
253     - [ ] Test reconnection after disconnect
254     - [ ] Commit: "test: verify WebSocket reconnection"
255  
256  * Phase 3: SSE Transit Vehicles
257  
258  ** Issue 019: Define Transit Types
259     :PROPERTIES:
260     :RADICLE-KEY: MC-019
261     :TRACER-BULLET: yes
262     :END:
263  
264     - [ ] Create src/types/transit.ts
265     - [ ] Define TransitVehicle interface
266     - [ ] Export for use across project
267     - [ ] Commit: "feat: define transit types"
268  
269  ** Issue 020: Build Transit SSE Machine
270     :PROPERTIES:
271     :RADICLE-KEY: MC-020
272     :TRACER-BULLET: yes
273     :END:
274  
275     - [ ] Create src/machines/transitSSEMachine.ts
276     - [ ] Define SSEEvent union type
277     - [ ] Implement streaming state
278     - [ ] Add handlers for reset/update/add/remove
279     - [ ] No reconnection state needed
280     - [ ] Commit: "feat: create SSE XState machine"
281  
282  ** Issue 021: Create Transit Marker Component
283     :PROPERTIES:
284     :RADICLE-KEY: MC-021
285     :TRACER-BULLET: yes
286     :END:
287  
288     - [ ] Create src/components/TransitMarker.tsx
289     - [ ] Implement bus icon
290     - [ ] Add popup with route/status
291     - [ ] Commit: "feat: create transit marker component"
292  
293  ** Issue 022: Add Transit Machine to Map
294     :PROPERTIES:
295     :RADICLE-KEY: MC-022
296     :TRACER-BULLET: yes
297     :END:
298  
299     - [ ] Import transitSSEMachine
300     - [ ] Render TransitMarker components
301     - [ ] Verify SSE connection
302     - [ ] Commit: "feat: add transit vehicles to map"
303  
304  ** Issue 023: Test MBTA API Connection
305     :PROPERTIES:
306     :RADICLE-KEY: MC-023
307     :TRACER-BULLET: yes
308     :END:
309  
310     - [ ] Get MBTA API key
311     - [ ] Configure key in machine
312     - [ ] Verify vehicles appear
313     - [ ] Test auto-reconnection
314     - [ ] Commit: "test: verify MBTA SSE connection"
315  
316  ** Issue 024: Handle SSE Event Types
317     :PROPERTIES:
318     :RADICLE-KEY: MC-024
319     :TRACER-BULLET: yes
320     :END:
321  
322     - [ ] Verify reset event clears all vehicles
323     - [ ] Verify update modifies existing vehicle
324     - [ ] Verify add appends new vehicle
325     - [ ] Verify remove filters vehicle
326     - [ ] Commit: "feat: handle all SSE event types"
327  
328  * Integration & Polish
329  
330  ** Issue 025: Combine All Three Data Sources
331     :PROPERTIES:
332     :RADICLE-KEY: MC-025
333     :TRACER-BULLET: yes
334     :END:
335  
336     - [ ] Add all three useMachine calls to Map
337     - [ ] Render all marker types
338     - [ ] Verify no conflicts
339     - [ ] Commit: "feat: integrate all three transport patterns"
340  
341  ** Issue 026: Create Unified Sidebar
342     :PROPERTIES:
343     :RADICLE-KEY: MC-026
344     :TRACER-BULLET: yes
345     :END:
346  
347     - [ ] Combine all state displays in one sidebar
348     - [ ] Add connection status indicators
349     - [ ] Show asset counts by category
350     - [ ] Unified telemetry panel
351     - [ ] Commit: "feat: create unified sidebar"
352  
353  ** Issue 027: Add Final Visual Polish
354     :PROPERTIES:
355     :RADICLE-KEY: MC-027
356     :TRACER-BULLET: yes
357     :END:
358  
359     - [ ] Add connection status icons (green/red)
360     - [ ] Improve telemetry panel styling
361     - [ ] Add loading states
362     - [ ] Create DefaultCatchBoundary error component
363     - [ ] Create NotFound component
364     - [ ] Wire errorComponent and notFoundComponent into root route
365     - [ ] Verify responsive layout
366     - [ ] Commit: "refactor: add visual polish"
367  
368  * Future Enhancements
369  
370  ** Issue 028: Marker Clustering
371     :PROPERTIES:
372     :RADICLE-KEY: MC-028
373     :TRACER-BULLET: yes
374     :END:
375  
376     - [ ] Research marker clustering options
377     - [ ] Implement for performance
378     - [ ] Test with many markers
379     - [ ] Commit: "feat: add marker clustering"
380  
381  ** Issue 029: Filter by Asset Type
382     :PROPERTIES:
383     :RADICLE-KEY: MC-029
384     :TRACER-BULLET: no
385     :END:
386  
387     - [ ] Add toggle controls
388     - [ ] Filter visible markers
389     - [ ] Update counts display
390     - [ ] Commit: "feat: add asset type filters"
391  
392  ** Issue 030: Historical Tracking
393     :PROPERTIES:
394     :RADICLE-KEY: MC-030
395     :TRACER-BULLET: no
396     :END:
397  
398     - [ ] Store position history
399     - [ ] Draw path trails
400     - [ ] Add timeline control
401     - [ ] Commit: "feat: add historical tracking"
402  
403  ** Issue 031: Alert Export
404     :PROPERTIES:
405     :RADICLE-KEY: MC-031
406     :TRACER-BULLET: no
407     :END:
408  
409     - [ ] Implement export function
410     - [ ] Support CSV/JSON formats
411     - [ ] Add download button
412     - [ ] Commit: "feat: add alert export"
413  
414  ** Issue 032: Multi-Region Support
415     :PROPERTIES:
416     :RADICLE-KEY: MC-032
417     :TRACER-BULLET: no
418     :END:
419  
420     - [ ] Add region selector
421     - [ ] Change bounding box for OpenSky
422     - [ ] Change SSE URL for different MBTA regions
423     - [ ] Commit: "feat: add multi-region support"