5
Open Questions
Patrick Plate edited this page 2026-06-24 21:32:30 +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: Draft v2 (Review v3 applied — Q13Q18 resolved, Q15 = Path A) Date: 2026-06-24 Owner: Patrick Scope: Decisions that are unresolved before Sprint 0 starts and must be answered (or explicitly deferred) before the v0.1.0 tag


1. How to use this document

Each question has:

  • ID (Q01…)
  • Topic (one-liner)
  • Status: 🟠 Open · 🟡 Leaning · Decided · ⏭️ Deferred
  • Context — why this is a question
  • Options considered
  • Current leaning with rationale
  • Decision deadline (which gate)
  • Owner (who decides)

When a question is decided, this doc gets updated; the decision is also reflected in Architecture.md, Roadmap.md, or Sprint-0-Plan.md as appropriate, and a stub fact is stored in BigMind.


2. Status overview

ID Topic Status Decide by
Q01 Concrete org table abstraction (Company → generic Organization?) Decided (2026-06-24) n/a
Q02 Microsoft Entra ID in v0.1 or defer to v0.2 Decided (2026-06-24) — Defer to v0.2 n/a
Q03 Flyway migration strategy (separate schema_history vs baseline reset) Decided (2026-06-24) — Separate flyway_schema_history_auth table (already implemented) n/a
Q04 Email magic-link provider in v0.1 or v0.2 ⏭️ Deferred n/a
Q05 npm package name (@platesoft/auth vs alternatives) Decided (2026-06-24) n/a
Q06 SemVer policy details — peer-version lockstep enforcement Decided (2026-06-24) — Wire-version constant (WIRE_VERSION=1) in envelope + npm peer dep n/a
Q07 Gitea publishing pipeline (Gitea Actions vs manual deploy) Decided (2026-06-24) — Gitea Actions on v* tag (workflows exist, test in W12) n/a
Q08 Spring Boot version pin (4.0.7 vs 4.1.0 vs latest milestone) Decided n/a (4.1.0)
Q09 Frontend bundler — tsup vs tsc vs unbuild Decided (2026-06-24) n/a
Q10 License — MIT, Apache-2.0, or internal proprietary Decided (2026-06-24) n/a
Q11 First-class i18n in @platesoft/auth/react? ⏭️ Deferred n/a
Q12 Audit emit channel — DB rows only, or also event stream? Decided (2026-06-24) — DB rows only v0.1; LoginEventSink SPI in v0.2 n/a
Q13 SecurityFilterChain scoping — securityMatcher vs unscoped anyRequest Decided (2026-06-24) — fixed in code @ b43ab5e n/a
Q14 Remove @ComponentScan from auto-config — explicit @Bean/@Import? Decided (2026-06-24) — fixed in code @ b43ab5e n/a
Q15 v0.1.0 surface — finish full extraction vs rescope to OAuth-core Decided (2026-06-24) — Path A: full extraction n/a
Q16 CORS default — fail-closed (same-origin) vs current open * Decided (2026-06-24) — fixed in code @ b43ab5e n/a
Q17 RefreshToken table — stateful rotation now (doc+migration) vs remove Decided (2026-06-24) — deleted @ b43ab5e n/a
Q18 spring-boot-starter-web deprecated in Spring Boot 4.x → spring-boot-starter-webmvc Decided (2026-06-24) — fix in W10 n/a

3. Open questions (detail)

Q01 — Concrete org table abstraction

Status: Decided 2026-06-24 — Option A: polymorphic FK (org_type, org_id) validated by OrgValidator SPI. plate-auth does NOT ship a concrete organizations table in 0.1.

Context. InspectFlow's Membership entity references Company (concrete entity). Sparkboard will have its own org table (probably Project or Studio). plate-auth must support both without leaking either domain.

Options considered:

