docs(08): complete social sign-in execution

This commit is contained in:
Arthur Belleville 2026-05-15 21:13:59 +02:00
parent 6e6583636f
commit f9f528544d
No known key found for this signature in database
8 changed files with 417 additions and 27 deletions

View file

@ -9,12 +9,12 @@ Requirements for milestone v2.0. Each requirement must map to exactly one roadma
### Authentication ### Authentication
- [ ] **AUTH-08**: User can start a Google sign-in flow from the login/signup page - [x] **AUTH-08**: User can start a Google sign-in flow from the login/signup page
- [ ] **AUTH-09**: Google callback validates state, exchanges the authorization code, verifies the ID token, and creates or links a local Xtablo user - [x] **AUTH-09**: Google callback validates state, exchanges the authorization code, verifies the ID token, and creates or links a local Xtablo user
- [ ] **AUTH-10**: User can start an Apple sign-in flow from the login/signup page - [x] **AUTH-10**: User can start an Apple sign-in flow from the login/signup page
- [ ] **AUTH-11**: Apple callback validates state/nonce, exchanges the authorization code, verifies the ID token, and creates or links a local Xtablo user - [x] **AUTH-11**: Apple callback validates state/nonce, exchanges the authorization code, verifies the ID token, and creates or links a local Xtablo user
- [ ] **AUTH-12**: Social sign-in issues the same server-managed Xtablo session cookie used by email/password login - [x] **AUTH-12**: Social sign-in issues the same server-managed Xtablo session cookie used by email/password login
- [ ] **AUTH-13**: Existing email/password login, signup, logout, CSRF, and rate limiting continue to work after social sign-in is added - [x] **AUTH-13**: Existing email/password login, signup, logout, CSRF, and rate limiting continue to work after social sign-in is added
### Chat ### Chat
@ -95,7 +95,7 @@ Populated during roadmap creation.
| Requirement | Phase | Status | | Requirement | Phase | Status |
|-------------|-------|--------| |-------------|-------|--------|
| AUTH-08..13 | Phase 8 | Pending | | AUTH-08..13 | Phase 8 | Complete |
| ETAPE-01..06 | Phase 9 | Pending | | ETAPE-01..06 | Phase 9 | Pending |
| EVENT-01..05 | Phase 10 | Pending | | EVENT-01..05 | Phase 10 | Pending |
| PLAN-01..04 | Phase 11 | Pending | | PLAN-01..04 | Phase 11 | Pending |
@ -108,4 +108,4 @@ Populated during roadmap creation.
--- ---
*Requirements defined: 2026-05-15* *Requirements defined: 2026-05-15*
*Last updated: 2026-05-15 after v2.0 roadmap creation* *Last updated: 2026-05-15 after Phase 8 execution complete*

View file

@ -25,6 +25,7 @@
### Phase 8: Social Sign-in ### Phase 8: Social Sign-in
**Goal:** Users can sign in with Google or Apple while Xtablo keeps owning user accounts and sessions. **Goal:** Users can sign in with Google or Apple while Xtablo keeps owning user accounts and sessions.
**Mode:** mvp **Mode:** mvp
**Status:** Complete
**Requirements:** AUTH-08, AUTH-09, AUTH-10, AUTH-11, AUTH-12, AUTH-13 **Requirements:** AUTH-08, AUTH-09, AUTH-10, AUTH-11, AUTH-12, AUTH-13
**Success Criteria:** **Success Criteria:**
1. Login/signup page shows Google and Apple sign-in entry points alongside email/password 1. Login/signup page shows Google and Apple sign-in entry points alongside email/password

View file

