2
Open Questions
Patrick Plate edited this page 2026-06-24 15:29:06 +02:00
This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

Open Questions

Status: Living document Owner: Patrick Last updated: 2026-06-24

This page captures Sparkboard-specific decisions that are not yet locked. Each question has a recommended leaning based on the Sprint 1 walking-skeleton constraints. Patrick has the final call; the leaning is what we'll build unless Patrick overrides.

Auth and multi-tenancy questions live in plate-auth's own docs (Sparkboard consumes those decisions, not makes them).


Question Map

ID Topic Status Blocks Sprint Decision needed by
Q01 Single-org name and ID strategy Decided 2026-06-24 — A Sprint 1 (W2) Sprint 1 kickoff
Q02 Allowlist management UX Decided 2026-06-24 — A Sprint 1 (W1) — light; Sprint 4 — heavy Sprint 1 kickoff
Q03 Admin promotion model Decided 2026-06-24 — A Sprint 1 (W2) Sprint 1 kickoff
Q04 Idea status workflow Open Sprint 2 (Kindling) Sprint 2 kickoff
Q05 Reaction model Open Sprint 2 (Kindling) Sprint 2 kickoff
Q06 Security customisation: do we need any beyond plate-auth? Open Sprint 1 (W1) — confirm "no"; Sprint 2 — re-check Sprint 1 kickoff
Q07 PWA assets pipeline (icons, splash) Decided 2026-06-24 — A Sprint 1 (W4) Sprint 1 mid-sprint
Q08 Mobile strategy: PWA-only vs native APK Open Sprint 5 (Wildfire) Sprint 4 retro
Q09 Real-time updates (live list refresh) Open Sprint 4 (Ember) Sprint 3 retro
Q10 Notifications: email, push, or none Open Sprint 4 (Ember) Sprint 3 retro

Q01 — Single-org name and ID strategy

Question: The whole of Sparkboard runs against one org. How do we identify it?

  • (A) Hardcode a magic UUID 00000000-0000-0000-0000-000000000001 everywhere.
  • (B) Look up by org_type = 'SPARK_ORG' on every request (assume only one row).
  • (C) Bind via @ConfigurationProperties("sparkboard.org.id") from application.yml.

Why it matters: This decision shows up in IdeaController (the FAMILY_SPARK_ID constant), the SparkboardOnboardingHook, the V2__seed_family_spark_org.sql migration, and any future entity that needs org_id.

Leaning: A (hardcode the all-zeros-with-trailing-1 magic UUID).

Why:

  • Sparkboard is single-org by definition. The constant is honest.
  • One value in one place (IdeaController.FAMILY_SPARK_ID = UUID.fromString("00000000-0000-0000-0000-000000000001")).
  • Trivial to refactor to option C the moment a second org appears (which is "never" for Sparkboard, but might be relevant if the pattern is lifted into a different app).
  • Option B costs a DB roundtrip per request for no value. Option C costs configuration ceremony for no value.

Decision: Decided 2026-06-24 — Option A. Hardcode FAMILY_SPARK_ID = UUID.fromString("00000000-0000-0000-0000-000000000001") as a public static final on SparkboardOnboardingHook. Used by IdeaController, the hook, and the V2__seed_family_spark_org.sql migration. Refactor to option C only when a second org appears (not in Sprint 15).


Q02 — Allowlist management UX

Question: Who can sign in is controlled by plate-auth's allowlist. How does Patrick add/remove the 4 family humans?

  • (A) Edit application.ymlplate.auth.allowlist[] → redeploy via Gitea Actions.
  • (B) Edit a DB table → no redeploy.
  • (C) Build an admin UI (form + endpoint).

Why it matters: Affects W1 config shape, Sprint 4 admin-panel scope, and how forgiving the system is when a 5th human needs adding ("guest").

Leaning: A (YAML + redeploy) for v1, B if Patrick says manual edits feel painful, C is Sprint 4+.

Why:

  • 4 humans, very low churn. Editing YAML and pushing to main triggers a deploy and is honestly fine.
  • DB-backed allowlist (B) adds an entire CRUD surface; not worth it in Sprint 1.
  • Admin UI (C) is multi-week work; explicitly scheduled in Sprint 4 (Ember) on the Roadmap.