Option Pros Cons
A) Polymorphic FK (org_type, org_id) validated by OrgValidator SPI No domain leak; each consumer keeps its own concrete table No FK constraint in DB; needs runtime validation
B) Generic organizations table in plate-auth, consumers reference it Real FK; consistent schema Consumers must mirror their own org table into ours; cross-DB sync nightmare
C) Abstract @MappedSuperclass consumers extend Type-safe at JPA level Forces JPA inheritance; cross-app reuse breaks

Decision: Option A. Matches Architecture.md § 4 SPI seams and was already designed into Sprint 14.2 (SPRINT-14.2-MEMBERSHIP-PLAN.md). The runtime-validation gap is closed by the mandatory OrgValidator SPI (default PermissiveOrgValidator with per-call WARN — see Architecture.md § 3.4).

Owner: Patrick. Locked 2026-06-24.


Q02 — Microsoft Entra ID in v0.1?

Status: Decided 2026-06-24Defer to v0.2 (extraction discipline > AI-assisted ease)

Context. InspectFlow Sprint 14.1 ships Google OAuth. Microsoft Entra ID was scoped into the "SSO sprint" but never landed. Sparkboard does not need it day 1.

GLM-5.2 + Lumen lens. With full AI power, adding MS Entra would be ~half a day (same OAuth pattern, SPI hooks ready, V5 migration already indexes the tenant field). The data model supports it. BUT — Sprint 0 is an extraction sprint, and MS Entra was never in InspectFlow's Sprint 14 code. Adding it would be a NEW feature, not an extraction. The discipline of "no new features in extraction" holds regardless of how easy AI makes it. The provider is a clean v0.2 addition — same pattern, ~1 day with AI.

Options:

Option Pros Cons
A) Include MS provider in v0.1 Single PR, both providers symmetric Adds scope to Sprint 0, no consumer asks for it yet
B) Defer to v0.2; SPI hooks present, provider impl absent Smaller Sprint 0; provider added cleanly later InspectFlow team has to wait for MS
C) Include MS but mark @Experimental Available + visible Half-tested code in stable release

Leaning: Option B. Keeps Sprint 0 tight. Note in Roadmap.md v0.2 line item.

Decision deadline: Before W2 starts (impacts provider package layout).

Owner: Patrick.


Q03 — Flyway migration strategy

Status: Decided 2026-06-24Separate flyway_schema_history_auth table (already implemented in PlateAuthFlywayConfig)

GLM-5.2 + Lumen lens. This was already implemented (W5 — PlateAuthFlywayConfig creates a second Flyway bean with table = "flyway_schema_history_auth", locations = "classpath:db/migration/auth"). It works, it's clean, no reason to revisit. The W-B co-existence test (W12) will prove it against a consumer that also has its own primary Flyway.

Context. InspectFlow has migrations V1..V31 in one history table. plate-auth needs V1..V6 (its own 6 auth migrations — see F2). If we deploy plate-auth into InspectFlow's existing DB, Flyway sees "your V1 is not my V1" — collision.

Options:

Option Pros Cons
A) Separate flyway_schema_history_auth table; second Flyway bean Clean separation; both apps see only their migrations Two Flyway runs at startup; complexity
B) Baseline-on-migrate + InspectFlow-side stub rows V1..V6 = "applied" Single history table Risky — Flyway baseline is one-shot; mistakes are hard to fix
C) Renumber plate-auth migrations to V100+ Single table, no collision Forever pollutes plate-auth versioning; ugly
D) Forbid plate-auth from owning migrations; consumer apps copy SQL No coupling Defeats the purpose of a starter; each consumer drifts

Leaning: Option A. Documented in Sprint-0-Plan.md § 7.1. Sparkboard starts fresh → no problem. InspectFlow gets baseline rows for V1..V6 added in the migration doc (see Migration-InspectFlow.md).

Decision deadline: Before W5 starts.

Owner: Patrick + Plan Reviewer ratification.


Status: ⏭️ Deferred to v0.2

Context. Magic-link sign-in is a common third option (after Google + password). InspectFlow Sprint 14.1 explicitly deferred it.

Decision: No v0.1 work. SPI seam InvitationMailer is generic enough to repurpose if we add magic-link later. Roadmap v0.2.