@ -2,15 +2,15 @@
gsd_state_version: 1.0 gsd_state_version: 1.0
milestone: v2.0 milestone: v2.0
milestone_name: Collaboration, planning, and social sign-in milestone_name: Collaboration, planning, and social sign-in
status: executing status: ready_for_verification
last_updated: "2026-05-15T18:50:49.735Z" last_updated: "2026-05-15T19:13:18Z"
last_activity: 2026-05-15 -- Phase 08 planning complete last_activity: 2026-05-15 -- Phase 08 execution complete
progress: progress:
total_phases: 5 total_phases: 5
completed_phases: 0 completed_phases: 1
total_plans: 5 total_plans: 5
completed_plans: 0 completed_plans: 5
percent: 0 percent: 100
--- ---
# STATE # STATE
@ -24,20 +24,20 @@ progress:
See: `.planning/PROJECT.md` (updated 2026-05-15) See: `.planning/PROJECT.md` (updated 2026-05-15)
**Core value:** A user can sign in and run the Tablos workflow — organize work, attach files, discuss, and plan scheduled events — without a JS framework or managed chat provider. **Core value:** A user can sign in and run the Tablos workflow — organize work, attach files, discuss, and plan scheduled events — without a JS framework or managed chat provider.
**Current focus:** Phase 8 — Social Sign-in **Current focus:** Phase 9 — Etapes
## Current Position ## Current Position
Phase: 8 — Social Sign-in Phase: 8 — Social Sign-in
Plan: — Plan: —
Status: Ready to execute Status: Ready for verification
Last activity: 2026-05-15 -- Phase 08 planning complete Last activity: 2026-05-15 -- Phase 08 execution complete
## Phase Status ## Phase Status
| # | Phase | Status | | # | Phase | Status |
|---|-------|--------| |---|-------|--------|
| 8 | Social Sign-in | ○ Pending | | 8 | Social Sign-in | ✓ Complete |
| 9 | Etapes | ○ Pending | | 9 | Etapes | ○ Pending |
| 10 | Events | ○ Pending | | 10 | Events | ○ Pending |
| 11 | Individual Planning | ○ Pending | | 11 | Individual Planning | ○ Pending |
@ -45,7 +45,7 @@ Last activity: 2026-05-15 -- Phase 08 planning complete
## Verification Record ## Verification Record
No v2.0 verification records yet. - 2026-05-15: Phase 8 execution complete. Local verification passed with `go test ./... -count=1`; database-backed integration coverage skips unless `TEST_DATABASE_URL` is configured.
## Decisions ## Decisions
@ -84,6 +84,11 @@ No v2.0 verification records yet.
- **river deps as // indirect until Plan 02** — cmd/worker wiring in Plan 02 will promote river to direct dependency; expected Go module behavior (06-01) - **river deps as // indirect until Plan 02** — cmd/worker wiring in Plan 02 will promote river to direct dependency; expected Go module behavior (06-01)
- **signal.NotifyContext after rivermigrate and S3 init** — startup I/O uses context.Background(); signal context created after all I/O succeeds; prevents river.Client.Start receiving a pre-cancelled context (RESEARCH Pitfall 2) (06-02) - **signal.NotifyContext after rivermigrate and S3 init** — startup I/O uses context.Background(); signal context created after all I/O succeeds; prevents river.Client.Start receiving a pre-cancelled context (RESEARCH Pitfall 2) (06-02)
- **pool.Close() explicit after StopAndCancel, not via defer** — StopAndCancel fully returns before pool is closed; matches PATTERNS.md pool close ordering (06-02) - **pool.Close() explicit after StopAndCancel, not via defer** — StopAndCancel fully returns before pool is closed; matches PATTERNS.md pool close ordering (06-02)
- **Social-only users use NULL password_hash** — email/password login rejects them through the generic invalid-credentials path while provider sign-in owns the session path (08-01)
- **Verified provider identity links by provider subject first, then verified email** — prevents duplicate local users while keeping provider subject as the strongest identity key (08-02)
- **Apple callback uses GET/query response mode for the first working version** — keeps the callback inside existing CSRF middleware boundaries; Apple dashboard configuration must match (08-03)
- **Provider buttons degrade to disabled controls when config is missing** — auth pages remain deployable without provider credentials (08-04)
- **Account providers page is read-only in Phase 8** — linked identity visibility shipped before unlink/add-password account management (08-05)
## Performance Metrics ## Performance Metrics
@ -105,6 +110,11 @@ No v2.0 verification records yet.
| 06-background-worker | 01 | ~15min | 2 | 9 | | 06-background-worker | 01 | ~15min | 2 | 9 |
| Phase 06-background-worker P01 | ~15min | 2 tasks | 9 files | | Phase 06-background-worker P01 | ~15min | 2 tasks | 9 files |
| 06-background-worker | 02 | ~10min | 2 | 3 | | 06-background-worker | 02 | ~10min | 2 | 3 |
| Phase 08 P01 | 25min | 2 tasks | 8 files |
| Phase 08 P02 | 35min | 2 tasks | 9 files |
| Phase 08 P03 | 30min | 2 tasks | 7 files |
| Phase 08 P04 | 20min | 2 tasks | 8 files |
| Phase 08 P05 | 20min | 2 tasks | 7 files |
## Notes ## Notes
@ -142,13 +152,12 @@ No v2.0 verification records yet.
- Commits (06-01): 62e5e3e (river dep + ListOrphanFiles sqlc query), a1c2828 (internal/jobs package + unit tests) - Commits (06-01): 62e5e3e (river dep + ListOrphanFiles sqlc query), a1c2828 (internal/jobs package + unit tests)
- Phase 6 Plan 02 SUMMARY: `.planning/phases/06-background-worker/06-02-SUMMARY.md` - Phase 6 Plan 02 SUMMARY: `.planning/phases/06-background-worker/06-02-SUMMARY.md`
- Commits (06-02): 6e70478 (cmd/worker full river wiring), e202ad3 (just worker target + README docs) - Commits (06-02): 6e70478 (cmd/worker full river wiring), e202ad3 (just worker target + README docs)
- Phase 8 Plan 01 SUMMARY: `.planning/phases/08-social-sign-in/08-01-SUMMARY.md`
- Phase 8 Plan 02 SUMMARY: `.planning/phases/08-social-sign-in/08-02-SUMMARY.md`
- Phase 8 Plan 03 SUMMARY: `.planning/phases/08-social-sign-in/08-03-SUMMARY.md`
- Phase 8 Plan 04 SUMMARY: `.planning/phases/08-social-sign-in/08-04-SUMMARY.md`
- Phase 8 Plan 05 SUMMARY: `.planning/phases/08-social-sign-in/08-05-SUMMARY.md`
- Commits (08): 2d004cd (social identity schema foundation), 6779663 (Google sign-in), a8b6a03 (Apple sign-in), 59fd6b1 (auth page provider controls), 6e65836 (account providers view + docs)
--- ---
*Last updated: 2026-05-15 after Phase 4 Plan 03 complete (Wave 3 — inline task edit + drag-and-drop reorder, all 9 TestTask* tests active)* *Last updated: 2026-05-15 after Phase 8 execution complete*
## Current Position
Phase: Not started (defining requirements)
Plan: —
Status: Defining requirements
Last activity: 2026-05-15 — Milestone v2.0 started

