# Wave 1 Implementation Plan (plan 3) > **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking. **Goal:** Ship Wave 1: schema versioning + live migration, built-in album player with last-played tracking, loan tracking, rip queue, stats wall, and JSON export + SQLite backups. **Architecture:** Extends the existing Fastify/SQLite backend (server/) and React SPA (web/) without changing the frozen plan-1 API. New routes: stream/album proxy, loans, stats, export/backup. First schema migration via `app_meta.schema_version`. Player is a global context above the router so audio survives navigation. **Tech Stack:** unchanged (Fastify 5, better-sqlite3, React 19, Vite, Vitest). Spec: `docs/superpowers/specs/2026-09-03-wave1-hygiene-listening-design.md`. **Prerequisites:** main (post plan 2), 147/147 tests. Branch: `wave1-hygiene-listening`. Node >= 20. **Stamping refinement vs spec:** Subsonic's recent-list entries don't reliably carry a played timestamp. `last_played_at` is therefore stamped from two sources: (1) sync, when an album entry reports one (`played`/`playedAt` field, OpenSubsonic-style — opportunistic, null-safe), and (2) the built-in player, via `POST /api/album/:subsonicId/played` on playback start. UX is identical. --- ## File structure (plan 3) ``` server/src/ ├── db.ts # MODIFY: versioned migrate(), loans table, last_played_at ├── config.ts # MODIFY: backupsDir ├── subsonic.ts # MODIFY: getAlbum(), getRecentAlbums(), public url() ├── sync.ts # MODIFY: stamp last_played_at ├── ripstatus.ts # MODIFY: findMatchedAlbum() ├── routes/ │ ├── collectionRoutes.ts # MODIFY: detail gains matchedAlbum, onLoan filter │ ├── streamRoutes.ts # NEW: /api/stream/:songId, /api/album/:id/tracks, /api/album/:id/played │ ├── loanRoutes.ts # NEW: loans CRUD │ ├── statsRoutes.ts # NEW: /api/stats │ └── dataRoutes.ts # NEW: /api/export, /api/backup, /api/backups └── test/ (new: migrate.test.ts, loans.test.ts, stats.test.ts, data.test.ts, stream.test.ts; modified: subsonic.test.ts, sync.test.ts, collection.test.ts) web/src/ ├── types.ts # MODIFY: Track, Stats, Loan, Backups, matchedAlbum ├── api.ts # MODIFY: new methods ├── player/PlayerContext.tsx # NEW: global player state +