Owner: Patrick — already decided.


Q05 — npm package name

Status: Decided 2026-06-24 — npm: @platesoft/auth · Maven: de.platesoft:plate-auth-starter.

Context. The npm scope must be registered on the Gitea npm registry, which means it must be unique within our setup. We control the registry, so collisions aren't a concern; aesthetics + intent are.

Options considered:

Option Pros Cons
@platesoft/auth Matches Maven group de.platesoft; clear org scope None
@plate/auth Shorter Looks like the company is "plate" alone
plate-auth (unscoped) Simpler No org scope — collides with NPM-public name space if we ever publish there
@plate-software/auth Verbose but explicit Long imports

Decision: @platesoft/auth (npm) paired with de.platesoft:plate-auth-starter (Maven). Matches the Gitea org slug platesoft. Maven group is de.platesoft (reverse-DNS) → npm scope is @platesoft (shortened). Both artifacts ship in lockstep from the same v0.x.y git tag.

Owner: Patrick. Locked 2026-06-24.


Q06 — SemVer policy and peer-version lockstep

Status: Decided 2026-06-24Wire-version constant (WIRE_VERSION=1) in HMAC envelope + npm peerDependencies

GLM-5.2 + Lumen lens. With AI assistance, implementing the wire-version is trivial: add WIRE_VERSION = 1 to the envelope JSON in both ExchangeService (backend) and signEnvelope() (frontend), reject on mismatch. This is the real enforcement — it's testable, strict, and prevents silent contract drift between the two artifacts. The npm peer dep is a secondary guard. Implement in W8 (backend) + W9 (frontend). ~2 hours across both halves. Bumping wire-version = trigger for a 0.x → 0.(x+1) release.

Context. Backend and frontend ship from the same monorepo at the same version. If a consumer pins backend 0.1.0 and frontend 0.2.0, the HMAC envelope contract might drift.

Options:

Option Mechanism Pros Cons
A) Document only — trust the consumer Wiki note No code overhead Easy to break
B) Peer-version lockstep (npm peer dep >=0.1.0 <0.2.0 against a matching Maven artifact in the consumer's pom.xml) npm peer + runtime check Hard to misuse Cross-language peer dep is unusual
C) Embed a wire-version constant in both artifacts; HMAC header includes it; mismatched envelope rejected Code Strict; testable Adds protocol field

Leaning: Option B + C combined — npm peer dep + wire-version=1 constant embedded in HMAC envelope. v0.1 → wire-version 1. Bumping wire-version is the trigger for a 0.x → 0.(x+1) release across both halves.

Decision deadline: Before v0.1.0 release.

Owner: Patrick + Plan Reviewer.


Q07 — Gitea publishing pipeline

Status: Decided 2026-06-24Gitea Actions on v* tag — full CI/CD, not just basic publishing

Patrick's directive: "For Gitea and the DevOps tools behind us that make our lives so much nicer — always try to be up-to-date. For Gitea, let's explore and do the hard stuff if it's worth it. We will learn and get better."

Decision: Full Gitea Actions pipeline, not just basic tag-publishing. This includes:

  1. ci.yml — on every push/PR: mvn verify + pnpm build + unit/integration tests (matrix Java 25 + Node 22)
  2. release.yml — on v* tag: build + test + publish Maven JAR to Gitea Package Registry + publish npm tarball to Gitea npm registry
  3. Snyk / OWASP dep-check (§9.10 security checklist) — scan for CVEs at release tag, fail build on >medium severity
  4. Renovate — configured for post-release dependency management (keeps deps current automatically)
  5. Provenance — explore Gitea Package Registry's provenance/signing features as they mature
  6. Test with v0.0.1 validation tag (W12) before cutting the real v0.1.0

Workflows (ci.yml + release.yml) already exist in the repo. W12 tests the full pipeline end-to-end. The homelab's self-hosted act_runner on TrueNAS is the execution backend (same as CannaManage/InspectFlow). With GLM-5.2 + Lumen, we explore and adopt Gitea's latest Actions features as they land.

