Commit Graph

89 Commits

Author SHA1 Message Date
06e5eaf94e test(02-06): add failing auth session state tests
- cover restore, login, refresh failure, logout, and cancellation
- assert Phase 2 authenticated householdId remains null
2026-04-28 16:53:46 +02:00
b364c3056e docs(02-05): complete iOS auth actuals plan
- Summarize iOS AppAuth and Keychain implementation
- Record verification results and deviations
2026-04-28 16:21:01 +02:00
88dc8d719a feat(02-05): wire iOS OIDC callback
- Register recipe URL scheme in Info.plist
- Forward SwiftUI openURL callbacks to the AppAuth bridge
2026-04-28 16:18:21 +02:00
ac9fc61410 feat(02-05): implement iOS AppAuth client
- Add AppAuth login, refresh, logout actual
- Add iOS Keychain auth state store to unblock native compile
- Add iOS Podfile AppAuth integration
2026-04-28 16:14:04 +02:00
8d1c34c2f6 docs(02-04): complete Android auth actuals plan
- Add execution summary with verification results
- Document Android expect/actual ordering deviation and token mapping fix
2026-04-28 16:01:57 +02:00
11a5eeb3ff fix(02-04): harden Android OIDC token result mapping
- Treat missing access tokens as auth failures
- Preserve AppAuth discovery errors for correct network/auth classification
2026-04-28 16:00:20 +02:00
6385453653 feat(02-04): register Android OIDC callback
- Add AppAuth redirect receiver for recipe://callback
- Preserve existing launcher activity manifest wiring
2026-04-28 15:58:12 +02:00
fa78ee31b4 feat(02-04): implement Android AppAuth OIDC client
- Add Android AppAuth login, fresh-token refresh, and end-session logout
- Add Android secure AuthState store actual required for Android compilation
2026-04-28 15:57:16 +02:00
a94f803ca6 docs(02-03): complete common auth seams plan
Tasks completed: 2/2
- Define common OIDC and secure store contracts
- Add JVM and Wasm actuals

SUMMARY: .planning/phases/02-authentication-foundation/02-03-SUMMARY.md
2026-04-28 14:16:47 +02:00
0dbd374f46 feat(02-03): add Wasm auth stubs
- Keep Wasm OIDC behind explicit v2 NotImplementedError boundaries
- Add non-persistent Wasm AuthState store actual so the target compiles
2026-04-28 13:49:14 +02:00
edc2a1d4c8 feat(02-03): define common auth contracts
- Add OIDC result and expect client seam with pinned native AppAuth semantics
- Add secure AuthState JSON store contract and JVM dev actuals for test compilation
2026-04-28 13:48:25 +02:00
3122fdaf37 docs(02-02): complete server auth boundary plan
- add execution summary with verification and deviations

- update state, roadmap progress, and completed auth requirements
2026-04-28 13:46:46 +02:00
7ef222e71e test(02-03): add failing secure auth state store contract
- Covers write overwrite semantics
- Covers clear removing stored AuthState JSON
2026-04-28 13:36:48 +02:00
8cf112a68a feat(02-02): add users migration, JIT PrincipalResolver, /api/v1/me route 2026-04-28 13:14:59 +02:00
36c1b2c822 feat(02-02): wire AuthConfig, JWT verifier, and CallLogging redaction 2026-04-28 13:06:50 +02:00
614b57c34d test(02-02): add failing JWT validation tests for AuthPlugin 2026-04-28 13:04:04 +02:00
fe8c0b6823 docs(phase-02): update tracking after wave 1 2026-04-28 11:00:51 +02:00
9f7cadda7b docs(02-01): complete shared auth contracts and Authentik setup plan
Adds the per-plan SUMMARY for 02-01: shared MeResponse/User DTOs +
Constants, full Phase 2 dependency catalog wired into composeApp/
server without bumping Ktor 3.4.1, and docs/authentik-setup.md
reproducible-provider playbook with multi-source audit.

3 tasks (Task 1 ran TDD: RED + GREEN), 4 commits, 6 deviations
auto-fixed (5 × Rule 3 blocking, 1 × Rule 1 bug), 0 scope creep.
All plan-level verifications PASS.