View file

@ -0,0 +1,78 @@
---
phase: 08-social-sign-in
plan: 01
subsystem: auth-database
tags: [postgres, sqlc, nullable-passwords, social-identities]
requires:
- phase: 02-authentication
provides: local users, password auth, and database-backed sessions
provides:
- nullable password hashes for social-only users
- user_identities schema and sqlc query contracts
- social-only login/signup regression handling
affects: [auth, google-sign-in, apple-sign-in, account-providers]
tech-stack:
added: []
patterns: [provider-subject identity table, nullable password_hash handling]
key-files:
created:
- backend/migrations/0006_social_identities.sql
- backend/internal/db/queries/user_identities.sql
- backend/internal/web/social_identity_migration_test.go
- backend/internal/web/social_identity_schema_test.go
modified:
- backend/internal/db/queries/users.sql
- backend/internal/auth/types.go
- backend/internal/web/handlers_auth.go
- backend/internal/web/handlers_auth_test.go
key-decisions:
- "Social-only users use NULL password_hash; password login treats NULL as generic invalid credentials."
- "Provider identity is keyed by unique (provider, provider_subject)."
patterns-established:
- "Provider metadata lives in user_identities; local users and sessions remain authoritative."
requirements-completed: [AUTH-09, AUTH-11, AUTH-12, AUTH-13]
duration: 25min
completed: 2026-05-15
---
# Phase 8 Plan 01: Social Identity Schema Summary
**Postgres user identity foundation with nullable passwords, provider-subject uniqueness, and social-only auth safeguards**
## Performance
- **Duration:** ~25 min
- **Started:** 2026-05-15T18:51:00Z
- **Completed:** 2026-05-15T19:16:00Z
- **Tasks:** 2
- **Files modified:** 8
## Accomplishments
- Added `user_identities` with provider subject uniqueness and provider metadata.
- Made `users.password_hash` nullable and regenerated sqlc locally.
- Updated signup/login behavior for social-only users.
- Added schema and auth regression tests.
## Task Commits
1. **Schema and nullable auth foundation** - `2d004cd` (`feat(08-01)`)
## Deviations from Plan
Combined the two Plan 01 tasks into one production commit because sqlc nullable type changes require auth compile fixes in the same buildable state.
**Total deviations:** 1 process deviation. **Impact:** No scope change; kept the repository buildable.
## Issues Encountered
Integration tests that require Postgres skip locally without `TEST_DATABASE_URL`; fast migration contract tests cover local verification.
## User Setup Required
None.
## Next Phase Readiness
Ready for Google and Apple callback flows to call the shared local account-linking path.