Context. Gitea supports both Maven and npm registries. We need to publish on each tag.

Options:

Option Pros Cons
A) Gitea Actions (.gitea/workflows/release.yml) on tag push Reproducible, auditable; matches InspectFlow's CI style Need runner availability
B) Manual mvn deploy + npm publish from a maintainer's laptop Zero CI setup Not reproducible; "works on my machine" risk
C) GitHub-mirror with GitHub Actions, push artifacts to Gitea via API Reuse GH free runners Two-CI complexity

Leaning: Option A. Sprint-0-Plan.md § 8 sketches ci.yml + release.yml.

Decision deadline: Before W6.

Owner: Patrick.


Q08 — Spring Boot version pin

Status: Decided — 4.1.0

Context. Sparkboard targets 4.1.0 (latest GA). InspectFlow runs 4.0.7 today but is on its own upgrade path.

Decision. plate-auth targets Spring Boot 4.1.0 as minimum. The starter compiles against 4.1.0 APIs. InspectFlow's Sprint 14.7 will bump 4.0.7 → 4.1.0 as a prerequisite for swapping to plate-auth. Compatibility window: starter v0.1.x works with Spring Boot 4.1.x. A future v0.2 may broaden to 4.2.x.

Stored. Reflected in Architecture.md § 1 wire contract and Roadmap.md.


Q09 — Frontend bundler

Status: Decided 2026-06-24tsup

Context. @platesoft/auth ships ESM with server / edge / react subpath exports. We need a bundler that handles tree-shaking + conditional exports correctly.

Options:

Bundler Notes
tsup Most common for libs; sensible defaults; good for ESM-only
tsc (plain TypeScript compiler) Zero deps; less ergonomic for multi-entry
unbuild Nuxt-team tool; good DX
rollup (raw) Power user; more config

Decision: tsup — zero-config dual ESM/CJS build, fast, ideal for a library package with conditional subpath exports. packages/auth/tsup.config.ts already exists in the repo, targeting Node 20 + Edge runtime. Implemented in W9 (Sprint-0-Plan.md §13.2, steps W9-6 + W3-2).

Owner: Patrick. Locked 2026-06-24.


Q10 — License

Status: Decided 2026-06-24 — Apache-2.0 placeholder for v0.1.0.

Options considered: MIT, Apache-2.0 (with explicit patent grant — recommended for libs), or internal proprietary.

Decision. plate-auth ships LICENSE.md set to Apache-2.0 as a placeholder for v0.1.0. The repo lives in private Gitea, so the license is dormant — it only activates if/when we choose to open-source. Apache-2.0 was picked over MIT for the explicit patent grant (standard for libraries that consumers will depend on). Patrick may flip to proprietary or another OSI license before any public release.

Owner: Patrick. Locked 2026-06-24.


Q11 — First-class i18n in @platesoft/auth/react?

Status: ⏭️ Deferred

Decision. Components in @platesoft/auth/react ship with English strings only in v0.1. Consumers wrap with their own i18n (InspectFlow uses next-intl, Sparkboard TBD). v1.0 may revisit.


Q12 — Audit emit channel

Status: Decided 2026-06-24DB rows only v0.1; LoginEventSink SPI in v0.2

GLM-5.2 + Lumen lens. A LoginEventSink SPI is trivially easy to add (one interface, one no-op default, one @ConditionalOnMissingBean). But the question isn't effort — it's need. For a 2-consumer homelab library (Sparkboard + InspectFlow), DB rows are sufficient. The LoginEventService writes rows, and W11 adds Envers RevInfo for entity-change audit. Together these cover the full v0.1 audit surface (login events + state changes). External shipping (Kafka/SIEM) is a v0.2 concern. The SPI will be a clean addition then.

Context. LoginEvent writes a DB row per login. Some consumers may want to emit to Kafka, NATS, syslog, or an external SIEM.

Decision: v0.1 = DB rows only. The AuditEmitter SPI added in v0.2 will let consumers tee events out. Refer to Roadmap.md.

