feat(dashboard): complete React cutover

This commit is contained in:
jjbrunton committed 2026-08-08 16:11:57 +01:00
1 parent d5f0175dc2
commit ec0cd1318b
13 files changed
+50 -4291

No files matched your search

+3 -5
View File
@@ -1000,16 +1000,14 @@ the complete validated event envelope:
Clients may reconnect with `Last-Event-ID`; the server replays retained events
after that ID in order. The stream sends heartbeats, bounds buffered events and
slow-client queues. Applying the same authentication boundary as the API is a
pending cutover gate.
slow-client queues, and uses the same authentication boundary as the API.
Current event families include bot status, message sent or failed,
conversation updated, reply received, sync lifecycle and progress, rate-limit
state, Reddit session state, and logs.
`GET /api/logs/stream` remains temporarily available for the legacy dashboard.
Its untyped `connected`, `log`, and `sync-progress` frames should not be used by
new clients.
`GET /api/logs/stream` remains temporarily available for compatibility tooling.
New clients use the typed `/api/events/stream` endpoint.
**Log Levels**:
+5 -15
View File
@@ -167,8 +167,6 @@ RedditBot/
│ └── dist/ # Generated production assets (not committed)
├── packages/
│ └── api-contracts/ # Shared Zod HTTP and realtime schemas
├── public/
│ └── index.html # Temporary legacy dashboard fallback
├── scripts/
│ ├── inspect-chat-dom.ts # Debug: inspect chat DOM structure
│ └── login.ts # Manual browser login helper
@@ -203,7 +201,7 @@ RedditBot/
│ └── image.ts # Image download + base64 + MIME validation (34 lines)
└── web/
├── server.ts # Express API, SSE, and dashboard host
├── dashboard-assets.ts # React-build selection with legacy fallback
├── dashboard-assets.ts # Required production React-build resolver
└── events/ # Typed event hub and Express SSE adapter
```
@@ -412,10 +410,8 @@ Express server with API route modules and SSE transport.
keys; cached content remains visible if the stream reconnects.
- Vite writes production assets to `apps/dashboard/dist`.
The asset resolver prefers the React build and can fall back to
`public/index.html`. Wiring that resolver into authenticated Express static and
private-media hosting is still a migration gate; the legacy file has not been
removed.
The asset resolver requires the production React build. Express serves those
assets, API/SSE routes, and private media behind one authentication boundary.
---
@@ -922,15 +918,9 @@ Deployment documentation is provided in `DOKPLOY_DEPLOY.md`.
### Medium Priority
7. **Legacy dashboard fallback** - `public/index.html` remains during migration.
Remove it only after authenticated React hosting and feature-parity gates pass.
7. **Config Mutability** - Runtime config updates via `PUT /api/config` modify the in-memory config object. Consider a proper config service with validation on updates.
8. **Settings route** - The React route is still a placeholder; runtime and
access settings have not yet moved into validated route-backed forms.
9. **Config Mutability** - Runtime config updates via `PUT /api/config` modify the in-memory config object. Consider a proper config service with validation on updates.
10. **Error Handling** - Some services have basic try/catch. Consider structured error types with retry logic.
8. **Error Handling** - Some services have basic try/catch. Consider structured error types with retry logic.
### Low Priority
+4 -5
View File
@@ -691,11 +691,10 @@ services/repositories -> Express /api snapshots -> Zod -> TanStack Query -> Reac
+-> realtime event hub -> /api/events/stream --------+
```
### Legacy fallback model
### Retired legacy model
The diagram below describes `public/index.html`, which remains only as a
compatibility fallback until Express is switched to authenticated React static
hosting and private-media protection is verified.
The historical diagram below is retained for migration context only.
`public/index.html` has been removed and is no longer served.
```
┌─────────────────────────────────────────────────────────────────┐
@@ -734,7 +733,7 @@ hosting and private-media protection is verified.
│ │ └─► Data: { level, message, timestamp } │
│ └─► On disconnect: unsubscribe │
│ │
│ ──── LEGACY FALLBACK (public/index.html) ──────────────────── │
│ ──── RETIRED LEGACY IMPLEMENTATION ────────────────────────── │
│ │
│ JavaScript polls API endpoints: │
│ ├─► /api/stats every 5 seconds │
+1 -1
View File
@@ -124,7 +124,7 @@ npm start
### 5. Access Dashboard
Open the Vite URL (normally http://localhost:5173) during frontend development.
Production and legacy-fallback checks use http://localhost:3000.
Production dashboard checks use http://localhost:3000.
---
+2 -5
View File
@@ -30,8 +30,6 @@ RedditBot/
│ └── dashboard/ # React + Vite operator console
├── packages/
│ └── api-contracts/ # Shared Zod transport contracts
├── public/
│ └── index.html # Temporary legacy dashboard fallback
├── scripts/
│ ├── login.ts # Manual login helper
│ └── inspect-chat-dom.ts # DOM inspection debug script
@@ -521,9 +519,8 @@ Reddit frequently updates their `faceplate-*` components. Shadow DOM traversal c
### Dashboard Migration Boundary
The React feature slices live in `apps/dashboard`, but `public/index.html`
remains as a compatibility fallback. Do not delete it until authenticated
Express hosting, private-media protection, and browser parity checks are proven.
The React application lives in `apps/dashboard`. A production build is required
before the Express server starts; there is no legacy HTML fallback.
The repository has automated service, contract, component, and transport tests.
Manual browser verification is still required for Reddit DOM changes and the
+18 -26
View File
@@ -2,29 +2,22 @@
## Outcome
Replace the inline dashboard in `public/index.html` with a typed, accessible React
application without disrupting the bot worker or its Express API. At cutover,
Express will remain the authenticated API, SSE, private-media, and static-asset
host.
The inline dashboard has been replaced by a typed, accessible React application.
Express remains the authenticated API, SSE, private-media, and production
static-asset host.
## Current status
The React application and production build are present. The current routes are
Overview, Conversations (including route-addressable detail), Media,
Performance, Operations, and a Settings placeholder. Shared HTTP and realtime
schemas live in `packages/api-contracts`, and `/api/events/stream` supplies the
typed SSE transport.
The current routes are Overview, Conversations (including route-addressable
detail), Media, Performance, Operations, and validated Settings and Access.
Shared HTTP and realtime schemas live in `packages/api-contracts`, and
`/api/events/stream` supplies the typed SSE transport.
`npm run build` compiles the server and writes the Vite application to
`apps/dashboard/dist`. `src/web/dashboard-assets.ts` can select that build and
fall back to `public/index.html`, but the checked-in Express server has not yet
completed that authenticated static-hosting cutover. Until it does, the legacy
page remains the served fallback and the dashboard must not be exposed to an
untrusted network.
The migration is complete only when the legacy dashboard can be removed without
losing a documented capability and the full test, type-check, production-build,
browser-acceptance, authentication, private-media, and reconnect gates pass.
`apps/dashboard/dist`. `src/web/dashboard-assets.ts` requires that build and
fails startup with an actionable error if it is absent. The legacy HTML has
been removed. Root pages, assets, APIs, SSE, and private media share the same
timing-safe dashboard authentication boundary.
## Architecture
@@ -50,7 +43,7 @@ The application shell provides a responsive sidebar or drawer with these routes:
| `/media` | Private blurred-by-default gallery and sync controls |
| `/performance` | Trends, strategies, subreddits, and successful examples |
| `/operations` | Domain activity, background jobs, and diagnostics |
| `/settings` | Placeholder for runtime and access settings |
| `/settings` | Validated runtime configuration and Reddit access state |
Overview surfaces bot state, dry-run state, cooldowns, timers, and the guarded
start/stop control. Operations owns connection health, sync state, activity,
@@ -89,8 +82,8 @@ and falls back to visibility-aware polling where necessary.
9. Run feature parity and security audits, switch Express to the Vite output,
remove the legacy HTML, and update operator and deployment documentation.
Each slice must be usable independently and must not require a flag-day rewrite.
The legacy dashboard remains available until replacement behavior is proven.
All slices now run from the React application; the migration phases above are
retained as implementation history.
## Engineering gates
@@ -108,12 +101,11 @@ The legacy dashboard remains available until replacement behavior is proven.
- No production frontend or backend code uses `any` or `console.log`.
- Mutations display the confirmed server outcome and do not rely on optimistic
success for operational controls.
- Production builds are deterministic. Serving only generated frontend assets
plus authenticated private content remains a cutover gate.
- Production builds are deterministic. The server serves only generated React
assets plus authenticated private content.
## Cutover evidence
Before deleting `public/index.html`, record evidence for every legacy capability,
all API and SSE authentication paths, private media access, container restart and
Cutover verification covers API and SSE authentication, private media access,
SSE recovery, responsive navigation, frontend type-check/build, backend build,
the complete Vitest suite, and the critical Playwright journeys.
the complete Vitest suite, and browser smoke journeys.