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
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.
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>
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>
- Replace testRoot template assertion with 'health endpoint returns 200 with status ok'
- Compose only configureRouting() in testApplication — NOT Application.module()
- This keeps the test independent of Database.migrate / running Postgres (D-11 test invariant)
- Install ContentNegotiation { json() } inside application { } — production module() does it,
but the test composes routing directly and must install the plugin itself
- All imports explicit (D-11 allWarningsAsErrors); no wildcards
- Body checked via substring for "status" + "ok" — robust to JSON field ordering
Note: ./gradlew :server:test runtime verification deferred to Plan 07 (integration build)
since build-logic/recipe.jvm.server plugin is being authored in parallel Plan 02 worktree.
- Create MainApplication : Application() running configureLogging() then initKoin { androidContext(this@MainApplication) } in onCreate
- Register android:name=".MainApplication" on <application> element (MainActivity entry preserved)
- Establishes the canonical init order for Android process boot
- Single postgres service pinned to postgres:16
- Credentials recipe/recipe/recipe match application.conf HOCON defaults
- Named volume recipe-pgdata for persistence across restarts
- Healthcheck via pg_isready enables docker compose up --wait usage
- No version key (modern compose v2); Authentik stays on homelab (D-17)
Three executable bash scripts under tools/ that Wave 0 and every
subsequent Phase 1 plan's <automated> block rely on:
- verify-no-version-literals.sh (INFRA-01 SC#2 / D-09): no literal
library/plugin version strings in any *.gradle.kts. Excludes
build-logic/build.gradle.kts (needs asDependency() literals) and
top-level project-version assignments ("^version = \"x.y.z\"")
which are artifact metadata, not library pins.
- verify-shared-pure.sh (INFRA-06 / D-19): shared/commonMain must
not import Ktor/Compose/SQLDelight. Returns OK if the directory
does not exist yet (pre-scaffold tolerance for Plan 07).
- verify-ios-flags.sh (INFRA-03 / D-18): both K/N iOS binary flags
present in gradle.properties.
All three use bash (#!/usr/bin/env bash + set -euo pipefail) and
are marked chmod +x. Scripts exit 0 against the current repo state.