# Phase 8: Social Sign-in - Pattern Map

**Generated:** 2026-05-15
**Purpose:** Map Phase 8 files to closest existing codebase analogs before execution.

## File Pattern Map

| Target file | Role | Closest existing analogs | Pattern to preserve |
|-------------|------|--------------------------|---------------------|
| `backend/migrations/0006_social_identities.sql` | Auth schema migration | `backend/migrations/0002_auth.sql`, `backend/migrations/0004_tasks.sql` | Goose SQL migration with `-- +goose Up/Down`, citext-friendly auth schema, explicit constraints and indexes |
| `backend/internal/db/queries/user_identities.sql` | sqlc identity persistence queries | `backend/internal/db/queries/users.sql`, `backend/internal/db/queries/sessions.sql` | Small named queries with typed params, no dynamic SQL, transaction-safe use through generated `WithTx` |
| `backend/internal/db/queries/users.sql` | Nullable password and lookup changes | Existing `users.sql` | Preserve `InsertUser`/`GetUserByEmail` names only if sqlc call sites are updated together |
| `backend/internal/auth/types.go` | Domain user shape | Existing `auth.User` | Mirror sqlc nullable password shape without treating social-only users as password users |
| `backend/internal/auth/session.go` | Session lookup/store mapping | Existing `auth.Store` methods | Keep local DB-backed sessions authoritative; provider tokens never become sessions |
| `backend/internal/auth/oauth.go` | Provider config, state, nonce, and verifier contracts | `backend/internal/auth/csrf.go`, `backend/internal/auth/password.go`, `backend/internal/auth/session.go` | Package-local auth primitives with unit tests, standard Go error handling |
| `backend/internal/auth/oauth_test.go` | Auth primitive tests | `backend/internal/auth/csrf_test.go`, `backend/internal/auth/password_test.go`, `backend/internal/auth/session_test.go` | Table-driven tests, no real provider network calls |
| `backend/internal/web/handlers_social.go` | OAuth start/callback handlers | `backend/internal/web/handlers_auth.go`, `backend/internal/web/handlers_tasks.go` | Dependency struct injection, clear redirects, form/callback parsing compatible with CSRF middleware |
| `backend/internal/web/handlers_social_test.go` | OAuth handler tests | `backend/internal/web/handlers_auth_test.go`, `backend/internal/web/handlers_tasks_test.go` | `httptest` handler coverage, local DB/test deps, no real Google/Apple calls |
| `backend/templates/auth_login.templ` | Login provider buttons | Existing `LoginPage` template | Keep centered `w-full max-w-sm` auth card and existing error rendering |
| `backend/templates/auth_signup.templ` | Signup provider buttons | Existing `SignupPage` template | Same provider block as login, existing signup validation preserved |
| `backend/templates/auth_forms.go` | Template data structs | Existing login/signup form structs | Add provider status/error data without echoing passwords or tokens |
| `backend/internal/web/ui/button.css` | Neutral provider button styling | Existing local UI button CSS | Add neutral outline/disabled state with stable 44px height, no broad design-system rewrite |
| `backend/templates/account_providers.templ` | Linked providers view | `backend/templates/tablos_list.templ`, `backend/templates/layout.templ` | Protected app surface, simple rows, no nested cards or unlink controls |
| `backend/cmd/web/main.go` | Provider env wiring | Existing env parsing for `SESSION_SECRET`, S3, upload size | Read env vars once at startup, no secret values in logs |
| `backend/internal/web/router.go` | Route registration | Existing auth and protected route groups | Start/callback routes outside `RequireAuth`, account status route inside `RequireAuth`, static routes before parametric routes |
| `backend/.env.example`, `backend/README.md` | Operator docs | Existing env docs | Placeholder config only, no secrets, local missing-config behavior documented |

## Data Flow Pattern

1. Browser clicks `/auth/{provider}/start`.
2. Handler validates provider config, creates state/nonce, stores them in short-lived HTTP-only cookies, and redirects to provider.
3. Callback validates state and nonce, exchanges the code, verifies the ID token, and normalizes provider claims.
4. Account-linking code runs in a database transaction: provider subject first, verified email second, create/link identity, update profile metadata.
5. Handler calls the existing `auth.Store.Create` and `auth.SetSessionCookie`, then redirects to `/`.

## Constraints To Carry Into Plans

- D-01 through D-17 from `08-CONTEXT.md` must be visible in plan `must_haves`.
- AUTH-08 through AUTH-13 must all appear in plan frontmatter.
- Every plan handling authentication needs a `<threat_model>` block.
- UI changes must follow `08-UI-SPEC.md`: equal Google/Apple prominence, disabled missing-config states, neutral provider buttons, no provider-specific welcome page.

