From dd5a1b22fdfebbced0206be7632770402a6707cf Mon Sep 17 00:00:00 2001 From: Claude Date: Sun, 5 Apr 2026 18:49:37 +0000 Subject: [PATCH] =?UTF-8?q?docs(01-01):=20complete=20backend=20scaffold=20?= =?UTF-8?q?plan=20=E2=80=94=20SUMMARY,=20STATE,=20ROADMAP,=20REQUIREMENTS?= =?UTF-8?q?=20updated?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Created 01-01-SUMMARY.md with full accomplishment record - STATE.md: advanced to plan 2/3, progress 33%, added 3 key decisions - ROADMAP.md: Phase 1 updated to 1/3 summaries (In Progress) - REQUIREMENTS.md: marked INF-01, INF-02, DEV-01, DEV-02, SHW-01, SHW-02 complete --- .planning/REQUIREMENTS.md | 12 +- .planning/ROADMAP.md | 4 +- .planning/STATE.md | 36 +++- .../phases/01-foundation/01-01-SUMMARY.md | 177 ++++++++++++++++++ 4 files changed, 214 insertions(+), 15 deletions(-) create mode 100644 .planning/phases/01-foundation/01-01-SUMMARY.md diff --git a/.planning/REQUIREMENTS.md b/.planning/REQUIREMENTS.md index 332fb04..3277174 100644 --- a/.planning/REQUIREMENTS.md +++ b/.planning/REQUIREMENTS.md @@ -17,8 +17,8 @@ ### Device Registry -- [ ] **DEV-01**: Register a device with: name, strip type (SK6812 / WS2801 / generic), LED count, target IP, target port -- [ ] **DEV-02**: Devices persist across sessions (stored in config file) +- [x] **DEV-01**: Register a device with: name, strip type (SK6812 / WS2801 / generic), LED count, target IP, target port +- [x] **DEV-02**: Devices persist across sessions (stored in config file) - [ ] **DEV-03**: Device list shown in UI — enable/disable per show ### Animation Library @@ -41,8 +41,8 @@ ### Show Engine -- [ ] **SHW-01**: Show files saved and loaded as JSON (schema_version field required in v1) -- [ ] **SHW-02**: Show file includes: audio path/URL, device registry snapshot, all animation blocks with timestamps, beat analysis data +- [x] **SHW-01**: Show files saved and loaded as JSON (schema_version field required in v1) +- [x] **SHW-02**: Show file includes: audio path/URL, device registry snapshot, all animation blocks with timestamps, beat analysis data - [ ] **SHW-03**: Live show execution — follow MPV position, dispatch animation commands to devices via UDP at correct timestamps ### UDP Communication @@ -67,8 +67,8 @@ ### Infrastructure -- [ ] **INF-01**: Python 3.11 backend (FastAPI + uvicorn) -- [ ] **INF-02**: Modular device abstraction — adding a new strip type requires only a new device class, no changes to core engine +- [x] **INF-01**: Python 3.11 backend (FastAPI + uvicorn) +- [x] **INF-02**: Modular device abstraction — adding a new strip type requires only a new device class, no changes to core engine - [ ] **INF-03**: Windows 11 timer resolution fix applied at startup (`timeBeginPeriod(1)` via ctypes) --- diff --git a/.planning/ROADMAP.md b/.planning/ROADMAP.md index b185545..3121761 100644 --- a/.planning/ROADMAP.md +++ b/.planning/ROADMAP.md @@ -35,7 +35,7 @@ Decimal phases appear between their surrounding integers in numeric order. **Plans**: 3 plans Plans: -- [ ] 01-01: Backend scaffold — FastAPI app, Pydantic show/device models, show store (JSON load/save), device registry +- [x] 01-01: Backend scaffold — FastAPI app, Pydantic show/device models, show store (JSON load/save), device registry - [ ] 01-02: Frontend shell — HTML/CSS terminal aesthetic, WebSocket client stub, device panel, show panel - [ ] 01-03: REST API — CRUD endpoints for devices and shows, static file serving, integration smoke test **UI hint**: yes @@ -151,7 +151,7 @@ Phases execute in numeric order: 1 → 2 → 3 → 4 → 5 → 6 → 7 | Phase | Plans Complete | Status | Completed | |-------|----------------|--------|-----------| -| 1. Foundation | 0/3 | Not started | - | +| 1. Foundation | 1/3 | In Progress| | | 2. Audio Engine | 0/3 | Not started | - | | 3. Communication Protocol | 0/3 | Not started | - | | 4. Timeline Editor | 0/4 | Not started | - | diff --git a/.planning/STATE.md b/.planning/STATE.md index 3baedc9..4c5a41e 100644 --- a/.planning/STATE.md +++ b/.planning/STATE.md @@ -1,3 +1,19 @@ +--- +gsd_state_version: 1.0 +milestone: v1.0 +milestone_name: milestone +status: executing +stopped_at: Completed 01-foundation/01-01-PLAN.md +last_updated: "2026-04-05T18:49:18.330Z" +last_activity: 2026-04-05 +progress: + total_phases: 7 + completed_phases: 0 + total_plans: 3 + completed_plans: 1 + percent: 0 +--- + # Project State ## Project Reference @@ -5,20 +21,21 @@ See: .planning/PROJECT.md (updated 2026-04-05) **Core value:** Load a song, build a synchronized light show, play it back live — with precise control over every effect on every device. -**Current focus:** Phase 1 — Foundation +**Current focus:** Phase 01 — foundation ## Current Position -Phase: 1 of 7 (Foundation) -Plan: 0 of 3 in current phase -Status: Ready to plan -Last activity: 2026-04-05 — Roadmap and state initialized +Phase: 01 (foundation) — EXECUTING +Plan: 2 of 3 +Status: Ready to execute +Last activity: 2026-04-05 Progress: [░░░░░░░░░░] 0% ## Performance Metrics **Velocity:** + - Total plans completed: 0 - Average duration: — - Total execution time: 0 hours @@ -30,10 +47,12 @@ Progress: [░░░░░░░░░░] 0% | - | - | - | - | **Recent Trend:** + - Last 5 plans: — - Trend: — *Updated after each plan completion* +| Phase 01-foundation P01 | 4 | 2 tasks | 23 files | ## Accumulated Context @@ -46,6 +65,9 @@ Recent decisions affecting current work: - Init: python-mpv-jsonipc preferred over ctypes binding — no libmpv.dll dependency on Windows - Init: Firmware deferred to Phase 7 — protocol must be validated against simulator first - Init: undo/redo built in Phase 4 — retrofitting command pattern is expensive +- [Phase 01-foundation]: Module-level state in main.py for registry/show_store — acceptable for Phase 1, Phase 2 migrates to Depends() +- [Phase 01-foundation]: StaticFiles mounted last in create_app() — prevents catch-all interception of /api/* routes +- [Phase 01-foundation]: encode_animation_cmd stubs return b'' — Phase 3 implements real UDP animation command encoding ### Pending Todos @@ -59,8 +81,8 @@ None yet. ## Session Continuity -Last session: 2026-04-05 -Stopped at: Roadmap created, STATE.md initialized +Last session: 2026-04-05T18:49:18.325Z +Stopped at: Completed 01-foundation/01-01-PLAN.md Resume file: None Next action: `/gsd:plan-phase 1` diff --git a/.planning/phases/01-foundation/01-01-SUMMARY.md b/.planning/phases/01-foundation/01-01-SUMMARY.md new file mode 100644 index 0000000..ba245ed --- /dev/null +++ b/.planning/phases/01-foundation/01-01-SUMMARY.md @@ -0,0 +1,177 @@ +--- +phase: 01-foundation +plan: 01 +subsystem: backend +tags: [python, fastapi, pydantic, uvicorn, websocket, nginx, terminal-ui] + +# Dependency graph +requires: [] +provides: + - "Python package lightsync/ with all backend modules" + - "Pydantic v2 DeviceConfig and ShowModel with full schema" + - "BaseDevice ABC + SK6812/WS2801 concrete implementations" + - "DeviceRegistry with JSON persistence (devices.json)" + - "ShowStore with JSON save/load (shows/ directory)" + - "FastAPI app with lifespan, REST stubs, WebSocket stub" + - "Terminal-aesthetic frontend shell (DAW skeleton)" + - "python -m lightsync entry point serving on port 8000" +affects: [phase-01-02, phase-02, phase-03, phase-04, phase-05, phase-06, phase-07] + +# Tech tracking +tech-stack: + added: + - "FastAPI 0.115+ — web framework, REST, WebSocket, StaticFiles" + - "uvicorn[standard] 0.34+ — ASGI server with WebSocket support" + - "Pydantic v2 — model validation and JSON serialization" + - "aiofiles 24+ — async file I/O for show JSON and device registry" + - "python-dotenv — HOST/PORT config from .env file" + - "structlog — structured logging" + - "hatchling — build backend for pyproject.toml" + patterns: + - "lifespan context manager for startup/shutdown (replaces deprecated @app.on_event)" + - "Module-level registry/show_store refs in main.py — accessed via `import lightsync.main as state`" + - "StaticFiles LAST — API routes registered before mount to prevent catch-all interception" + - "Pydantic v2 APIs: model_dump_json(), model_validate_json(), model_validate() — never v1 .json()/.parse_obj()" + - "BaseDevice ABC + _DEVICE_CLASSES dict — adding new strip type = new file + one dict entry (INF-02)" + - "pathlib.Path throughout — cross-platform safe file paths" + - "aiofiles for all file I/O in async contexts — non-blocking" + +key-files: + created: + - pyproject.toml + - .env + - .gitignore + - lightsync/__init__.py + - lightsync/__main__.py + - lightsync/main.py + - lightsync/models/__init__.py + - lightsync/models/device.py + - lightsync/models/show.py + - lightsync/devices/__init__.py + - lightsync/devices/base.py + - lightsync/devices/sk6812.py + - lightsync/devices/ws2801.py + - lightsync/devices/registry.py + - lightsync/store/__init__.py + - lightsync/store/show_store.py + - lightsync/api/__init__.py + - lightsync/api/devices.py + - lightsync/api/shows.py + - lightsync/api/ws.py + - lightsync/frontend/index.html + - lightsync/frontend/style.css + - lightsync/frontend/app.js + modified: [] + +key-decisions: + - "aiofiles for all JSON file I/O — keeps async handlers non-blocking per research guidance" + - "Module-level state in main.py for registry/show_store — acceptable for Phase 1, Phase 2 migrates to Depends()" + - "StaticFiles mounted last — required to prevent catch-all interception of /api/* routes" + - "encode_animation_cmd stubs return b'' — Phase 3 implements real UDP animation command encoding" + - ".gitignore excludes devices.json and shows/ — these are runtime data, not source" + +patterns-established: + - "lifespan context manager for app startup/shutdown" + - "BaseDevice ABC + _DEVICE_CLASSES registry dict for extensible device type system" + - "Pydantic v2 serialization patterns (model_dump_json, model_validate_json)" + - "aiofiles for async file I/O in FastAPI route handlers" + - "CSS custom properties for terminal aesthetic — all colors via :root vars" + +requirements-completed: + - INF-01 + - INF-02 + - DEV-01 + - DEV-02 + - SHW-01 + - SHW-02 + +# Metrics +duration: 4min +completed: 2026-04-05 +--- + +# Phase 1 Plan 01: Backend Scaffold Summary + +**FastAPI backend scaffold with Pydantic v2 models, device ABC, JSON persistence stores, REST+WebSocket stubs, and terminal-aesthetic DAW skeleton frontend — all runnable via `python -m lightsync`** + +## Performance + +- **Duration:** ~4 min +- **Started:** 2026-04-05T18:43:46Z +- **Completed:** 2026-04-05T18:48:03Z +- **Tasks:** 2 (both auto) +- **Files created:** 23 + +## Accomplishments + +### Task 1: Package structure, Pydantic models, device abstractions (commit: 061edfc) + +- `pyproject.toml` with all Phase 1 dependencies (FastAPI, uvicorn, Pydantic v2, aiofiles, structlog) +- `lightsync/models/device.py` — `DeviceConfig` Pydantic model with `StripType` literal, UUID auto-ID, validation constraints +- `lightsync/models/show.py` — `ShowModel` with `schema_version=1`, `AudioRef`, `TrackModel`, `CueModel`, `AnalysisBlock` +- `lightsync/devices/base.py` — `BaseDevice` ABC with `encode_frame`, `encode_animation_cmd`, `bytes_per_pixel` +- `lightsync/devices/sk6812.py` — SK6812 RGBW (4 bytes/pixel), encode_frame builds RGBW bytearray +- `lightsync/devices/ws2801.py` — WS2801 RGB (3 bytes/pixel), encode_frame builds RGB bytearray + +### Task 2: Registry, show store, FastAPI app, frontend shell (commit: 5e10272) + +- `lightsync/devices/registry.py` — `DeviceRegistry` with `_DEVICE_CLASSES` dict, load/save (aiofiles), add/remove/get/list_all/instantiate +- `lightsync/store/show_store.py` — `ShowStore` with async save/load, `list_ids()` via glob +- `lightsync/main.py` — `create_app()` with lifespan hook, API routes registered before `StaticFiles` mount +- `lightsync/api/devices.py` — `GET /`, `POST /`, `DELETE /{id}` — full CRUD with save-on-write +- `lightsync/api/shows.py` — `GET /`, `POST /`, `GET /{id}` — create and retrieve shows +- `lightsync/api/ws.py` — `ConnectionManager` + `/ws` WebSocket endpoint with ack echo +- `lightsync/frontend/index.html` — DAW skeleton: header, sidebar (DEVICES + ANIMATIONS), TIMELINE main area, TRANSPORT footer +- `lightsync/frontend/style.css` — Terminal aesthetic: `#0a0a0a` bg, `#00ffff` cyan accent, `border-radius: 0` everywhere, CSS Grid layout +- `lightsync/frontend/app.js` — `LightSyncClient` WS with reconnect, `loadDevices()` populating device list +- `.gitignore` — excludes runtime data (`devices.json`, `shows/`), `.venv/`, `__pycache__/` + +## Verification Results + +All verification checks passed: +- `pip install -e ".[dev]"` — installs successfully +- `python -c "from lightsync.models.show import ShowModel; s = ShowModel(name='test'); assert s.schema_version == 1"` — passes +- `python -c "from lightsync.devices.registry import DeviceRegistry; print('OK')"` — passes +- `python -m lightsync` — starts server on port 8000, serves `GET /api/devices/` → 200 `[]` + +## Task Commits + +| Task | Commit | Description | +|------|--------|-------------| +| 1 | 061edfc | Package structure, Pydantic models, device abstractions | +| 2 | 5e10272 | Registry, show store, FastAPI app, frontend shell | + +## Decisions Made + +- Module-level `registry` and `show_store` refs in `main.py` — acceptable for Phase 1 single-process server; Phase 2 should migrate to `Depends()` for testability +- `encode_animation_cmd` stubs in SK6812/WS2801 return `b""` — Phase 3 implements real UDP frame encoding +- Google Fonts (JetBrains Mono) loaded from CDN — offline fallback to Consolas via CSS custom property chain + +## Deviations from Plan + +None — plan executed exactly as written. + +## Known Stubs + +These are intentional per-plan stubs, documented in the plan spec: + +| Stub | File | Line | Reason | +|------|------|------|--------| +| `encode_animation_cmd` returns `b""` | lightsync/devices/sk6812.py | 28 | Phase 3 implements real UDP animation command encoding | +| `encode_animation_cmd` returns `b""` | lightsync/devices/ws2801.py | 26 | Phase 3 implements real UDP animation command encoding | +| ANIMATIONS panel placeholder | lightsync/frontend/index.html | — | Phase 3+ per design decision D-08 | +| TIMELINE panel placeholder | lightsync/frontend/index.html | — | Phase 2+ per design decision D-09 | +| TRANSPORT bar placeholder | lightsync/frontend/index.html | — | Phase 2+ per design decision D-10 | + +All stubs are DAW skeleton placeholders (per D-06 decision: full panel layout from day 1) or device encoding stubs for UDP (Phase 3). They do not prevent the plan's goal from being achieved — the backend scaffold, persistence, and server entry point are fully functional. + +## Next Phase Readiness + +- Ready for 01-02: frontend UI details and static file serving verification +- Ready for 01-03: Docker deploy to groll.cloud +- All future phases can import from `lightsync.models`, `lightsync.devices`, `lightsync.store` +- `_DEVICE_CLASSES` dict ready to receive new strip types in Phase 5 + +--- +*Phase: 01-foundation* +*Completed: 2026-04-05*