Per parallel-execution rules, this commit does not modify STATE.md
or ROADMAP.md — the orchestrator owns those updates after the wave
completes.
2026-04-28 10:59:07 +02:00
62040d461a docs(02-01): add Authentik provider setup and Phase 2 source audit
Task 02-01-03. Creates docs/authentik-setup.md as the load-bearing
Phase 2 deliverable (D-10): a reproducible playbook for the
homelab Authentik provider plus the multi-source audit that ties
every Phase 2 input to a covering plan.

Sections (in mandated order):
- Provider — Public + PKCE S256, recipe-app client_id, RS256, single-
  string aud, JWKS URI, end-session endpoint, Issuer trailing slash.
- Scopes — exactly `openid profile email offline_access`; explains
  why offline_access must be both requested AND mapped on the
  provider for refresh tokens (PITFALLS.md Phase 2 Pitfall 2).
- Redirect URI — recipe://callback, registered byte-for-byte in
  Authentik + iOS Info.plist + Android <intent-filter>.
- Server Env Vars — OIDC_ISSUER / OIDC_AUDIENCE / OIDC_JWKS_URL with
  override semantics matching Phase 1's DATABASE_URL pattern.
- Logout — RP-initiated end-session sequence (D-19, D-20).
- Manual UAT — UAT-01 fresh login, UAT-02 reopen with refresh,
  UAT-03 logout returns to login, UAT-04 curl/HTTP verification of
  GET /api/v1/me 200/401 cases including wrong-aud and never-log-
  Authorization assertion.
- Source Audit — exhaustive table mapping GOAL Phase 2, REQ
  AUTH-01..AUTH-06, RESEARCH constraints, CONTEXT D-01..D-34,
  UI-SPEC, VALIDATION Wave 0, and PATTERNS file map to either this
  doc () or a downstream Phase 2 plan (⤳). All deferred ideas
  listed as ✂ excluded: Universal Links/App Links, real Desktop
  OIDC, Wasm OIDC, Apple Sign-in, Authentik provisioning automation,
  per-user AuthState, modal refresh-failure UX, background refresh,
  two-tier logout, BuildConfig OIDC injection, real-Authentik
  integration tests.

Verification:
- grep -E 'openid profile email offline_access|PKCE S256|single-string
  |recipe://callback|/api/v1/me|Source Audit' docs/authentik-setup.md:
  hits all six tokens.
- All Task 3 grep acceptance criteria PASS, including
  AUTH-01.*AUTH-02.*AUTH-03.*AUTH-04.*AUTH-05.*AUTH-06 on a single
  audit-table line and "Universal Links / App Links.*excluded".
2026-04-28 10:55:38 +02:00
c1cc713bbb feat(02-01): wire Phase 2 dependency aliases without bumping Ktor
Task 02-01-02. Adds Phase 2 deps to the version catalog and routes
them into composeApp + server build files. Ktor stays pinned at
3.4.1 per the resolved Open Question — patch bump deferred unless a
concrete incompatibility appears.

Catalog (gradle/libs.versions.toml):
- Versions: appauth, appauth-ios, androidx-security-crypto, exposed,
  hikari, multiplatformSettings, testcontainers, plus the
  kotlinCocoapods plugin alias.
- Libraries: ktor server auth/auth-jwt/call-logging/status-pages,
  ktor client core/auth/content-negotiation/logging/okhttp/darwin/cio,
  ktor-serializationKotlinxJsonMpp (the multiplatform variant; the
  -jvm one stays for server), AppAuth, AndroidX Security Crypto,
  multiplatform-settings + coroutines, Exposed core/jdbc/java-time,
  HikariCP, Testcontainers postgresql + junit-jupiter.

composeApp/build.gradle.kts:
- Apply kotlinSerialization (alias) and kotlin.native.cocoapods (by
  id — the plugin is shipped inside the Kotlin Gradle plugin already
  on the classpath via recipe.kotlin.multiplatform; alias-applying
  it would request a fresh version and fail).
- Cocoapods block: ComposeApp baseName + isStatic, ../iosApp/Podfile,
  iOS deployment target 15.0, AppAuth pod pulled from
  libs.versions.appauth.ios.get() — no literal pin in the build
  file (verify-no-version-literals.sh stays green).
