Table of Contents
- Sprint 0 — Assessment
- 1. Source-of-truth inventory
- 1.1 Backend — Java / Spring Boot 4.0.7
- 1.2 Frontend — TypeScript / Next.js 15 / NextAuth v5
- 1.3 What is not in InspectFlow but should be
- 2. Reusability classification — summary
- 3. Risk register
- 4. Dependencies we are accepting
- 5. Effort estimate
- 6. Recommendation
- 7. Open questions raised during assessment
Sprint 0 — Assessment
Status: Draft v1 Date: 2026-06-24 Owner: Patrick (plate-software) Purpose: Inventory InspectFlow's current auth implementation, classify each piece as lift-and-shift / needs-reshaping / leave-behind, and surface the risks of the extraction.
1. Source-of-truth inventory
InspectFlow's auth surface was built over six sub-sprints (14.1 – 14.6). The artifacts below were read
directly from inspectflow/backend and inspectflow/frontend at the time of this assessment.
1.1 Backend — Java / Spring Boot 4.0.7
| Layer | Class / file | Lines | Domain coupling | Status |
|---|---|---|---|---|
| Config | SecurityConfig |
67 | Hardcoded URL list for permitAll includes InspectFlow-specific routes (/api/companies/*/public-info) |
Reshape — make permit-list config-driven |
| Filter | JwtAuthenticationFilter |
60 | None — pure JWT extraction + SecurityContext | Lift-and-shift |
| Filter | OrgContextResolver |
~80 | Reads X-Org-Id header, validates via MembershipService — no concrete-org coupling |
Lift-and-shift |
| Service | JwtService |
97 | None — pure JWT issuance using HMAC SHA-256 | Lift-and-shift |
| Service | OAuthService |
~200 | Calls TenantAutoMapService for MS tenant→company mapping (InspectFlow-specific) |
Reshape — hoist auto-map to T3 via OnboardingHook SPI |
| Service | ExchangeService |
~150 | None — HMAC verify + nonce dedup (in-memory ConcurrentHashMap) |
Lift-and-shift (note: in-memory replay store breaks under multi-replica — flagged for v0.3) |
| Service | MembershipService |
~250 | Joins to companies for display name → use OrgDisplayNameResolver SPI |
Reshape |
| Service | InvitationService |
~300 | Mails via InvitationMailer (already abstracted in Sprint 14.3) |
Lift-and-shift with minor SPI surface tweak |
| Service | AccessRequestService |
~250 | Same pattern as Invitation | Lift-and-shift |
| Service | LoginEventService |
~120 | None — async event recorder | Lift-and-shift |
| Service | AuthService |
~180 | Password login / register / refresh — uses User + Role only | Lift-and-shift |
| Service | OnboardingService |
~200 | Heavy — manages InspectFlow's "first sign-in" business-state machine | Leave behind (T3) — expose OnboardingHook SPI for plate-auth to call |
| Service | TenantAutoMapService |
~150 | Heavy — MS Entra tenant → InspectFlow Company auto-mapping | Leave behind (T3) |
| Controller | OAuthController |
~80 | None | Lift-and-shift |
| Controller | AuthController |
~150 | None | Lift-and-shift |
| Controller | InvitationController |
~120 | None | Lift-and-shift |
| Controller | AccessRequestController |
~100 | None | Lift-and-shift |
| Controller | AdminAuditController |
~80 | None | Lift-and-shift |
| Entity | User |
~80 | None — default_org_id is polymorphic UUID |
Lift-and-shift |
| Entity | UserIdentity |
~70 | None — provider-agnostic | Lift-and-shift |
| Entity | Membership |
~90 | Polymorphic (org_type, org_id) already |
Lift-and-shift |
| Entity | Invitation |
~80 | Polymorphic | Lift-and-shift |
| Entity | AccessRequest |
~80 | Polymorphic | Lift-and-shift |
| Entity | LoginEvent |
~60 | None | Lift-and-shift |
| Entity | Company |
~120 | Pure InspectFlow — addresses, embedding vector, industry | Leave behind (T3) |
| Enums | OrgType, MembershipRole, MembershipStatus, InvitationStatus, AccessRequestStatus, LoginProvider, Role |
~70 total | None | Lift-and-shift |
| Migration | V26 — user_identities, password_hash nullable |
— | None | Renumber to V1 |
| Migration | V27 — memberships + org-FK trigger |
— | Trigger references companies |
Renumber to V2 + leave trigger as T3 consumer responsibility |
| Migration | V28 — invitations + audit |
— | None | Renumber to V3 |
| Migration | V29 — access_requests |
— | None | Renumber to V4 |
| Migration | V30 — companies.microsoft_tenant_id |
— | Pure InspectFlow | Leave in InspectFlow's migration set |
| Migration | V31 — login_events + revinfo actor |
— | None | Renumber to V6 (see note below) |
Migration-count note (corrected 2026-06-24, supersedes earlier "V5 tail"): plate-auth ships 6 migrations, V1..V6. V26→V1, V27→V2, V28→V3, V29→V4, then a standalone
V5__add_microsoft_tenant_id_index.sql(an index onuser_identities.microsoft_tenant_id— T1 data, distinct from V30'scompanies.microsoft_tenant_idwhich is T3 and stays in InspectFlow), and finally V31→V6create_login_events_and_revinfo_actor.sql. This matches Architecture.md §8.1, Open-Questions F2, and the 6 migration files present inplate-auth-starter/src/main/resources/db/migration/auth/. The earlier "tail is V5 not V6" phrasing was wrong and is retracted.
1.2 Frontend — TypeScript / Next.js 15 / NextAuth v5
| Layer | File | Lines | Domain coupling | Status |
|---|---|---|---|---|
| Config | auth-config.ts |
~150 | InspectFlow-branded provider opts, invite-token extraction from URL | Reshape — extract createAuthConfig(opts) factory |
| Lib | exchange.ts |
~80 | None — HMAC envelope sign + POST | Lift-and-shift |
| Lib | auth.ts |
~40 | Hardcoded localStorage keys (inspectflow_access_token) |
Reshape — make key prefix configurable |
| Route | app/api/auth/[...nextauth]/route.ts |
~10 | None | Lift-and-shift as default boilerplate |
| Route | app/api/[...path]/route.ts (proxy) |
~120 | None — calls auth() + BACKEND_URL env var |
Reshape — extract createProxyHandlers(opts) factory |
| Middleware | middleware.ts |
~5 | Trivial passthrough | Lift-and-shift |
| Context | auth-context.tsx |
~100 | Syncs NextAuth session → localStorage with InspectFlow keys | Reshape — provide hook, let consumer choose persistence |
| Component | <SignInButton />, <UserMenu />, etc. |
— | InspectFlow UI styling | Leave behind — components stay per-product |
1.3 What is not in InspectFlow but should be
| Item | Justification |
|---|---|
PlateAuthAutoConfiguration |
Spring Boot starter auto-config doesn't exist yet — InspectFlow wires beans manually |
PlateAuthProperties with @ConfigurationProperties("plate.auth") |
InspectFlow has scattered @Value("${jwt.secret}") etc. — needs consolidation |
META-INF/spring/...AutoConfiguration.imports |
Spring Boot 3+ auto-config registration file |
OrgValidator SPI |
Currently MembershipService.grantMembership(…) checks companies directly via repository |
Default OrgDisplayNameResolver |
Currently joined inline in MembershipService |
OnboardingHook SPI |
Currently OAuthService calls OnboardingService directly |
createAuthConfig(opts) factory |
InspectFlow's auth-config.ts is mostly procedural |
createProxyHandlers(opts) factory |
Same |
| Lockstep version contract documentation | InspectFlow doesn't version its in-tree code as a public artifact |
2. Reusability classification — summary
pie title "Auth surface — extraction classification"
"Lift-and-shift" : 65
"Reshape (small)" : 25
"Leave behind (T3)" : 10
- ~65% lift-and-shift: entities, filters, JwtService, ExchangeService, controllers, password-auth, login events, invitation flow, access request flow.
- ~25% reshape: SecurityConfig permit-list, MembershipService FK lookup, frontend factories, config namespace.
- ~10% leave behind (T3): Company entity, OnboardingService, TenantAutoMapService, V30 migration.
The extraction is fundamentally a rename + repackage operation with 5 well-defined SPI seams.
3. Risk register
| # | Risk | Likelihood | Impact | Mitigation |
|---|---|---|---|---|
| R1 | Flyway migration renumbering corrupts InspectFlow's flyway_schema_history |
Medium | High — could break a production deploy | Use Flyway baseline strategy: introduce flyway_schema_history_auth separate from app's table OR use installed_rank re-mapping (see Sprint-0-Plan § Migration strategy) |
| R2 | InspectFlow ends up shadow-overriding services because SPI is too narrow | Medium | Medium — forks defeat purpose of library | Plan v0.2 SPI follow-up; track shadow-overrides during InspectFlow migration |
| R3 | Spring Boot 4 + Java 25 not yet GA when we ship | Low (Sparkboard already committed) | Medium | Pin to specific stable milestone; coordinate with Sparkboard team |
| R4 | NextAuth v5 final API differs from current beta | Low | Medium | Pin next-auth@5.0.0-beta.X and lockstep with our v0.1 release |
| R5 | In-memory nonce store breaks under multi-replica (already known) | Certain (when scaling) | Medium | Documented in Roadmap.md as v0.3 work; v0.1 ships with this known limitation |
| R6 | Gitea Package Registry npm publishing not yet configured | Medium | Medium | Sprint 0 includes a "publish pipeline" task; validate by publishing a 0.0.0-snapshot first |
| R7 | de.platesoft.auth.* package rename breaks downstream consumers that imported from de.platesoft.inspectflow.security.* |
Certain (InspectFlow consumes) | Low — mechanical refactor | Migration-InspectFlow.md provides exact sed/find-replace recipes |
| R8 | Microsoft Entra ID coupling assumed (InspectFlow uses it, Sparkboard might not) | Low — feature is config-gated | Low | Provider enabled via plate.auth.providers.microsoft.enabled=false default |
| R9 | OrgType enum is shared across products — what if Sparkboard adds WORKSPACE and InspectFlow doesn't know about it? |
Medium | Low — enum is in lib, value space is open | Make OrgType a String-backed enum or keep as enum but document the "consumer registers their own types" pattern. Decision deferred to Open-Questions Q01. |
| R10 | The published JAR contains entity classes — consumers must not extend or modify them | Low | Medium | Mark entities final where Hibernate allows; document the contract in Architecture.md |
| R11 | HMAC secret regeneration causes total session invalidation across all users | Low (deliberate ops action) | Low | Document operational runbook; v0.3 adds kid-based rotation |
| R12 | Java 25 LTS adoption — Sparkboard pioneer, InspectFlow currently on Java 25 already | Low | Low | Verified InspectFlow pom.xml shows Java 25 — no risk |
4. Dependencies we are accepting
Version snapshot at time of extraction (read from inspectflow/backend/pom.xml):
| Dep | Version | Notes |
|---|---|---|
| Spring Boot | 4.1.0 (target — InspectFlow on 4.0.7 today) | Bump as part of extraction |
| Java | 25 LTS | Aligned with InspectFlow + Sparkboard |
| jjwt | 0.12.6 | HMAC SHA-256 token signing |
| Hibernate | (Spring Boot managed) | + Envers for audit |
| Postgres driver | (Spring Boot managed) | |
| Flyway | (Spring Boot managed) | |
| Lombok | (Spring Boot managed) | |
| MapStruct | (Spring Boot managed) | DTO mapping |
| NextAuth | 5.x (beta tracking) | Frontend session layer |
| Next.js | 15+ App Router | Required for auth() + duplex:"half" |
| React | 19 | Required by NextAuth v5 |
We accept tight coupling to these. We do not abstract over framework boundaries.
5. Effort estimate
Single-engineer days, including planning, code, tests, plan reviews:
| Phase | Effort | Notes |
|---|---|---|
| Wiki documentation (this batch) | 1d | Done in this session |
| Plan Review iteration loop | 0.5–1d | Plan Reviewer + Ask Phase + Patrick GO |
| Repo scaffolding (Maven + npm + CI) | 0.5d | Gitea Actions, publish pipeline |
| Backend extraction (rename + repackage) | 1.5d | Mechanical; lots of imports to update |
| Backend SPI work (5 SPIs + auto-config) | 1d | Net new code |
| Flyway migration consolidation | 0.5d | + integration tests |
| Frontend extraction (factories + types) | 1d | |
| Internal tests | 1d | Integration tests covering exchange + auth flow |
| InspectFlow migration | 1d | Per Migration-InspectFlow.md |
| Sparkboard adoption dry-run | 0.5d | Validates Integration-Guide.md |
| Buffer | 1d | Always |
| Total | ~9–10 engineer-days | Sprint 0 fits in 2 calendar weeks |
6. Recommendation
GO — proceed to Sprint-0-Plan v1 with the following constraints:
- Strict T1+T2 scope. Anything T3-flavored stays in InspectFlow until at least v0.2.
- 5 SPIs are mandatory in v0.1. Without them InspectFlow cannot migrate cleanly.
- Lockstep versioning is mandatory. Frontend and backend ship together with identical version numbers.
- Migration renumbering uses a separate
flyway_schema_history_authtable (or equivalent) — must NOT touch InspectFlow's existingflyway_schema_history. Final decision in Open-Questions Q03. - In-memory nonce store is acceptable for v0.1. Documented limitation. Multi-replica fix in v0.3.
- No Spring Boot 4 GA gate. Use the milestone Sparkboard team has already adopted, even if it's a release candidate.
If the Plan Reviewer disagrees with any of these, we iterate. But these are the assumptions Sprint-0-Plan v1 will be built on.
7. Open questions raised during assessment
The following items surfaced during analysis but should not block Sprint 0 planning. They are tracked in
Open-Questions.md for Patrick to resolve before code starts:
- Q01 — Concrete org table abstraction (Company stays vs. generic Organization)
- Q02 — Microsoft Entra ID in v0.1 or defer to v0.2 (depends on Sparkboard plans)
- Q03 — Flyway migration strategy (separate schema history table vs. baseline reset)
- Q04 — Email magic-link provider in v0.1 or v0.2
- Q05 — npm package name (
@platesoft/authvs alternatives) - Q06 — SemVer policy details (especially around peer version lockstep)
- Q07 — Gitea publishing pipeline (Gitea Actions vs manual deploy)
- Q08 — Spring Boot version pin (4.0.7 vs 4.1.0 vs latest milestone)
Assessment ready for Plan Reviewer. Sprint-0-Plan v1 will be drafted assuming all Section 6 recommendations hold; any Plan Reviewer pushback re-opens the recommendation list.