docs: apply F1 (PermissiveOrgValidator default + per-call WARN) and F2 (V1..V6 migrations) across Architecture, Plan, Testplan, Integration-Guide
+5
-3
@@ -149,13 +149,15 @@ Consumers implement these to plug their domain into plate-auth:
|
|||||||
|
|
||||||
| Interface | Required? | Default | Purpose |
|
| Interface | Required? | Default | Purpose |
|
||||||
|---|---|---|---|
|
|---|---|---|---|
|
||||||
| `OrgValidator` | **Yes** (if T2 used) | — | Validate `org_id` exists in consumer's `companies` / `workspaces` / etc. |
|
| `OrgValidator` | Optional (override strongly recommended for production) | `PermissiveOrgValidator` — returns `true` for any `(org_type, org_id)` and **logs a WARN on every call** ("OrgValidator default permissive — override `OrgValidator` bean before production") | Validate `(org_type, org_id)` exists in consumer's `companies` / `workspaces` / etc. |
|
||||||
| `OrgDisplayNameResolver` | Optional | Returns `org_id.toString()` | Pretty-print org for invitations / emails. |
|
| `OrgDisplayNameResolver` | Optional | Returns `type + ":" + org_id.toString()` | Pretty-print org for invitations / emails. |
|
||||||
| `InvitationMailer` | Optional | No-op logger | Send invitation emails. Default just logs the token URL. |
|
| `InvitationMailer` | Optional | No-op logger | Send invitation emails. Default just logs the token URL. |
|
||||||
| `AccessRequestMailer` | Optional | No-op logger | Notify admins of new access requests. |
|
| `AccessRequestMailer` | Optional | No-op logger | Notify admins of new access requests. |
|
||||||
| `OnboardingHook` | Optional | No-op | Called on first successful sign-in — consumer's place to wire T3 onboarding. |
|
| `OnboardingHook` | Optional | No-op | Called on first successful sign-in — consumer's place to wire T3 onboarding. |
|
||||||
|
|
||||||
All extension points are `@ConditionalOnMissingBean` — register your own bean to override.
|
All extension points are `@ConditionalOnMissingBean` — register your own bean to override. The
|
||||||
|
`PermissiveOrgValidator` default exists so the starter boots green with zero consumer code; the
|
||||||
|
per-call WARN log makes it impossible to ignore that no real validation is happening.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
+4
-3
@@ -110,7 +110,7 @@ That's it for the bare minimum. Run your app — the starter auto-configures.
|
|||||||
| `ExchangeService` | HMAC envelope mint/consume |
|
| `ExchangeService` | HMAC envelope mint/consume |
|
||||||
| `JwtAuthenticationFilter` | Reads `Authorization: Bearer ...`, populates `SecurityContext` |
|
| `JwtAuthenticationFilter` | Reads `Authorization: Bearer ...`, populates `SecurityContext` |
|
||||||
| `SecurityFilterChain` (named `plateAuthSecurityChain`) | Whitelists `/auth/**`, requires JWT elsewhere |
|
| `SecurityFilterChain` (named `plateAuthSecurityChain`) | Whitelists `/auth/**`, requires JWT elsewhere |
|
||||||
| `OrgValidator` (default = `PermissiveOrgValidator`) | Accepts any `(org_type, org_id)` — replace via SPI |
|
| `OrgValidator` (default = `PermissiveOrgValidator`) | Accepts any `(org_type, org_id)` and **logs a WARN on every call** (`"OrgValidator default permissive — override de.platesoft.auth.spi.OrgValidator bean before production"`) — replace via SPI before production |
|
||||||
| `InvitationMailer` (default = `LoggingMailer`) | Logs mails to console — replace via SPI |
|
| `InvitationMailer` (default = `LoggingMailer`) | Logs mails to console — replace via SPI |
|
||||||
| `AccessRequestMailer` (default = `LoggingMailer`) | Same |
|
| `AccessRequestMailer` (default = `LoggingMailer`) | Same |
|
||||||
| `OnboardingHook` (default = `NoopOnboardingHook`) | Does nothing — replace via SPI |
|
| `OnboardingHook` (default = `NoopOnboardingHook`) | Does nothing — replace via SPI |
|
||||||
@@ -405,11 +405,12 @@ Run these manually to verify the integration is healthy:
|
|||||||
|
|
||||||
- [ ] App boots without errors. Logs show `Started ... in X seconds`.
|
- [ ] App boots without errors. Logs show `Started ... in X seconds`.
|
||||||
- [ ] `curl http://localhost:8080/auth/health` returns 200 OK.
|
- [ ] `curl http://localhost:8080/auth/health` returns 200 OK.
|
||||||
- [ ] DB has 5 new tables under your schema. `flyway_schema_history_auth` has 5 rows.
|
- [ ] DB has 6 new tables / index objects under your schema. `flyway_schema_history_auth` has **6 rows** (V1..V6).
|
||||||
- [ ] `curl -d '{"email":"a","password":"b"}' http://localhost:8080/auth/login` returns 401 with structured JSON error (not a stack trace).
|
- [ ] `curl -d '{"email":"a","password":"b"}' http://localhost:8080/auth/login` returns 401 with structured JSON error (not a stack trace).
|
||||||
- [ ] Frontend `/login` page renders.
|
- [ ] Frontend `/login` page renders.
|
||||||
- [ ] Sign-in with Google works → redirect → `/api/hello` returns email.
|
- [ ] Sign-in with Google works → redirect → `/api/hello` returns email.
|
||||||
- [ ] No `WARN` logs about missing SPI defaults (you should have replaced `PermissiveOrgValidator` and `LoggingMailer`).
|
- [ ] **WARN logs `"OrgValidator default permissive — override ..."` are gone** — meaning you registered a real `OrgValidator` bean. Until you do, the default fires on every membership check.
|
||||||
|
- [ ] No remaining `LoggingMailer` warnings (you should have replaced `InvitationMailer` and `AccessRequestMailer`).
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
+21
-14
@@ -36,8 +36,8 @@ Each step is numbered so the Code-mode worker can check off progress without amb
|
|||||||
- Frontend artifact `@platesoft/auth@0.1.0` (npm, NextAuth v5 wiring)
|
- Frontend artifact `@platesoft/auth@0.1.0` (npm, NextAuth v5 wiring)
|
||||||
- 5 SPIs (`OrgValidator`, `OrgDisplayNameResolver`, `InvitationMailer`, `AccessRequestMailer`,
|
- 5 SPIs (`OrgValidator`, `OrgDisplayNameResolver`, `InvitationMailer`, `AccessRequestMailer`,
|
||||||
`OnboardingHook`)
|
`OnboardingHook`)
|
||||||
- Flyway migrations under `db/migration/auth/V1..V5` (one less than InspectFlow because V30 stays
|
- Flyway migrations under `db/migration/auth/V1..V6` (6 migrations — see § 5 and
|
||||||
in app — see § 5)
|
[`Architecture.md`](Architecture.md) § 8.1 for the canonical list)
|
||||||
- Gitea Actions pipeline that publishes both artifacts on a `v*` git tag
|
- Gitea Actions pipeline that publishes both artifacts on a `v*` git tag
|
||||||
- Internal integration tests covering exchange + JWT + memberships
|
- Internal integration tests covering exchange + JWT + memberships
|
||||||
- All 10 wiki docs reviewed + approved by Plan Reviewer + GO from Patrick
|
- All 10 wiki docs reviewed + approved by Plan Reviewer + GO from Patrick
|
||||||
@@ -372,9 +372,10 @@ through `PlateAuthProperties`. App fails fast at startup if `secret` is missing
|
|||||||
```
|
```
|
||||||
2. **W4-2** Default implementations (annotated `@ConditionalOnMissingBean`, registered in
|
2. **W4-2** Default implementations (annotated `@ConditionalOnMissingBean`, registered in
|
||||||
`PlateAuthAutoConfiguration`):
|
`PlateAuthAutoConfiguration`):
|
||||||
- `DefaultOrgValidator` — **does NOT exist as a default**; auto-config requires the consumer to
|
- `PermissiveOrgValidator` — **ships as the default**. `exists(...)` always returns `true` and
|
||||||
provide one if T2 endpoints are used. If absent, T2 endpoints fail-fast on first invocation with a
|
**logs a WARN on every call**: `"OrgValidator default permissive — override de.platesoft.auth.spi.OrgValidator bean before production"`.
|
||||||
clear error: "Provide a `de.platesoft.auth.spi.OrgValidator` bean to use plate-auth multi-tenancy."
|
Rationale: the starter must boot green with zero consumer code; the per-call WARN makes it
|
||||||
|
impossible to ship to production without noticing that real validation is missing.
|
||||||
- `DefaultOrgDisplayNameResolver` — returns `type + ":" + orgId.toString()`
|
- `DefaultOrgDisplayNameResolver` — returns `type + ":" + orgId.toString()`
|
||||||
- `LoggingInvitationMailer` — logs the accept URL at INFO level
|
- `LoggingInvitationMailer` — logs the accept URL at INFO level
|
||||||
- `LoggingAccessRequestMailer` — logs notifications at INFO level
|
- `LoggingAccessRequestMailer` — logs notifications at INFO level
|
||||||
@@ -389,8 +390,9 @@ through `PlateAuthProperties`. App fails fast at startup if `secret` is missing
|
|||||||
- What happens if the consumer doesn't provide one (which default kicks in)
|
- What happens if the consumer doesn't provide one (which default kicks in)
|
||||||
- Migration: if a previous version's signature changed, link to CHANGELOG
|
- Migration: if a previous version's signature changed, link to CHANGELOG
|
||||||
|
|
||||||
**Done when:** A consumer can register a single `OrgValidator` bean and have T2 fully functional. Default
|
**Done when:** Starter boots green with zero SPI beans (default `PermissiveOrgValidator` accepts
|
||||||
mailers log instead of crashing.
|
all `(org_type, org_id)` and emits per-call WARN). A consumer can register a single `OrgValidator`
|
||||||
|
bean to replace it and have T2 fully validated. Default mailers log instead of crashing.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -554,11 +556,11 @@ for v0.1 (subject to Plan Reviewer concurrence):
|
|||||||
> - Runs at startup *before* the application's own Flyway
|
> - Runs at startup *before* the application's own Flyway
|
||||||
> - Application's primary `Flyway` continues to manage `flyway_schema_history` for app migrations
|
> - Application's primary `Flyway` continues to manage `flyway_schema_history` for app migrations
|
||||||
>
|
>
|
||||||
> **Why:** plate-auth's `V1..V5` numbering is completely independent of any app's `V1..VN`.
|
> **Why:** plate-auth's `V1..V6` numbering is completely independent of any app's `V1..VN`.
|
||||||
> Both libraries can advance their own version space without collision. Consumers get a clean install
|
> Both libraries can advance their own version space without collision. Consumers get a clean install
|
||||||
> from scratch, and InspectFlow's `Migration-InspectFlow.md` handles the in-place baseline.
|
> from scratch, and InspectFlow's `Migration-InspectFlow.md` handles the in-place baseline.
|
||||||
|
|
||||||
If Plan Reviewer rejects this and prefers numbered-tail approach (e.g. plate-auth ships V1..V5 and
|
If Plan Reviewer rejects this and prefers numbered-tail approach (e.g. plate-auth ships V1..V6 and
|
||||||
relies on app migrations starting at V100), we revise to single-table strategy. Both approaches are
|
relies on app migrations starting at V100), we revise to single-table strategy. Both approaches are
|
||||||
viable; the separate-table one is more isolating.
|
viable; the separate-table one is more isolating.
|
||||||
|
|
||||||
@@ -577,15 +579,19 @@ viable; the separate-table one is more isolating.
|
|||||||
migrated; if you previously relied on it, keep it in your app's migration."
|
migrated; if you previously relied on it, keep it in your app's migration."
|
||||||
4. **W5-4** Copy V28 → `V3__create_invitations.sql`.
|
4. **W5-4** Copy V28 → `V3__create_invitations.sql`.
|
||||||
5. **W5-5** Copy V29 → `V4__create_access_requests.sql`.
|
5. **W5-5** Copy V29 → `V4__create_access_requests.sql`.
|
||||||
6. **W5-6** Copy V31 → `V5__create_login_events_and_revinfo_actor.sql`.
|
6. **W5-6** Create `V5__add_microsoft_tenant_id_index.sql`. This is a standalone migration that
|
||||||
|
adds an index on `user_identities.microsoft_tenant_id` (the column itself lives in V1). It stays
|
||||||
|
separate from the login-events migration so the index can ship as a hotfix without renumbering.
|
||||||
|
7. **W5-7** Copy V31 → `V6__create_login_events_and_revinfo_actor.sql`.
|
||||||
(V30, `companies.microsoft_tenant_id`, stays in InspectFlow's migration set — T3.)
|
(V30, `companies.microsoft_tenant_id`, stays in InspectFlow's migration set — T3.)
|
||||||
7. **W5-7** Add `MigrationContentTest` (integration test) that:
|
8. **W5-8** Add `MigrationContentTest` (integration test) that:
|
||||||
- Spins up Testcontainers Postgres
|
- Spins up Testcontainers Postgres
|
||||||
- Runs plate-auth Flyway against `flyway_schema_history_auth`
|
- Runs plate-auth Flyway against `flyway_schema_history_auth`
|
||||||
- Asserts all 5 versions applied successfully
|
- Asserts all 6 versions applied successfully (`V1..V6`)
|
||||||
- Asserts no SQL errors in clean install
|
- Asserts no SQL errors in clean install
|
||||||
|
|
||||||
**Done when:** Migration test passes against Testcontainers Postgres in CI.
|
**Done when:** Migration test passes against Testcontainers Postgres in CI with 6 rows in
|
||||||
|
`flyway_schema_history_auth`.
|
||||||
|
|
||||||
### 7.3 W5 — Auto-config the second Flyway bean
|
### 7.3 W5 — Auto-config the second Flyway bean
|
||||||
|
|
||||||
@@ -808,7 +814,8 @@ v0.1.0 cannot tag until every item below is verified.
|
|||||||
|
|
||||||
### 10.1 Step 0 — internal validation tag
|
### 10.1 Step 0 — internal validation tag
|
||||||
|
|
||||||
1. Cut `v0.0.1` from main after all workstreams W1–W7 complete + tests green.
|
1. Cut `v0.0.1` from main after all workstreams W1–W7 complete + tests green (6 Flyway migrations
|
||||||
|
applied, default `PermissiveOrgValidator` emits WARN on every call).
|
||||||
2. In a throwaway repo, consume `de.platesoft:plate-auth-starter:0.0.1` + `@platesoft/auth@0.0.1`.
|
2. In a throwaway repo, consume `de.platesoft:plate-auth-starter:0.0.1` + `@platesoft/auth@0.0.1`.
|
||||||
3. Implement an `OrgValidator` that returns `true` for any input. Boot the app.
|
3. Implement an `OrgValidator` that returns `true` for any input. Boot the app.
|
||||||
4. Hit `/api/auth/config` — should return Google provider info.
|
4. Hit `/api/auth/config` — should return Google provider info.
|
||||||
|
|||||||
+3
-3
@@ -188,8 +188,8 @@ Status legend: ⬜ Open · 🟡 In progress · ✅ Passed · ❌ Failed · ⏭
|
|||||||
|
|
||||||
- **Class:** `de.platesoft.auth.spi.OrgContextResolverTest`
|
- **Class:** `de.platesoft.auth.spi.OrgContextResolverTest`
|
||||||
- **Given:** No user-provided `OrgValidator` bean; default `PermissiveOrgValidator` in effect.
|
- **Given:** No user-provided `OrgValidator` bean; default `PermissiveOrgValidator` in effect.
|
||||||
- **When:** Resolving any `(org_type, org_id)`.
|
- **When:** Resolving any `(org_type, org_id)` — called N times.
|
||||||
- **Then:** Returns `true` (default-accept), logs a WARN once on startup that no `OrgValidator` is configured.
|
- **Then:** Returns `true` (default-accept) every time, and emits **one WARN log entry per call** with message containing `"OrgValidator default permissive — override de.platesoft.auth.spi.OrgValidator bean before production"`. Assert WARN count == N (not throttled, not one-shot).
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -202,7 +202,7 @@ Strategy: each integration test boots Spring with `@SpringBootTest(classes = Pla
|
|||||||
- **Class:** `de.platesoft.auth.flyway.PlateAuthFlywayMigrationIT`
|
- **Class:** `de.platesoft.auth.flyway.PlateAuthFlywayMigrationIT`
|
||||||
- **Given:** Empty Postgres 16 container.
|
- **Given:** Empty Postgres 16 container.
|
||||||
- **When:** Boot starter with default config; Flyway runs.
|
- **When:** Boot starter with default config; Flyway runs.
|
||||||
- **Then:** Schema contains tables `users`, `user_identities`, `memberships`, `invitations`, `access_requests`, `login_events`. `flyway_schema_history_auth` table has 5 rows (V1..V5). All migrations are non-failed.
|
- **Then:** Schema contains tables `users`, `user_identities`, `memberships`, `invitations`, `access_requests`, `login_events`, plus the index `idx_user_identities_microsoft_tenant_id` from V5. `flyway_schema_history_auth` table has **6 rows (V1..V6)**. All migrations are non-failed.
|
||||||
|
|
||||||
### T-IT02 — Auto-config wires required beans
|
### T-IT02 — Auto-config wires required beans
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user