Owner: Patrick.


Q13 — SecurityFilterChain scoping

Status: Decided 2026-06-24securityMatcher(...) scoped to plate-auth endpoints.

Context. Review v2 B1 found the SecurityFilterChain was unscoped (@Order(-100) + .anyRequest().authenticated()), hijacking every request in the consuming app.

Decision: The chain is now scoped via http.securityMatcher("/api/auth/**", "/api/invitations/**", "/api/access-requests/**", "/api/admin/**", "/api/me", "/api/memberships/**") at @Order(100). Verified in code on branch feature/sprint-0/review-v2-fixes @ b43ab5e. See Review v3 §1.


Q14 — Remove @ComponentScan from auto-config

Status: Decided 2026-06-24 — explicit @Import of 8 classes, no @ComponentScan.

Context. Review v2 B2 found @ComponentScan(basePackages = "de.platesoft.auth") in PlateAuthAutoConfiguration — an anti-pattern per Spring Boot docs.

Decision: @ComponentScan removed. The auto-config now explicitly @Imports: SecurityConfig, PlateAuthFlywayConfig, PlateAuthExceptionHandler, ExchangeService, JwtService, LoginEventService, MembershipService, OAuthController. Verified @ b43ab5e.


Q15 — v0.1.0 surface — Path A or rescope

Status: Decided 2026-06-24Path A: complete the full extraction for v0.1.0.

Context. Review v2 B3 found the code materially diverged from the plan — only the OAuth exchange path existed. The question was whether to finish the full extraction or rescope v0.1.0 to "OAuth-core only."

Options considered:

  • Path A: Finish full extraction — AuthController, Invitation/AccessRequest/AdminAudit services+controllers, OrgContextResolver, real frontend createAuthConfig/proxy/exchange
  • Path B: Rescope v0.1.0 to OAuth-exchange + memberships core, defer the rest to v0.2

Decision: Path A. Both consumers (Sparkboard, InspectFlow) depend on the full advertised surface. The missing work is lift-and-shift from InspectFlow 14.114.6 — mechanical extraction, not new design. Completion path: Plan v2 §13, workstreams W8W12. See Review v3 §5.

Owner: Patrick. Locked 2026-06-24.


Q16 — CORS default — fail-closed vs open

Status: Decided 2026-06-24 — fail-closed (same-origin only when origins empty).

Context. Review v2 B4 found CORS was default-open (allowedOriginPatterns("*")) when allowedOrigins was empty — wrong default for an auth library.

Decision: When allowedOrigins is empty → no CORS configuration registered at all (same-origin only). Consumer must explicitly set plate.auth.cors.allowed-origins to enable cross-origin. Verified @ b43ab5e.


Q17 — RefreshToken table

Status: Decided 2026-06-24 — removed (stateless JWT refresh for v0.1).

Context. Review v2 B5 found an undocumented RefreshToken entity + repository that appeared in no wiki doc, conflicting with the threat model (Architecture §10 says stateless JWT refresh, rotation deferred to v0.3).

Decision: RefreshToken.java and RefreshTokenRepository.java deleted. v0.1 uses stateless JWT refresh. Threat model and code are now consistent. Verified @ b43ab5e.


Q18 — spring-boot-starter-web deprecated in Spring Boot 4.x

Status: Decided 2026-06-24 — rename to spring-boot-starter-webmvc in W10.

Context. Review v3 N1 (new finding, not caught by v2): plate-auth-starter/pom.xml line 22 uses spring-boot-starter-web, which is deprecated in Spring Boot 4.x. The umbrella starter was renamed to spring-boot-starter-webmvc as part of Spring Boot 4's modularized auto-configuration. Confirmed via web research (Dan Vega blog Dec 2025, rieckpil.de, Spring Boot 4 migration guide). It still resolves and compiles (deprecation warnings) but will be removed in a future release.

