Files
MobilityOps/PROJECT_STATE.md
T
NuklearRabbit 03c5b60235 M1: implement operational core
Demo auth, seed import/reset, dashboard, vehicle/booking list+detail, audit trail. Backend: 19 tests passing, ruff clean. Frontend: React Router shell, typed API client, responsive pages. Verified end-to-end via curl and browser.
2026-08-01 21:20:53 +02:00

8.5 KiB

Project state

Current milestone

M1 — complete. Starting M2 next.

Locked decisions

  • Product name: MobilityOps.
  • Fictitious tenant: Northstar Mobility Demo.
  • PoC only; all operational and knowledge data are synthetic.
  • Core stack and boundaries are defined in CLAUDE.md and docs/03-architecture.md.
  • RAGcore and ITWorx MCP Hub are external central services.
  • n8n receives post-commit events through an outbox dispatcher.
  • SQLAlchemy 2 declarative models cover the full domain model (backend/app/models/); enums are plain String columns validated at the Pydantic/service layer, not native PG enums (simpler migrations).
  • backend/requirements.lock is compiled inside a python:3.12-slim container (matches the Dockerfile base image) via pip-compile --extra dev; regenerate the same way if pyproject.toml changes.
  • Frontend dependencies pinned (no more "latest"); package-lock.json committed; Docker build uses npm ci.
  • Demo auth is a lightweight HMAC-signed cookie (app/core/security.py), not a real password/JWT flow — matches "Demo role buttons create an authenticated session; they do not bypass authorization middleware." Two fixed demo users (USR-OPS operations_manager, USR-EMP rental_employee) are created by the seed loader, not from a CSV (no users.csv in seed/).
  • Seed loader (backend/app/seed_loader.py) only supports seed --reset (always rebuilds); there is no incremental/idempotent-without-reset mode, since the acceptance criteria only require deterministic reset, not partial import.
  • DataQualityIssue.entity_ref/related_ref from the CSVs are resolved to entity_type/entity_id (UUID) at load time per the domain model; the original human-readable refs are kept in evidence_json (entity_ref, related_refs) since the API and UI need them and re-resolving UUID→public_ref on every read would be wasteful.
  • backend/app/core/config.py added app_secret, session_cookie_name, session_ttl_seconds, seed_dir (/app/seed in-container), cors_allow_origins (comma-separated string, not a list — simpler with pydantic-settings env parsing), demo_today (drives the dashboard's "Today" section against the deterministic anchor date, default 2026-08-01).
  • compose.yaml api build context changed from ./backend to repo root with dockerfile: backend/Dockerfile, so the image can COPY seed ./seed (seed CSVs are outside backend/).
  • Frontend: added react-router-dom@7.18.2 (bumped from 6.x to clear two real advisories — open redirect + arbitrary constructor injection in v6). One residual npm audit finding (RSC-mode CSRF, GHSA-qwww-vcr4-c8h2) does not apply — this SPA never uses React Router's RSC/SSR mode.
  • Nav/pages built so far: Dashboard, Vehicles (list+detail with tabs), Bookings (list+detail), Audit. Data Quality, Knowledge and Automation nav items are intentionally omitted until M3/M5/M4 build the pages behind them — CLAUDE.md forbids dead routes/placeholders.

Completed evidence

M0 — Reproducible foundation

  • Added backend/app/core/db.py (engine/session), backend/app/models/* (User, Customer, Vehicle, Booking, Inspection, MaintenanceRecord, DataQualityIssue, OutboxEvent, AuditEvent), Alembic config (backend/alembic.ini, backend/alembic/env.py) and initial migration backend/alembic/versions/c9498525abb5_initial_schema.py.
  • Commands run and verified from this checkout:
    • docker compose build api — OK
    • docker compose run --rm api alembic upgrade head — applied cleanly to empty DB, created 9 tables + alembic_version.
    • docker compose run --rm api pytest -q — 1 passed.
    • docker compose run --rm api ruff check . — All checks passed (added extend-exclude = ["alembic/versions"] to backend/pyproject.toml for autogenerated migration line length).
    • docker compose up -d --build — all 4 services healthy: curl http://localhost:8128/health{"status":"ok",...}; curl -o /dev/null -w "%{http_code}" http://localhost:1228/ → 200; curl http://localhost:5678/healthz → 200.
  • Fixed a real scaffold bug: frontend/src/App.tsx used import.meta.env without a vite/client types reference, which broke npm run build in Docker (works fine under plain vite dev because Vite injects the global at dev-time but tsc -b still type-checks it). Added frontend/src/vite-env.d.ts.
  • make is not installed in this Windows/git-bash shell — validated the underlying docker compose ... commands directly instead (Makefile targets are thin wrappers around them and are correct as written for a Linux/CI shell or WSL).
  • Known accepted gap: npm audit reports 1 moderate/1 high transitive esbuild advisory (dev-server-only, fixed only by a Vite 8 major bump); left as-is for the PoC, noted here rather than silently upgrading a major version.

M1 — Operational core

  • Backend additions: app/core/security.py (HMAC-signed session cookies), app/api/deps.py (get_current_user, require_operations_manager), app/core/errors.py (AppError + the documented {"error": {...}} shape wired as a FastAPI exception handler for both AppError and HTTPException), app/seed_loader.py, app/cli.py (python -m app.cli seed --reset), app/services/audit.py, app/schemas.py, routers under app/api/routers/ (demo, dashboard, vehicles, bookings, audit).
  • Frontend additions: React Router-based app shell (src/App.tsx, src/components/Layout.tsx, src/components/RequireAuth.tsx), AuthContext, typed api client (src/api/client.ts, src/api/types.ts), pages Login, Dashboard, Vehicles/VehicleDetail, Bookings/BookingDetail, Audit. Full responsive stylesheet (src/styles.css) covering nav collapse and table→card layout under 700px, visible focus states, no hover-only actions.
  • Commands run and verified from this checkout (container rebuilt each time to pick up code changes):
    • docker compose run --rm api pytest -q19 passed (new: test_seed.py, test_auth.py, test_dashboard.py, test_vehicles.py, test_bookings.py, test_audit.py; tests seed the real Postgres via reset_and_seed in a session fixture, then exercise the FastAPI app through TestClient, not mocks).
    • docker compose run --rm api ruff check . — All checks passed (added ignore = ["B008"] — FastAPI's Depends()-as-default is idiomatic, not a real bug).
    • npm run build (local, Node 24) — clean tsc -b && vite build.
    • docker compose up -d --build then docker compose exec api python -m app.cli seed --reset — counts: users:2 customers:180 vehicles:50 bookings:246 inspections:75 maintenance:40 data_quality_issues:15 workflow_runs:20.
    • curl end-to-end: POST /api/v1/demo/login sets cookie and returns the user; unauthenticated GET /api/v1/dashboard → 401 with the documented error shape; authenticated dashboard/vehicle-detail return real seeded data (verified metrics available:21 rented:11 cleaning:6 maintenance:5 blocked:7, matching the 50 seeded vehicles).
    • Browser smoke test (Chrome via MCP) at desktop width: login page → Operations Manager login → Dashboard (metrics + attention items + today + recent automation all populated) → Vehicle detail MO-016 (tabs render, "Needs attention" badge correct — it's DQ-DEMO-OVERLAP/DQ-DEMO-STATUS) → Booking detail BK-DEMO-RETURN (matches S1 scenario: vehicle MO-024, status active, start odometer 53610). Responsive CSS (@media max-width:700px) was written and code-reviewed but the automated resize during this session didn't visibly reflect in the captured screenshot (likely a screenshot-timing quirk of the browser tool, not necessarily a real bug) — treat the ≤360px layout as visually unverified and re-check with a real device/DevTools emulation before final acceptance (M7).
  • Known accepted gap carried over from M0: npm audit residual esbuild/Vite-8 dev-server-only advisory.

Known blockers

None. External service credentials may be absent; use the documented demo/degraded providers.

Exact next action

Start M2 (vehicle return vertical slice): read docs/08-return-workflow.md, contracts/events.schema.json. Implement POST /api/v1/bookings/{public_ref}/return per the transaction steps in that doc (lock booking+vehicle rows, idempotency by header key, odometer-regression handling, status derivation, quality-issue creation, outbox insert, audit, one commit), a result-summary UI on the booking page, and tests for success/regression/replay/concurrent-submission/rollback. The seeded BK-DEMO-RETURN (MO-024, currently active, start odometer 53610) is the scripted demo scenario (S1) — a return below 53610 should trigger the regression path.