- Common deps: Ktor client family, MPP serialization, multiplatform
  settings; Android: AppAuth-Android + Security Crypto + OkHttp
  engine; iOS: Darwin engine; JVM: CIO engine.

server/build.gradle.kts: Adds Ktor server auth/JWT/CallLogging/
StatusPages, Exposed DSL trio, Hikari, kotlinx.serialization-json,
plus testImplementation testcontainers postgresql + junit-jupiter.

Deviations:
- Rule 3 (blocking): manifestPlaceholders["appAuthRedirectScheme"]
  = "recipe" added to Android defaultConfig because AppAuth-Android's
  bundled manifest declares a ${appAuthRedirectScheme} placeholder
  that breaks AGP merge before Plan 02-04 lands the full <intent-filter>.
- Rule 3 (blocking): top-level group/version on composeApp (required
  by the cocoapods podspec generator) pushes the Compose Resources
  Res-class package off recipe.composeapp.generated.resources, breaking
  Phase 1 App.kt imports. Lock the package via compose.resources {
  packageOfResClass = "recipe.composeapp.generated.resources" }.
- Rule 3 (housekeeping): *.podspec is generated by the cocoapods
  plugin on every build; ignored.

Verification:
- ./gradlew :composeApp:dependencies --configuration debugCompileClasspath
  :server:dependencies --configuration runtimeClasspath: PASS
  (the plan-stated androidMainCompileClasspath name doesn't exist
  under this AGP/Gradle combo; debugCompileClasspath is the
  functional equivalent and resolves all new deps).
- ./gradlew :composeApp:compileDebugKotlinAndroid :server:compileKotlin: PASS
- ./gradlew :composeApp:compileKotlinIosSimulatorArm64: PASS (cinterop
  pulls AppAuth pod cleanly).
- ./tools/verify-no-version-literals.sh: PASS
- ./tools/verify-shared-pure.sh: PASS
- All Task 2 grep acceptance criteria satisfied.
2026-04-28 10:52:40 +02:00
7e73a9a820 feat(02-01): land Constants and MeResponse/User DTOs in shared
GREEN phase of TDD task 02-01-01. Adds the load-bearing Phase 2
contract that downstream plans compile against:

- Constants.kt: OIDC_ISSUER (trailing slash, placeholder homelab host),
  OIDC_CLIENT_ID = recipe-app, OIDC_REDIRECT_URI = recipe://callback,
  API_BASE_URL, plus moved SERVER_PORT for one shared config object.
- dto/User.kt: domain identity (id/sub/email/displayName), id is String
  to keep shared free of UUID library deps (D-19 / INFRA-06).
- dto/MeResponse.kt: @Serializable wire DTO for GET /api/v1/me with a
  one-to-one toUser() mapper. Stable for Phase 3 to add householdId
  via ignoreUnknownKeys.
- Removes the now-redundant shared/.gitkeep placeholder.

Verification:
- ./gradlew :shared:jvmTest :shared:compileCommonMainKotlinMetadata: PASS
- ./tools/verify-shared-pure.sh: PASS
- All grep acceptance criteria for Task 1 satisfied
2026-04-28 10:45:04 +02:00
6504b46e40 test(02-01): add failing serialization test for MeResponse DTO
RED phase of TDD task 02-01-01. Locks the wire-format contract for
GET /api/v1/me before the DTO exists:

- camelCase JSON keys (id, sub, email, displayName) per D-27
- ignoreUnknownKeys forward compat for Phase 3 householdId per D-28
- MeResponse.toUser() one-to-one mapping

Wires kotlinx.serialization into shared/build.gradle.kts (api scope so
both client and server inherit the @Serializable runtime) and adds the
kotlinx-serializationJson catalog alias. The shared module remains
pure: only kotlin stdlib + kotlinx.serialization-json are pulled into
commonMain (D-19 / INFRA-06 still holds).

