Table of Contents
- Sprint 1 Plan — "Spark" (Part 4/4)
- 7. Implementation Order
- 8. Acceptance Criteria → Workstream Mapping
- 9. Open Questions (Sprint-1-Specific)
- 10. Definition of Done
- 10.1 Code & build
- 10.2 Functional (verified manually on TrueNAS deploy)
- 10.3 Testplan
- 10.4 Operations
- 10.5 Documentation
- 11. What Ships at End of Sprint 1
- 12. Risk Re-check Against Plan
- 13. Cross-references
Sprint 1 Plan — "Spark" (Part 4/4)
Final chunk. Implementation order, acceptance mapping, open-question cross-references, Definition of Done, and what actually ships at the end of Sprint 1.
Previous chunks:
- Sprint-1-Plan — Background, architecture, repo layout, W0 skeleton, W1 plate-auth wire-up
- Sprint-1-Plan-Part-2 — W2 domain, W3 API
- Sprint-1-Plan-Part-3 — W4 frontend, W5 seed data, W6 deploy + CI/CD
7. Implementation Order
The 7 workstreams are not all sequential. There is one hard prerequisite chain and one parallelisable pair.
7.1 Dependency graph
W0 Skeleton
│
▼
W1 plate-auth wire-up
│
├──────────────┐
▼ ▼
W2 Domain W3 API (depends on W2 entity + W1 @CurrentUser)
│ │
└──────┬───────┘
▼
W4 Frontend
│
▼
W5 Seed data (dev-only, can run in parallel with W4 once W2 is done)
│
▼
W6 Deploy + CI/CD
7.2 Recommended sequence
| Order | Workstream | Why this position |
|---|---|---|
| 1 | W0 Skeleton | Nothing builds without the repo + Maven + pnpm scaffolding. |
| 2 | W1 plate-auth wire-up | Until plate-auth is wired, @CurrentUser does not exist → W3 can't compile. |
| 3 | W2 Domain | Ideas table + entity + OnboardingHook impl. Unblocks both W3 and W4 (the API contract). |
| 4a | W3 API | Can start as soon as Idea and IdeaService exist. |
| 4b | W5 Seed (dev) | R__dev_seed_ideas.sql only needs the ideas table to exist. Can run in parallel with W3. |
| 5 | W4 Frontend | Needs W3 endpoints alive (at least /api/ideas GET returning []). |
| 6 | W6 Deploy + CI/CD | Last because it requires real images of W3 + W4 to ship. |
7.3 Daily-granular sketch (informal)
Reality check: Sprint 1 has no day-count contract. This is a rough shape, not a commitment.
| Phase | Focus | Outcome |
|---|---|---|
| Phase 1 | W0 + W1 | mvn -pl backend test green. Frontend builds. /login page renders. Backend boots with plate-auth auto-config. |
| Phase 2 | W2 + start W3 | Flyway migration creates spark_org + ideas. Onboarding hook registered. GET /api/ideas returns [] for authenticated user. |
| Phase 3 | Finish W3 + start W4 | POST /api/ideas works in Postman/curl with a real Bearer JWT. /ideas page renders empty list. |
| Phase 4 | W4 | /ideas/new form submits → backend persists → list refreshes. End-to-end happy path works in docker-compose up. |
| Phase 5 | W5 + start W6 | Dev seed loads 5 demo ideas locally. Backend Dockerfile builds. Frontend Dockerfile builds. |
| Phase 6 | W6 | TrueNAS deploy via Gitea Actions. https://sparkboard.plate-software.de/login reachable from public internet. PWA installable. |
8. Acceptance Criteria → Workstream Mapping
Each acceptance criterion from Sprint-1-Assessment §7 maps to one or more workstreams. If a workstream is incomplete, the linked acceptance criteria cannot pass.
| # | Acceptance | Workstreams | Verification |
|---|---|---|---|
| A1 | Allowlisted user can sign in via Google and reach /ideas |
W1 + W4 + W6 | Manual: load https://sparkboard.plate-software.de, click "Sign in with Google", land on /ideas. |
| A2 | Non-allowlisted user is rejected with a clear error | W1 | Manual: sign in with a non-allowlisted Google account → plate-auth rejects → error page or /login?error=access_denied. |
| A3 | Membership auto-created for new allowlisted user (no manual step) | W2 (SparkboardOnboardingHook) |
DB inspection: after first login, memberships table contains (user_id, 'SPARK_ORG', '00000000-0000-0000-0000-000000000001', 'MEMBER'|'ADMIN') row. |
| A4 | Authenticated user can create + list ideas | W2 + W3 + W4 | E2E: log in → /ideas/new → submit → idea appears on /ideas. |
| A5 | App is installable as PWA on iOS and Android | W4 (manifest + sw.js) | Manual on iPhone + Android: "Add to Home Screen" → standalone window with Sparkboard icon. |
| A6 | App is deployed to TrueNAS via Gitea Actions on push to main |
W6 | Watch .gitea/workflows/deploy.yml succeed; smoke-test.sh passes against https://sparkboard.plate-software.de. |
8.1 Coverage matrix (workstream → acceptance)
| Workstream | A1 | A2 | A3 | A4 | A5 | A6 |
|---|---|---|---|---|---|---|
| W0 Skeleton | — | — | — | — | — | — |
| W1 plate-auth wire-up | ✅ | ✅ | — | — | — | — |
| W2 Domain | — | — | ✅ | ✅ | — | — |
| W3 API | — | — | — | ✅ | — | — |
| W4 Frontend | ✅ | — | — | ✅ | ✅ | — |
| W5 Seed (dev) | — | — | — | — | — | — |
| W6 Deploy | ✅ | — | — | — | — | ✅ |
Gap check: W0 and W5 are not on the acceptance hook directly. W0 is infrastructure (without it, nothing else exists). W5 is dev productivity (no production value but speeds up manual testing on Patrick's laptop). Both stay in scope.
9. Open Questions (Sprint-1-Specific)
All Sprint-1-blocking questions have been decided 2026-06-24. The full list of Sparkboard open questions lives in Open-Questions — this section only logs the Sprint 1 decisions.
| ID | Question | Sprint 1 Impact | ✅ Decision (2026-06-24) |
|---|---|---|---|
| Q01 | Single-org name + ID strategy | High — affects W2 SQL + IdeaController.FAMILY_SPARK_ID constant. |
Option A. Hardcode FAMILY_SPARK_ID = UUID.fromString("00000000-0000-0000-0000-000000000001") as a public static final on SparkboardOnboardingHook. |
| Q02 | Allowlist management | Medium — affects W1 config shape and W6 deploy story. | Option A. plate.auth.allowlist[] in application.yml. YAML edit + Gitea Actions deploy. Admin UI deferred to Sprint 4. |
| Q03 | Admin promotion model | Medium — affects W2 (SparkboardOnboardingHook logic). |
Option A. sparkboard.admins[] YAML list (bound by SparkboardAdminProperties). onFirstSignIn(user) reads it and writes ADMIN vs MEMBER. Initial seed (placeholders — replace before first deploy): <patrick@email>, <friend@email>, <kid1@email>, <kid2@email>. |
| Q07 | PWA assets pipeline | Low — affects W4 + manifest. | Option A. Hand-craft 192×192 + 512×512 PNGs in frontend/public/icons/. No build-time generator in Sprint 1. |
Non-blocking but worth noting: Q04 (idea status workflow), Q05 (reaction model), Q06 (security customisation), Q08 (mobile PWA vs native), Q09 (real-time updates), Q10 (notifications) are all Sprint 2+. They do not affect Sprint 1's surface.
10. Definition of Done
Sprint 1 is done when all of these are true simultaneously:
10.1 Code & build
mvn -pl backend testexits 0 on Patrick's laptop and in CI.pnpm --filter frontend buildexits 0 on Patrick's laptop and in CI.docker compose upboots all 3 services (postgres + backend + frontend); backend logs show "Flyway migrations applied" for bothflyway_schema_historyandflyway_schema_history_auth.- No
TODOmarkers blocking Sprint 1 acceptance in committed code (TODOs for Sprint 2+ are fine).
10.2 Functional (verified manually on TrueNAS deploy)
- A1 — Patrick can sign in via Google → lands on
/ideas. - A2 — A non-allowlisted Gmail rejection produces a visible error (not a 500).
- A3 — DB inspection:
membershipsrow for Patrick's user exists after first login. - A4 — Patrick creates an idea via
/ideas/new→ it appears on/ideasafter redirect. - A5 — "Add to Home Screen" on iPhone Safari creates a standalone-mode Sparkboard icon.
- A6 — A commit to
maintriggers.gitea/workflows/deploy.yml, which succeeds and runssmoke-test.shagainsthttps://sparkboard.plate-software.de.
10.3 Testplan
- All test cases in Sprint-1-Testplan marked ✅ Passed, ⏭️ Skipped (with reason), or ❌ Failed (with linked follow-up ticket).
- No ❌ Failed test blocks an acceptance criterion.
10.4 Operations
https://sparkboard.plate-software.deresolves and serves the Next.js app.- frps tunnel on port
30011is alive and stable for ≥1 hour of uptime. - Caddy correctly routes
/api/*to backend and everything else to frontend. - Backend uses production secrets from environment variables (not literal
application.ymlvalues). - Postgres data survives
docker compose down && docker compose up(named volume mounted).
10.5 Documentation
- Sprint-1-Testplan is updated with actual results.
- Open-Questions reflects any decisions made during Sprint 1.
README.mdinsparkboard/repo root has local-dev instructions that work on a clean checkout.
11. What Ships at End of Sprint 1
The deliverable, in plain English:
Patrick (or one of the 4 humans on the allowlist) opens
https://sparkboard.plate-software.deon a phone or laptop, signs in with their Google account, lands on a list of ideas the family has captured. They tap "New idea", type a title and optional body, hit submit, and see their idea on the list. They can install the app to their home screen on iOS or Android. Anyone not on the allowlist gets a clear rejection. The whole thing was deployed bygit push origin main.
11.1 What ships (concrete)
| Component | Status at end of S1 |
|---|---|
sparkboard.plate-software.de |
Live, HTTPS via IONOS + frp + Caddy, port 30011 |
| Google sign-in (allowlisted) | Works for 4 humans on allowlist |
/ideas (list page) |
Server-rendered list, newest first |
/ideas/new (create form) |
Title + body → POST → redirect to /ideas |
| PWA manifest + service worker | Installable; no offline caching yet |
| Single org auto-membership | Every first login creates a (SPARK_ORG, '00...01', MEMBER|ADMIN) row |
| plate-auth v0.1.0 dependency | Pulled from Gitea Maven + npm registries |
| Gitea Actions deploy | Push to main → SSH to TrueNAS → docker compose pull && docker compose up -d → smoke test |
| Test suite | Backend mvn test green, frontend pnpm test green, E2E smoke green |
11.2 What does NOT ship in S1 (intentional deferrals)
| Deferred | Lands in | Why |
|---|---|---|
| Edit / delete idea | Sprint 2 (Kindling) | Read + create is the walking-skeleton minimum |
| Idea detail page | Sprint 2 (Kindling) | List view is enough to prove the model works |
| Reactions, comments | Sprint 2/3 (Kindling/Flame) | Single-feature focus; conversation later |
| Status workflow (RAW → BUILDING → SHIPPED) | Sprint 2 (Kindling) | Field exists on entity with default RAW, but no UI to change it |
| Notifications | Sprint 4 (Ember) | Requires push infra; not v1-critical |
| Offline mode / IndexedDB cache | Sprint 4 (Ember) | sw.js stub-only in S1 (R8 mitigation) |
| Native APK via Capacitor | Sprint 5 (Wildfire) | PWA-first; native only if PWA falls short |
| Admin UI for allowlist | Sprint 4 (Ember) | YAML + redeploy is fine for 4 humans |
| Per-user analytics, audit log | Phoenix (optional) | Not v1-critical |
| Multi-org support | Never (Sparkboard scope) | Sparkboard defines single-org. If multi-org is ever needed it becomes a different app. |
12. Risk Re-check Against Plan
Cross-reference of Sprint-1-Assessment §4 risks with the workstream that owns each mitigation:
| Risk | Owner | Mitigation in plan |
|---|---|---|
| R1 plate-auth incomplete on Sprint 1 start | W0/W1 | Sprint 1 blocked until plate-auth v0.1.0 shipped — gating is explicit. |
| R2 plate-auth API changes mid-sprint | W1 | Pin to v0.1.0 in pom.xml + package.json; refuse to bump mid-sprint. |
| R3 Spring Boot 4.1.0 guinea-pig issues | W0 | Accept; document workarounds in README.md as found. |
| R4 Google OAuth setup friction | W1 | Use plate-auth's existing OAuth config; reuse the InspectFlow Google Cloud project credentials. |
| R5 frp instability on port 30011 | W6 | Reuse existing frpc.toml pattern from InspectFlow (port 30009); same proven setup. |
| R6 IONOS reverse proxy quirks | W6 | Reuse existing pattern from inspectflow.plate-software.de. |
| R7 Flyway migration collision (two histories) | W2 | Distinct table names (flyway_schema_history vs flyway_schema_history_auth) configured in plate-auth's auto-config; no cross-history FKs. |
| R8 PWA install rejection | W4 | Hand-crafted icons; valid manifest; sw.js stub registers cleanly (no caching logic to break). |
| R9 Single-org assumption leaks into multi-org pattern | W2/W3 | FAMILY_SPARK_ID as one constant in one place. One-line refactor to read from user context when needed. |
| R10 Polymorphic FK ergonomics | W2 | Tolerated; index on (org_type, org_id) for query perf; documented. |
| R11 OnboardingHook race condition | W2 | MembershipService.upsert is idempotent; hook can run safely on every login. |
All risks have a workstream and a concrete mitigation.
13. Cross-references
- Sprint-1-Plan — chunk 1 (W0, W1)
- Sprint-1-Plan-Part-2 — chunk 2 (W2, W3)
- Sprint-1-Plan-Part-3 — chunk 3 (W4, W5, W6)
- Sprint-1-Assessment — risks, options, A1–A6
- Sprint-1-Testplan — test cases mapped to A1–A6
- Architecture — system diagrams, SPI seam
- Integration-Guide — Sparkboard's plate-auth wire-up walkthrough
- Open-Questions — full Q01–Q10 with leanings
- Roadmap — what comes after Sprint 1
End of Sprint 1 Plan. Status: Draft v1, awaiting GO from Patrick.