Decision: Rename spring-boot-starter-webspring-boot-starter-webmvc in W10. Also: document that consumers relying on Spring Boot's Flyway auto-configuration need spring-boot-starter-flyway (plate-auth's own PlateAuthFlywayConfig is fine since it creates its own bean).

Owner: Patrick. Locked 2026-06-24. Scheduled in Plan v2 §13.3 (W10).


4. Decided (history)

ID Decision Date Reference
Q08 Spring Boot 4.1.0 minimum 2026-06-24 Architecture.md
Q04 Magic-link → v0.2 2026-06-24 Roadmap.md
Q11 i18n → consumer-supplied 2026-06-24 this doc
Q01 Polymorphic FK (org_type, org_id) validated by OrgValidator SPI; no concrete organizations table in 0.1 2026-06-24 Architecture.md § 3.4, this doc
Q05 npm: @platesoft/auth · Maven: de.platesoft:plate-auth-starter (lockstep versions) 2026-06-24 Architecture.md § 9, this doc
Q10 Apache-2.0 placeholder for v0.1.0 (dormant until open-sourced) 2026-06-24 Home.md § Distribution, this doc
F1 PermissiveOrgValidator ships as default OrgValidator, logs WARN on every call 2026-06-24 Architecture.md § 3.4, Sprint-0-Plan.md § 4.5, Sprint-0-Testplan.md T-UT15, Integration-Guide.md § 3.3
F2 plate-auth ships 6 Flyway migrations (V1..V6) in db/migration/auth/; V5__add_microsoft_tenant_id_index.sql is a standalone index migration 2026-06-24 Architecture.md § 8.1, Sprint-0-Plan.md § 7.2, Sprint-0-Testplan.md T-IT01
Q13 SecurityFilterChain scoped via securityMatcher(...) at @Order(100) — fixed in code @ b43ab5e 2026-06-24 Review v3 §1 B1
Q14 @ComponentScan removed from auto-config; explicit @Import of 8 classes — fixed @ b43ab5e 2026-06-24 Review v3 §1 B2
Q15 Path A — complete full extraction for v0.1.0 (not rescope) 2026-06-24 Review v3 §5, Plan v2 §13
Q16 CORS fail-closed by default (empty origins → same-origin only) — fixed @ b43ab5e 2026-06-24 Review v3 §1 B4
Q17 RefreshToken entity/repository deleted — stateless JWT refresh for v0.1 — fixed @ b43ab5e 2026-06-24 Review v3 §1 B5
Q18 spring-boot-starter-webspring-boot-starter-webmvc (Spring Boot 4.x deprecation) — fix in W10 2026-06-24 Review v3 §2 N1, Plan v2 §13.3
Q09 Frontend bundler → tsup (packages/auth/tsup.config.ts exists) — implemented in W9 2026-06-24 Plan v2 §13.2, this doc
Q02 Microsoft Entra ID → defer to v0.2 (extraction discipline holds even with AI ease; SPI + V5 migration ready) 2026-06-24 Roadmap.md v0.2, this doc
Q03 Flyway → separate flyway_schema_history_auth table (already implemented in PlateAuthFlywayConfig) 2026-06-24 Plan v2 §7.3, this doc
Q06 Lockstep → wire-version constant (WIRE_VERSION=1) in HMAC envelope + npm peer dep (implement in W8/W9) 2026-06-24 Architecture.md §1, Plan v2 §13.1/§13.2
Q07 Publishing → full Gitea Actions CI/CD (ci.yml + release.yml + Snyk + Renovate; test with v0.0.1 in W12) 2026-06-24 Plan v2 §8 + §13.5 W12, this doc
Q12 Audit → DB rows only v0.1 (LoginEventService + Envers RevInfo in W11); LoginEventSink SPI v0.2 2026-06-24 Roadmap.md v0.2, this doc

5. How to add a new question

  1. Pick the next Qxx number.
  2. Add a row in § 2 with status 🟠 Open.
  3. Add a detailed § 3 entry with options + leaning.
  4. When decided, move row to § 4 and update referenced docs.
  5. Commit + push.

6. Cross-references


End of Open-Questions.md (v2).