Table of Contents
- Sprint 1 — Assessment ("Spark")
- 1. Problem analysis
- 2. Affected components
- 3. Current state
- 4. Risk assessment
- 5. Solution options
- Option A — Walking skeleton with one read + one write (RECOMMENDED)
- Option B — Backend + frontend in isolation, no deploy
- Option C — Frontend-only mock with localStorage
- 6. Recommendation
- 7. Acceptance criteria (A1–A6)
- A1 — Allowlisted user can sign in with Google
- A2 — Non-allowlisted user is rejected with a clean error
- A3 — First login auto-creates membership in Family Spark org
- A4 — Any authenticated user can create and list ideas
- A5 — PWA installable on iOS Safari and Android Chrome
- A6 — Deployed to https://sparkboard.plate-software.de via Gitea Actions
- 8. plate-auth integration footprint (Sprint 1)
- 9. Out of scope (deferred to Sprint 2+)
- 10. Open questions
- 11. Verdict
Sprint 1 — Assessment ("Spark")
Date: Pre-Sprint 1 planning
Module: Sparkboard (greenfield)
Author: Patrick Plate / Lumen (Planner)
Status: Entwurf v1 — ready for Patrick GO
Sprint codename: Spark
Sprint goal: Walking skeleton consuming plate-auth v0.1.0, deployed to sparkboard.plate-software.de, four allowlisted users can sign in with Google and post ideas.
1. Problem analysis
Sparkboard does not exist yet. There is no codebase, no database, no deployment, no DNS, no CI pipeline. The Sprint 1 problem is therefore not "fix a bug" or "extend a feature" — it is "go from a git init to a four-human production system in one sprint."
The unique pressure on Sprint 1 is that Sparkboard must be the first real consumer of plate-auth. Every assumption plate-auth made about how its starter would be used is, by definition, validated or falsified here. If plate-auth's auto-configuration leaves a sharp edge, Sparkboard will hit it. The benefit is that we are doing this hand-in-hand with plate-auth (same developer, same wiki, same week) — defects in plate-auth's contract surface immediately and can be patched in plate-auth, not worked around in Sparkboard.
The product surface is intentionally tiny: one entity (Idea), two endpoints (GET /api/ideas, POST /api/ideas), two pages (/login, /ideas). Everything else in Sprint 1 is infrastructure: build, deploy, auth wire-up, PWA, CI/CD. The fact that the product surface is small is the strategy — it focuses Sprint 1 entirely on the integration story.
2. Affected components
Because Sparkboard is greenfield, "affected" means "created". The full v1 component inventory:
| Layer | Component | New / Library | Owner |
|---|---|---|---|
| Backend | SparkboardApplication.java |
New | Sparkboard |
| Backend | Idea entity + IdeaRepository / IdeaService / IdeaController |
New | Sparkboard |
| Backend | SparkboardOnboardingHook (OnboardingHook SPI impl) |
New | Sparkboard |
| Backend | SparkboardAdminProperties (@ConfigurationProperties("sparkboard")) |
New | Sparkboard |
| Backend | Flyway migrations: V1__init.sql (Sparkboard tables only) + V2__seed_family_spark_org.sql |
New | Sparkboard |
| Backend | de.platesoft:plate-auth-starter:0.1.0 |
Library | plate-auth |
| Backend | application.yml with plate.auth.* configuration |
New | Sparkboard |
| Frontend | auth.ts (calls createAuthConfig from @platesoft/auth/next-auth) |
New | Sparkboard |
| Frontend | app/api/auth/[...nextauth]/route.ts (NextAuth handlers re-export) |
New | Sparkboard |
| Frontend | app/api/backend/[...path]/route.ts (calls createProxyHandlers from @platesoft/auth/proxy) |
New | Sparkboard |
| Frontend | app/(app)/ideas/page.tsx (list, server component) |
New | Sparkboard |
| Frontend | app/(app)/ideas/new/page.tsx + <IdeaForm/> |
New | Sparkboard |
| Frontend | app/(auth)/login/page.tsx |
New | Sparkboard |
| Frontend | public/manifest.json + public/sw.js + icon set + lib/sw-register.ts |
New | Sparkboard |
| Frontend | @platesoft/auth@0.1.0 npm package |
Library | plate-auth |
| Infra | docker-compose.yml (local dev) + docker-compose.prod.yml (TrueNAS) |
New | Sparkboard |
| Infra | IONOS Apache vhost for sparkboard.plate-software.de |
New | Sparkboard (same template as InspectFlow/CannaManage) |
| Infra | frpc entry on TrueNAS, port 30011 |
New | Sparkboard |
| Infra | DNS: sparkboard.plate-software.de CNAME |
New | Sparkboard |
| CI | .gitea/workflows/ci.yml (build + test) |
New | Sparkboard |
| CI | .gitea/workflows/deploy.yml (SSH deploy to TrueNAS) |
New | Sparkboard |
| Docs | This wiki | New | Sparkboard |
What is deliberately not built (because plate-auth ships it):
- Any
Userentity / table / repository - Any JWT-signing or JWT-validating filter
- Any allowlist enforcement
- Any membership / invitation / access-request table or controller
- Any auth-exchange controller
- Any hand-rolled proxy that injects bearer tokens
- Any NextAuth provider config beyond
createAuthConfig({ providers: { google: { ... } } })
The size of that not built list is the integration thesis.
3. Current state
There is no current state. Sprint 1 starts from the empty Gitea repo. The closest analogues are:
- plate-auth v0.1.0 (sibling repo, expected to ship before Sprint 1 starts) — provides every auth primitive.
- InspectFlow Sprint 14 — the origin of every auth pattern that now lives in plate-auth. Sparkboard does not copy code from InspectFlow; it consumes plate-auth instead. The patterns are similar by ancestry, not by code-reuse.
- CannaManage — sibling project; provides the deployment shape (TrueNAS + frps + IONOS Apache + Caddy/Apache vhost + Gitea Actions). Sparkboard's
docker-compose.prod.yml,Caddyfile(or Apache equivalent), anddeploy.share pattern-mirrored from CannaManage.
4. Risk assessment
| # | Risk | Probability | Impact | Mitigation |
|---|---|---|---|---|
| R1 | plate-auth v0.1.0 ships incomplete or with a bug in single-org mode — Sparkboard is the first consumer, so it finds problems first | Medium | High | Sprint 1 hard-blocks until plate-auth v0.1.0 is green. Sparkboard and plate-auth share a developer (Patrick), so plate-auth bugs become same-day patches, not multi-week tickets. |
| R2 | Spring Boot 4.1 regression — Sparkboard is the SB 4.1 guinea pig in plate-software | Low | Medium | Pin to the GA release, not RC/snapshot. If a regression appears, downgrade to SB 4.0 LTS is a one-line pom.xml change. plate-auth tests against SB 4.1 in its own CI before publishing. |
| R3 | Google OAuth misconfiguration — wrong redirect URI, wrong scopes, wrong consent screen | Medium | Medium | Validate end-to-end in dev with http://localhost:3000 redirect first, then add the production redirect. Document required Google Cloud Console steps in Integration Guide §1. |
| R4 | NextAuth v5 wire-up confusion — NextAuth v5 is still relatively new and has notable differences from v4 | Medium | Medium | @platesoft/auth/next-auth is the abstraction that hides v5 specifics. As long as that factory is correct, Sparkboard never touches NextAuth v5 internals. |
| R5 | frps tunnel + IONOS Apache double-proxy breaks for the new port 30011 | Low | Medium | Pattern is already validated for InspectFlow (30009) and CannaManage (30010). Copy the working frpc.toml and Apache vhost block; only change the port and hostname. |
| R6 | TrueNAS Docker volume permissions for the Postgres data dir | Medium | Low | Postgres image runs as UID 999 by default; the TrueNAS dataset must be chowned. Document in deploy.sh. Same lesson learned twice already (InspectFlow + CannaManage). |
| R7 | Gitea Actions SSH deploy step — SSH key, known_hosts, sudo password | Medium | Medium | Reuse the CannaManage workflow (appleboy/ssh-action@v1.0.0). Test the deploy script locally before committing the workflow. |
| R8 | PWA service-worker caching the login page — users get stuck on a stale /login |
Low | High | Service worker is stub-only in v1: it registers, claims clients, but caches nothing. Caching strategy is Sprint 4 work, not Sprint 1. |
| R9 | Allowlist typo locks out one of the four users | Medium | Low | Allowlist is in application.yml env-substituted (PLATE_AUTH_ALLOWLIST_EMAILS). Add an admin override mechanism in Sprint 2; for Sprint 1, accept that a redeploy fixes typos. |
| R10 | Flyway version drift between Sparkboard's history and plate-auth's history | Low | Medium | Two separate histories (flyway_schema_history + flyway_schema_history_auth) means they cannot collide. Configured via plate-auth's plate.auth.flyway.table property. |
| R11 | The OnboardingHook fires before plate-auth has finished persisting auth_identities — race condition on first login | Low | High | plate-auth's contract is that the hook runs after auth_identities INSERT, in the same transaction. Verified by reading plate-auth's tests. Hypothesis logged in BigMind for resolution during Sprint 1 W1. |
5. Solution options
Three options for Sprint 1 scope, scored on how aggressively they prove plate-auth.
Option A — Walking skeleton with one read + one write (RECOMMENDED)
- Scope:
Ideaentity only.GET /api/ideas+POST /api/ideas. List page + create form. PWA installable. Deployed. - Plate-auth touch surface: maximum. Auth, allowlist, membership row, JWT, proxy, single-org config — all exercised.
- Pro: smallest possible product surface focuses all energy on integration.
- Pro: every Sprint 1 acceptance criterion exercises plate-auth.
- Pro: if any Sprint 1 acceptance fails, it's almost certainly an integration issue, not a product issue — easy to localise.
- Con: the visible product looks very thin after a sprint. Four users get an idea list and a "+" button and nothing else.
- Effort: 2–3 weekends after plate-auth v0.1.0 lands.
Option B — Backend + frontend in isolation, no deploy
- Scope: Build the backend and frontend, run them locally, demo locally. Skip the TrueNAS / frps / IONOS / Gitea Actions work.
- Pro: less moving parts in one sprint.
- Con: doesn't validate the most operationally risky bits (R5, R6, R7). Defers risk.
- Con: delivers nothing the four real users can touch — defeats the point of "walking" skeleton.
- Effort: 1–2 weekends.
Option C — Frontend-only mock with localStorage
- Scope: No backend. Next.js app stores ideas in localStorage. Auth is stubbed.
- Pro: trivially deployable as a static site.
- Con: doesn't validate plate-auth at all. Sparkboard's entire strategic reason for existing collapses.
- Effort: 1 weekend.
6. Recommendation
Option A — Walking skeleton.
The visible thinness of Option A is the cost, and it is the right cost. Sparkboard's strategic value is in validating plate-auth, not in shipping a four-feature product surface to four humans on weekend two. If Sprint 1 ships a real auth flow, a real membership row, a real JWT, a real proxy, and a real production deploy — and only one CRUD operation each direction — the integration thesis is proven. Sprint 2 (Kindling) adds the product features.
Option B defers the highest-risk operational work into Sprint 2, where it would compete for attention with reactions/status/comments. Bad trade.
Option C undermines the whole project. Skip.
7. Acceptance criteria (A1–A6)
These are the formal gates Sprint 1 must clear before it is "done". Each is testable; the Sprint 1 Testplan maps tests onto each.
A1 — Allowlisted user can sign in with Google
Given a Gmail account in plate.auth.allowlist.emails, when the user visits https://sparkboard.plate-software.de/login and clicks "Sign in with Google", they are redirected to Google, consent, redirected back, and land on /ideas as an authenticated session. Tested by MT-01.
A2 — Non-allowlisted user is rejected with a clean error
Given a Gmail account NOT in the allowlist, when the user attempts the same flow, they see a generic "not authorised" message and no Sparkboard user record is created in any table. Tested by MT-02, IT-03.
A3 — First login auto-creates membership in Family Spark org
Given a successful first sign-in by an allowlisted user, after the flow completes, the memberships table contains exactly one row for that user_id: (user_id, 'SPARK_ORG', FAMILY_SPARK_ID, role) where role = ADMIN if the email is in sparkboard.admins[], otherwise MEMBER. Second sign-in does not create a duplicate. Tested by UT-04, IT-01, MT-03.
A4 — Any authenticated user can create and list ideas
POST /api/ideas with { title, description? } and a valid bearer token creates an Idea row with org_id = FAMILY_SPARK_ID, author_id = <token user_id>, status = RAW, and returns the new idea. GET /api/ideas returns all ideas in the Family Spark org, newest first. Tested by UT-02, UT-03, IT-02, E2E-01.
A5 — PWA installable on iOS Safari and Android Chrome
The deployed app serves a valid manifest.json with name, short_name, start_url, display: standalone, theme_color, and at least a 192×192 and 512×512 icon. The "Add to Home Screen" affordance appears on iOS Safari and Android Chrome. Once installed, the app launches in standalone mode without the browser chrome. Tested by E2E-03, MT-04, MT-05.
A6 — Deployed to https://sparkboard.plate-software.de via Gitea Actions
A merge to main triggers Gitea Actions, which builds backend and frontend images, pushes to the Gitea container registry, SSH-deploys to TrueNAS, the new containers come up healthy, and the smoke test (/api/health returns 200, /login returns 200) passes. The whole pipeline is < 10 minutes wall-clock. Tested by MT-06, MT-07.
8. plate-auth integration footprint (Sprint 1)
What Sparkboard touches in plate-auth's surface. If any of these contracts changes in v0.2, Sparkboard knows where to look:
| plate-auth surface | Sparkboard usage |
|---|---|
de.platesoft:plate-auth-starter Maven artifact |
Declared in backend/pom.xml |
plate.auth.jwt.secret config |
Set from env var PLATE_AUTH_JWT_SECRET |
plate.auth.exchange.secret config |
Set from env var PLATE_AUTH_EXCHANGE_SECRET |
plate.auth.allowlist.emails config |
List of 4 emails, env-substituted |
plate.auth.providers.google.{client-id, client-secret} config |
Env-substituted |
plate.auth.registration.enabled = false |
Explicit |
OnboardingHook SPI |
Implemented by SparkboardOnboardingHook |
MembershipService.upsert(userId, orgType, orgId, role) API |
Called from the hook |
Role enum (ADMIN, MEMBER) |
Used by the hook |
@platesoft/auth npm artifact |
Declared in frontend/package.json |
createAuthConfig(...) factory |
Called from frontend/auth.ts |
createProxyHandlers(...) factory |
Called from frontend/app/api/backend/[...path]/route.ts |
flyway_schema_history_auth table |
Owned by plate-auth; Sparkboard's Flyway never touches it |
Untouched in v1 (deliberately deferred or unneeded):
OrgValidatorSPI (default no-op accepted)OrgDisplayNameResolverSPI (defaultorg_idrendering accepted)InvitationMailerSPI (no invitations in v1)AccessRequestMailerSPI (no access requests in v1)- React hooks from
@platesoft/auth/react(Sprint 2 candidate if needed for profile page) /api/auth/invite//api/auth/access-requestsHTTP endpoints (not called)
9. Out of scope (deferred to Sprint 2+)
| Item | Sprint |
|---|---|
| Reactions (💡⚡🔥❓👀) | 2 (Kindling) |
| Status transitions in UI | 2 |
| Idea archive / soft-delete UI | 2 |
| Idea edit | 2 |
| Idea detail page | 2 |
| Profile / account-settings page | 2 |
| Comments | 3 (Flame) |
| Search | 3 |
| Notifications (email / web-push) | 4 (Ember) |
| Offline cache (real SW caching) | 4 |
| Native APK (Capacitor) | 5 (Wildfire) |
| Image attachments | 5 |
10. Open questions
Cross-referenced to Open Questions. The four that must be answered before Sprint 1 implementation starts:
- Q01 — Single-org name and ID strategy — what is the magic UUID? "Family Spark" the display name?
- Q02 — Allowlist management — env var? config file? DB seed? admin endpoint?
- Q03 — Admin promotion model — auto on first login? Flyway seed?
sparkboard.admins[]config? - Q07 — PWA assets pipeline — hand-drawn icons? generator? defer to Sprint 2?
The other six on the Open Questions page affect Sprint 2+ and do not block Sprint 1.
11. Verdict
Recommendation: APPROVE Option A, A1–A6 acceptance, with Q01–Q03 and Q07 answered before W2 of Sprint 1 starts.
Next document: Sprint 1 — Plan breaks the recommendation into workstreams W0–W6.