Decision: Decided 2026-06-24 — Option A. Allowlist lives in application.yml under plate.auth.allowlist[] (bound by plate-auth's PlateAuthProperties). Adding/removing a family member is a YAML edit + Gitea Actions deploy. DB-backed allowlist (B) and admin UI (C) deferred to Sprint 4 (Ember) at the earliest.


Q03 — Admin promotion model

Question: Patrick wants to bootstrap himself (and probably the friend) as ADMIN, with the kids as MEMBER. How is that decided?

  • (A) sparkboard.admins[] list in application.yml; SparkboardOnboardingHook checks the user's email against it and writes ADMIN or MEMBER accordingly.
  • (B) Manual DB UPDATE after first login.
  • (C) First-user-is-admin convention.
  • (D) All users are ADMIN; no MEMBER role in v1.

Why it matters: Affects W2 (SparkboardOnboardingHook impl) and the bootstrap story for new family-member onboarding.

Leaning: A (sparkboard.admins[] in YAML).

Why:

  • Self-documenting (admin list is in source control).
  • No DB-edit ritual.
  • Idempotent (re-running the hook against the same user with same admin list = no diff).
  • Option D (all ADMIN) is tempting for simplicity, but Sprint 2+ will care about MEMBER vs ADMIN (e.g., admin-only delete), so introducing the distinction now costs almost nothing.

Decision: Decided 2026-06-24 — Option A. Admin list lives in application.yml under sparkboard.admins[] (bound by SparkboardAdminProperties). SparkboardOnboardingHook.onFirstSignIn(user) reads it and writes Role.ADMIN if user.email() is in the list, otherwise Role.MEMBER. Initial seed list (placeholders — replace before first deploy): <patrick@email>, <friend@email>, <kid1@email>, <kid2@email>.


Q04 — Idea status workflow

Question: In Sprint 1, the IdeaStatus enum exists with values RAW, EXPLORING, BUILDING, SHIPPED, DEAD. Default is RAW. Sprint 2 (Kindling) adds UI to change status. What's the rule?

  • (A) Free transitions: any user can move any idea from any state to any state.
  • (B) Author-only: only Idea.authorId == currentUser.id can change status.
  • (C) Admin-only.
  • (D) Stage-gate: only RAW→EXPLORING→BUILDING→SHIPPED, with DEAD reachable from any.

Leaning: A for v1 (free transitions), revisit if it gets messy.

Why:

  • 4 humans, low conflict probability. Free transitions = least code, most agency.
  • Author-only (B) prevents Patrick from cleaning up a kid's neglected idea, which is the wrong tradeoff for this user group.
  • Admin-only (C) makes the kids feel infantilised.
  • Stage-gate (D) is over-engineered for v1; revisit if data shows people skipping states or "stuck in BUILDING for a year" patterns.

Decision: Pending. Not blocking Sprint 1.


Q05 — Reaction model

Question: Sprint 2 (Kindling) introduces reactions. What does a reaction look like?

  • (A) Likes only (one-bit, per user, per idea).
  • (B) Emoji set (fixed list: 👍 ❤️ 🔥 💡 🤔).
  • (C) Custom emoji per user.
  • (D) None — skip reactions, jump to comments in Sprint 3.

Leaning: B (fixed emoji set of 46).

Why:

  • Likes only (A) is too cold for a family idea board.
  • Fixed emoji set (B) gives expressiveness without UX complexity (one row per (user, idea, emoji)).
  • Custom emoji (C) is over-engineering for 4 humans.
  • Skipping reactions (D) is plausible if comments-first feels more valuable. Decision deferred to Sprint 2 retro.

Decision: Pending. Not blocking Sprint 1.


Q06 — Security customisation: do we need any beyond plate-auth?

Question: plate-auth ships a default Spring Security config that secures everything under /api/** and exposes /api/auth/** for the auth flow. Does Sparkboard need to:

  • (A) Use plate-auth's defaults as-is.
  • (B) Customise the SecurityFilterChain (e.g., add CORS rules, custom headers, rate limiting).
  • (C) Replace plate-auth's security config entirely.

Why it matters: If C is the answer, plate-auth's promise of "consumers don't touch auth code" breaks.

Leaning: A (use defaults).

Why:

  • 4-user app, no rate-limiting threat.
  • Same origin (frontend + backend behind Caddy) → no CORS surface.
  • If plate-auth's defaults are wrong for Sparkboard, that's a plate-auth bug, not a Sparkboard customisation. File it back upstream.

Decision: Pending. Sprint 1 verification: confirm A works end-to-end. Re-check in Sprint 2 if reactions/comments introduce new endpoint patterns.


Q07 — PWA assets pipeline

Question: Sprint 1 W4 produces manifest.json referencing icon files. How are those assets produced?

  • (A) Hand-crafted SVG + 12 PNG sizes (192 + 512) committed to frontend/public/icons/.
  • (B) Generated from a single source SVG via a build-time tool (e.g., pwa-asset-generator).
  • (C) Skip icons; rely on default browser icon (PWA install will still work, just ugly).

Why it matters: Affects A5 acceptance ("installable PWA with correct icon"). Default browser icon (C) technically installs but doesn't feel finished.

Leaning: A (hand-crafted, 2 sizes).

Why:

  • 4 humans, no app-store. Two PNGs are enough.
  • Asset-generator tooling (B) is Sprint 4+ when we care about iOS splash screens, maskable icons, dark-mode variants.
  • C fails the spirit of A5.

Decision: Decided 2026-06-24 — Option A. Hand-craft 2 PNGs (192×192 and 512×512), commit to frontend/public/icons/icon-192.png and frontend/public/icons/icon-512.png, reference both from frontend/public/manifest.json. No build-time generator in Sprint 1. Asset-generator tooling (Option B) revisited in Sprint 4+ when iOS splash / maskable / dark-mode variants are needed.


Q08 — Mobile strategy: PWA-only vs native APK

Question: Sprint 5 (Wildfire) optionally introduces Capacitor to package the PWA as a native APK (and iOS app). Do we go native?

  • (A) PWA only, forever. iOS share-target via PWA shortcuts; Android install via Chrome.
  • (B) PWA primary, plus a Capacitor APK for Android (cheap; native iOS deferred indefinitely).
  • (C) Full native (Capacitor APK + iOS via TestFlight + signing certs).

Leaning: A for v1; reconsider B at end of Sprint 4.

Why:

  • PWA install on iOS Safari does work (MT-01).
  • Capacitor for Android is genuinely cheap once the PWA exists.
  • iOS native is expensive (Apple developer account, signing, App Store review). Not worth it for 4 humans.

Decision: Pending. Not blocking Sprint 1.


Q09 — Real-time updates

Question: When User A creates an idea, does User B's open /ideas page refresh automatically?

  • (A) No real-time; rely on Next.js revalidation + manual refresh.
  • (B) Server-Sent Events (one-way push from backend to frontend).
  • (C) WebSockets (two-way, overkill for this).
  • (D) Polling every 10 seconds.

Leaning: A for v1/v2; B in Sprint 4 if it feels stale.

Why:

  • 4 humans, low concurrent-write rate. "Pull to refresh" is fine for v1.
  • SSE (B) is the cheapest real-time option (single endpoint, browser native).
  • WebSockets (C) costs more infrastructure for no real benefit at 4 users.
  • Polling (D) wastes bandwidth and battery.

Decision: Pending. Not blocking Sprint 1.


Q10 — Notifications

Question: Sprint 4 (Ember) lands notifications. What channels?

  • (A) Email digest (daily summary of new ideas).
  • (B) Web push (browser-side push notifications).
  • (C) Both.
  • (D) None — Sparkboard is pull-only.

Why it matters: Affects Sprint 4 architecture (SMTP integration vs Web Push API + VAPID keys).

Leaning: A (email digest first, then reassess for B).

Why:

  • Email is dead-simple: SMTP via SendGrid or postfix on TrueNAS; daily cron.
  • Web push requires VAPID keys, service-worker logic (sw.js becomes real, not a stub), and per-user permission grants. Higher effort, less reliable on iOS.
  • A daily email is genuinely useful for a family idea board (low rate of new items).
  • D ("none") is plausible if Sprint 3 reveals that the 4 humans naturally check the app regularly without prompting.

Decision: Pending. Not blocking Sprint 1.


Resolved Questions (Archive)

When a question is decided, the full text stays in place (numbering stays stable). This section is a quick-reference log of decisions.

ID Topic Decision Date
Q01 Single-org name and ID strategy A — Hardcode FAMILY_SPARK_ID = 00000000-0000-0000-0000-000000000001 2026-06-24
Q02 Allowlist management UX Aplate.auth.allowlist[] in application.yml 2026-06-24
Q03 Admin promotion model Asparkboard.admins[] YAML list, read by SparkboardOnboardingHook.onFirstSignIn 2026-06-24
Q07 PWA assets pipeline A — Hand-crafted 192×192 + 512×512 PNGs in frontend/public/icons/ 2026-06-24
F3 Reviewer finding — hook method spelling Renamed afterFirstLogin(OnboardingContext)onFirstSignIn(AuthenticatedUser) across all sparkboard docs (plate-auth spelling wins) 2026-06-24
F4 Reviewer finding — UT-06 package typo de.plate.sparkboard.auth.SparkboardOnboardingHookTestde.plate.sparkboard.onboarding.SparkboardOnboardingHookTest 2026-06-24

Cross-references

  • Sprint-1-Plan and Sprint-1-Plan-Part-4 — Sprint-1 impact of Q01, Q02, Q03, Q07
  • Roadmap — when each unresolved question is scheduled to bite
  • Architecture — context for Q01 (single-org), Q06 (security)
  • plate-auth wiki — for auth-side decisions (NOT in this list)

End of Open Questions. Status: 6 open, 4 resolved. (Q01, Q02, Q03, Q07 decided 2026-06-24.)