View file

@ -0,0 +1,79 @@
---
phase: 08-social-sign-in
plan: 02
subsystem: auth-oauth
tags: [google, oauth2, oidc, sessions]
requires:
- phase: 08-social-sign-in
provides: nullable users and user_identities
provides:
- Google OAuth start and callback routes
- OAuth state and nonce cookies
- mockable token exchange and ID token verifier interfaces
affects: [auth-ui, apple-sign-in, account-providers]
tech-stack:
added: [golang.org/x/oauth2, github.com/coreos/go-oidc/v3/oidc]
patterns: [provider verifier interface, transaction account linking]
key-files:
created:
- backend/internal/auth/oauth.go
- backend/internal/auth/oauth_test.go
- backend/internal/web/handlers_social.go
- backend/internal/web/handlers_social_test.go
modified:
- backend/cmd/web/main.go
- backend/internal/web/handlers_auth.go
- backend/internal/web/router.go
- backend/go.mod
- backend/go.sum
key-decisions:
- "Google provider tokens are verification evidence only; Xtablo still issues the local session cookie."
- "Provider subject wins after link; email conflicts update identity metadata without relinking."
patterns-established:
- "OAuth handlers depend on fakeable CodeExchanger and IDTokenVerifier interfaces."
requirements-completed: [AUTH-08, AUTH-09, AUTH-12, AUTH-13]
duration: 35min
completed: 2026-05-15
---
# Phase 8 Plan 02: Google Social Sign-in Summary
**Google OAuth/OIDC sign-in with state and nonce cookies, verified-email linking, and local Xtablo session issuance**
## Performance
- **Duration:** ~35 min
- **Started:** 2026-05-15T19:16:00Z
- **Completed:** 2026-05-15T19:51:00Z
- **Tasks:** 2
- **Files modified:** 9
## Accomplishments
- Added Google provider config and env wiring.
- Added OAuth state/nonce cookie helpers and OIDC verifier support.
- Added `/auth/google/start` and `/auth/google/callback`.
- Added tests for start redirect, invalid state, unverified email, verified linking, social-only creation, subject precedence, and conflict handling.
## Task Commits
1. **Google social sign-in flow** - `6779663` (`feat(08-02)`)
## Deviations from Plan
Combined Google primitives and handler wiring into one production commit because the handler tests compile against the newly introduced auth interfaces.
**Total deviations:** 1 process deviation. **Impact:** No functional scope change.
## Issues Encountered
DB-backed linking tests skip locally without `TEST_DATABASE_URL`; non-DB OAuth tests run in the default suite.
## User Setup Required
Google OAuth credentials are documented in Plan 05 docs.
## Next Phase Readiness
Apple can reuse the same provider claim and account-linking machinery.

