Phase 14.1: OAuth identities and fonoteka me routes - Discussion Log
Audit trail only. Do not use as input to planning, research, or execution agents.
Decisions are captured in CONTEXT.md. This log preserves the alternatives considered.
Date: 2026-10-04
Phase: 14.1-oauth-identities-and-fonoteka-me-routes
Areas discussed: where the identity table lives, token columns and import, parity case coverage, social-login-only users at cutover
The scout found two things before the discussion:
GET /api/v1/fonoteka/me is already served in Go. Its only gap is that collection_ids is [] where PHP returns null for an unrestricted token. This is decided by the PHP contract and was not asked.
- Go has no model or migration for
golem15_user_oauth_identities.
Where the identity table lives
| Option |
Description |
Selected |
| sm-user-plugin |
Mirrors PHP, where Golem15.User owns the table; additive change |
✓ |
| fonoteka plugin |
Leaves the shared plugin untouched, but the table sits in the wrong plugin |
|
The user asked what the handlers are for. They back Settings → Connected accounts in the Nuxt app, which lists linked Google, Facebook and GitHub logins and lets the user disconnect them. Unlinking the last one returns 409.
| Option |
Description |
Selected |
| fonoteka plugin |
Same as PHP |
|
| user plugin API |
Reusable handlers that fonoteka mounts at its prefix |
✓ |
| Option |
Description |
Selected |
| User plugin lang, same text |
New key in the user plugin with identical EN/PL text |
✓ |
| Host passes the message |
The mount supplies the message key |
|
| Option |
Description |
Selected |
| Mount option, default the three |
google/facebook/github by default; the host can narrow or extend |
✓ |
| Hard-coded three |
Matches PHP exactly |
|
Token columns and import
| Option |
Description |
Selected |
| Full PHP column set |
Encrypted tokens, jsonb profile_data, both unique indexes |
✓ |
| Full columns, tokens nulled at import |
Drop the stored provider tokens at import |
|
| Only what list/unlink need |
Minimal columns |
|
| Option |
Description |
Selected |
| No, Phase 15 writes the import mapper |
HasWinterImport does not exist yet |
✓ |
| Yes, note the transforms now |
Docs only |
|
Parity case coverage
Identity cases to record (multi-select): list with linked rows ✓, unlink 204 and last-method 409 ✗, foreign vs missing 404 ✗, unknown provider and 401 ✗.
| Option |
Description |
Selected |
| Add unrestricted-token case (/me) |
collection_ids: null case |
✓ |
| Also scope variants |
Read-only and revoked tokens |
|
| Option |
Description |
Selected |
| Go tests ported from the PHP tests |
Covers the unselected behaviours in the final unit-test plan |
✓ |
| Keep only what's recorded |
|
|
Social-login-only users at cutover
| Option |
Description |
Selected |
| Flag for the Phase 15 preflight |
Count OAuth-only users in the dump; give them a password first, or schedule a social login phase |
✓ |
| Accept, nobody uses it |
|
|
| Pull social login into scope |
Big scope jump |
|
Claude's Discretion
- The shape of the exported sm-user-plugin API and how fonoteka mounts it
- Where the throttle for
throttle:10,1 is declared
- ISO-8601 formatting that matches Laravel's
toIso8601String()
- Plan split (unit tests come last; the plan count is confirmed first)
- README and docs updates
Deferred Ideas
- Social login port (its own phase; the Phase 15 preflight decides the urgency)
- Winter-import mapper for the identities table (Phase 15)