Test currently fails: MeResponse and User unresolved; GREEN follows.
2026-04-28 10:43:15 +02:00
1246e12012 docs(state): mark phase 2 ready for execution 2026-04-28 10:31:02 +02:00
37450291c6 docs(02): fix auth plan verification blockers 2026-04-27 21:11:46 +02:00
0b01bc8bbb fix(02): split auth platform plans 2026-04-27 21:07:18 +02:00
f0462cbca1 docs(02): add missing auth store actuals to plan 2026-04-27 20:59:41 +02:00
29d655828d docs(02): resolve planning verification artifacts 2026-04-27 20:57:05 +02:00
cca3ab7923 docs(02): create authentication foundation plans 2026-04-27 20:54:21 +02:00
ab69cc1dff docs(02): add validation strategy 2026-04-27 20:42:04 +02:00
090027224c docs(02): research phase domain 2026-04-27 20:41:15 +02:00
6ab7960e16 docs(02): approve UI design contract
UI-SPEC verified — all 6 dimensions PASS. No flags. Frontmatter
status flipped from draft to approved.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-27 20:02:19 +02:00
31b4f4d57e docs(02): UI design contract for auth foundation
Locks scaffold-level visual contract for Phase 2: spacing scale,
typography roles, Material 3 color seed, copywriting keys, and
auth-gate routing — without committing to Liquid-Glass / Haze
(Phase 10) or final font + Polish polish (Phase 11).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-27 19:59:41 +02:00
830097f5c1 docs(state): record phase 2 context session 2026-04-27 19:29:04 +02:00
f3569b41d6 docs(02): capture phase context 2026-04-27 19:28:57 +02:00
04b3d9b1d5 Remove unnecessary convention plugins 2026-04-26 22:22:28 +02:00
42d134a997 docs(01-07): complete phase gate plan 2026-04-24 20:59:21 +02:00
68655eae1a Phase 1 work 2026-04-24 20:21:03 +02:00
b36058fa79 chore(01-07): add shared package scaffold placeholder
- Create dev.ulfrx.recipe.shared sub-package with .gitkeep marker
- Phase 2+ will populate with cross-target DTOs / domain models
- Satisfies INFRA-06 file-existence criterion for empty package scaffold
2026-04-24 19:46:30 +02:00
81bff1db17 merge(01-04): Koin + Kermit bootstrap across all platforms 2026-04-24 19:45:25 +02:00
eaa88fff36 docs(01-04): add SUMMARY for Koin + Kermit bootstrap plan 2026-04-24 19:44:47 +02:00
fd3e7e1584 feat(01-04): wire JVM + Wasm main + Swift iOSApp to bootstrap Koin + Kermit
- JVM main: configureLogging() + initKoin() before application { Window }
- Wasm main: configureLogging() + initKoin() before ComposeViewport (PITFALL #8)
- iOSApp.swift: import ComposeApp + init { KoinIosKt.doInitKoin() } (PITFALL #4)
2026-04-24 19:41:51 +02:00
129ee616d5 docs(01-05): add SUMMARY for server /health + Flyway + HOCON plan 2026-04-24 19:41:47 +02:00
8cd608a981 feat(01-04): add Android MainApplication + manifest registration
- MainApplication.onCreate calls configureLogging() then initKoin { androidContext(...) }
- AndroidManifest registers android:name=".MainApplication"
2026-04-24 19:41:22 +02:00
cc5002d1df feat(01-04): add Koin + Kermit bootstrap commonMain + iOS bridge
- initKoin() helper with optional KoinAppDeclaration config
- empty appModule placeholder (Phase 2+ extends)
- configureLogging() sets Kermit tag 'recipe' (D-15)
- iOS doInitKoin() bridge → Swift symbol KoinIosKt.doInitKoin
2026-04-24 19:41:05 +02:00
d7ee6b83fc Add summary for plan phase 1.2 2026-04-24 19:26:41 +02:00
61885455bb merge(01-06): docker-compose + README Local development 2026-04-24 18:41:51 +02:00
6972839fd0 merge(01-05): server /health + Flyway + HOCON + fail-loud DB boot 2026-04-24 18:41:51 +02:00
c79f9218aa merge(01-03): module refactor to recipe.* conventions + drop js 2026-04-24 18:41:51 +02:00
2c786b2fc2 merge(01-02): build-logic scaffold + 5 precompiled plugins 2026-04-24 18:41:43 +02:00
f9d3a0c2d4 docs(01-06): add SUMMARY for dev-ergonomics plan 2026-04-24 18:24:24 +02:00