View file

@ -0,0 +1,76 @@
---
phase: 08-social-sign-in
plan: 03
subsystem: auth-oauth
tags: [apple, oauth2, oidc, es256, go-jose]
requires:
- phase: 08-social-sign-in
provides: shared OAuth primitives and account linking
provides:
- Apple provider config and ES256 client-secret generation
- Apple start and callback routes
- nonce-protected Apple ID token verification path
affects: [auth-ui, account-providers]
tech-stack:
added: [github.com/go-jose/go-jose/v4]
patterns: [Apple client-secret signing, provider-specific callback over shared linker]
key-files:
created: []
modified:
- backend/internal/auth/oauth.go
- backend/internal/auth/oauth_test.go
- backend/internal/web/handlers_social.go
- backend/internal/web/handlers_social_test.go
- backend/internal/web/router.go
- backend/cmd/web/main.go
key-decisions:
- "Apple callback uses GET with state and nonce to preserve existing CSRF middleware for local POST forms."
- "Apple private relay emails are accepted when the provider marks them verified."
patterns-established:
- "Apple first-login name is treated as display metadata only."
requirements-completed: [AUTH-10, AUTH-11, AUTH-12, AUTH-13]
duration: 30min
completed: 2026-05-15
---
# Phase 8 Plan 03: Apple Social Sign-in Summary
**Sign in with Apple flow using ES256 client-secret JWTs, nonce validation, verified relay email support, and local sessions**
## Performance
- **Duration:** ~30 min
- **Started:** 2026-05-15T19:51:00Z
- **Completed:** 2026-05-15T20:21:00Z
- **Tasks:** 2
- **Files modified:** 7
## Accomplishments
- Added Apple config, private-key normalization, and client-secret signing.
- Added `/auth/apple/start` and `/auth/apple/callback`.
- Extended verifier claim parsing to accept boolean or string `email_verified`.
- Added tests for Apple config, client-secret claims, start redirect, nonce rejection, unverified email, and relay/name persistence.
## Task Commits
1. **Apple social sign-in flow** - `a8b6a03` (`feat(08-03)`)
## Deviations from Plan
Used a GET callback rather than `form_post` to avoid broad CSRF middleware changes. OAuth state and ID-token nonce remain the callback defense.
**Total deviations:** 1 architecture-light deviation. **Impact:** Keeps local form CSRF untouched; Apple dashboard callback mode must match this route.
## Issues Encountered
None beyond local DB-backed tests skipping without `TEST_DATABASE_URL`.
## User Setup Required
Apple Services ID, Team ID, Key ID, private key, and redirect URL are documented in Plan 05 docs.
## Next Phase Readiness
Both provider start routes are ready for login/signup UI entry points.

View file

@ -0,0 +1,72 @@
---
phase: 08-social-sign-in
plan: 04
subsystem: auth-ui
tags: [templ, htmx, css, social-sign-in]
requires:
- phase: 08-social-sign-in
provides: Google and Apple start routes
provides:
- provider buttons on login and signup
- disabled provider states for missing config
- neutral provider button CSS
affects: [auth, account-providers]
tech-stack:
added: []
patterns: [provider button block above HTMX auth forms]
key-files:
created: []
modified:
- backend/templates/auth_forms.go
- backend/templates/auth_login.templ
- backend/templates/auth_signup.templ
- backend/internal/web/handlers_auth.go
- backend/internal/web/ui/button.css
key-decisions:
- "Provider buttons render on full auth pages; HTMX swaps continue to target only the email/password form fragment."
patterns-established:
- "Missing provider config keeps visible disabled buttons with no actionable href."
requirements-completed: [AUTH-08, AUTH-10, AUTH-13]
duration: 20min
completed: 2026-05-15
---
# Phase 8 Plan 04: Auth Provider UI Summary
**Login and signup pages with equal Google and Apple entry points, neutral styling, and disabled missing-config states**
## Performance
- **Duration:** ~20 min
- **Started:** 2026-05-15T20:21:00Z
- **Completed:** 2026-05-15T20:41:00Z
- **Tasks:** 2
- **Files modified:** 8
## Accomplishments
- Added provider button data structures and handler propagation.
- Rendered Google and Apple controls on login and signup.
- Added separator copy `or` and neutral outline CSS.
- Added tests for configured and disabled login/signup provider states.
## Task Commits
1. **Provider controls on auth pages** - `59fd6b1` (`feat(08-04)`)
## Deviations from Plan
None - plan executed exactly as written.
## Issues Encountered
None.
## User Setup Required
None.
## Next Phase Readiness
Account provider status view can use the stored identities from social callbacks.

View file

@ -0,0 +1,75 @@
---
phase: 08-social-sign-in
plan: 05
subsystem: account-ui-docs
tags: [templ, account, env-docs, regression]
requires:
- phase: 08-social-sign-in
provides: user_identities and provider callbacks
provides:
- protected linked providers account view
- Google and Apple env documentation
- final Phase 8 regression evidence
affects: [account, auth, deployment]
tech-stack:
added: []
patterns: [fixed provider status rows, placeholder-only env docs]
key-files:
created:
- backend/internal/web/handlers_account.go
- backend/internal/web/handlers_account_test.go
- backend/templates/account_providers.go
- backend/templates/account_providers.templ
modified:
- backend/internal/web/router.go
- backend/.env.example
- backend/README.md
key-decisions:
- "Linked providers view is status-only; unlink and add-password actions remain deferred."
patterns-established:
- "Provider docs use placeholders only; missing config keeps disabled provider buttons visible."
requirements-completed: [AUTH-08, AUTH-09, AUTH-10, AUTH-11, AUTH-12, AUTH-13]
duration: 20min
completed: 2026-05-15
---
# Phase 8 Plan 05: Linked Providers and Docs Summary
**Protected linked-provider status page with Google/Apple rows, placeholder provider env docs, and full backend regression coverage**
## Performance
- **Duration:** ~20 min
- **Started:** 2026-05-15T20:41:00Z
- **Completed:** 2026-05-15T21:01:00Z
- **Tasks:** 2
- **Files modified:** 7
## Accomplishments
- Added `GET /account/providers` behind `auth.RequireAuth`.
- Rendered `Linked providers` with Google and Apple status rows.
- Added Google and Apple placeholder env vars to `.env.example`.
- Updated README with provider config and disabled-button behavior.
- Ran `go test ./... -count=1` successfully.
## Task Commits
1. **Linked providers view and provider docs** - `6e65836` (`feat(08-05)`)
## Deviations from Plan
None - plan executed exactly as written.
## Issues Encountered
DB-backed linked-provider row test skips locally without `TEST_DATABASE_URL`; unauthenticated route protection and full compile/regression coverage pass locally.
## User Setup Required
External provider dashboards must be configured before live Google/Apple sign-in works. Required env vars are listed in `backend/.env.example`.
## Next Phase Readiness
Phase 8 is ready for verification. Phase 9 can build on local users, sessions, and auth UI without needing a managed auth provider.