| 14.1-oauth-identities-and-fonoteka-me-routes |
01 |
api |
| oauth-identities |
| sm-user-plugin |
| me-token |
| parity |
| gormigrate |
| lagoon.Encrypted |
| wire.Time |
| throttle |
|
| phase |
provides |
| 07-user-plugin-and-authentication |
sm-user-plugin sessionApp/insertUser, jwt.auth, lang YAML, controllers.writeJSON |
|
| phase |
provides |
| 08-oauth2-1-authorization-server |
JWT group in fonoteka routes.go, MeToken personal-token bootstrap, TokenSurfaceIsolation coverage |
|
| phase |
provides |
| 14-domain-jobs-and-external-integrations |
parity corpus at 175 PHP routes with 3 pending D-09 identity/me entries, fonoteka seed extras, php_parity.sh recording |
|
|
| OAuthIdentity model and gormigrate 202610050001_create_oauth_identities in sm-user-plugin (table golem15_user_oauth_identities, full PHP column set) |
| Exported OAuthIdentitiesIndex, OAuthIdentitiesDestroy, OAuthIdentitiesOptions; host JWT mounts GET/DELETE /oauth-identities with Winter HTML 404 and throttle:10,1 on DELETE |
| D-09 MeToken collection_ids JSON null when CollectionIDs is invalid or empty; scopes still wire.Slice |
| Parity extras oauth-identities-linked and me-unrestricted; three manifest routes ported; TestParityCorpus recorded 175/175 passing 175 failing 0 unrecorded 0 pending 0 |
|
| 14.1-02 unit tests |
| 15-cutover (zero pending routes) |
|
| tokens |
tasks |
commits |
| 5100 |
4 |
5 |
|
c3bbbcbb9f |
ac8aa16217556f70f1e1b2c0a3495c7eea6b5747 |
1584d7390d80b8f1d3e8de53c2f0144deb9ebd64 |
| added |
patterns |
|
|
| Host-mounted constructors: sm-user-plugin exports Index/Destroy; the host chooses the path, throttle and WriteNotFound (Winter HTML 404), never a /_user route |
| Parity extras keyed as "<route id>#<case id>" on both PHP tinker reset and Go seedFonotekaCase |
| assertPortedMismatch wraps a ported fixture with mutateStatus and requires tide.MismatchError |
|
|
| created |
modified |
| ../fonoteka.go/plugins/golem15/user/models/oauth_identity.go |
| ../fonoteka.go/plugins/golem15/user/updates/202610050001_create_oauth_identities.go |
| ../fonoteka.go/plugins/golem15/user/controllers/oauth_identities.go |
| ../fonoteka.go/plugins/golem15/user/oauth_identities_test.go |
| ../fonoteka.go/parity/fixtures/routes/GET___fonoteka_api_v1_oauth-identities_jwt__linked.yaml |
| ../fonoteka.go/parity/fixtures/routes/GET__api_v1_fonoteka_me_personal_token__unrestricted.yaml |
|
| ../fonoteka.go/plugins/golem15/user/lang/en/lang.yaml |
| ../fonoteka.go/plugins/golem15/user/lang/pl/lang.yaml |
| ../fonoteka.go/plugins/golem15/user/README.md |
| ../fonoteka.go/plugins/golem15/fonoteka/routes.go |
| ../fonoteka.go/plugins/golem15/fonoteka/phase08_coverage_test.go |
| ../fonoteka.go/plugins/golem15/fonoteka/controllers/api/me_token_controller.go |
| ../fonoteka.go/parity/manifest.yaml |
| ../fonoteka.go/parity/parity_test.go |
| ../fonoteka.go/parity/parity_contract_test.go |
| ../fonoteka.go/parity/fonoteka_seed_test.go |
| ../fonoteka.go/parity/fonoteka_reset.php |
| ../fonoteka.go/parity/genres_seed_test.go |
| ../fonoteka.go/parity/fixtures/routes/GET__api_v1_fonoteka_me_personal_token.yaml |
|
|
| Task 1 answered ship-shared-full before dispatch: table golem15_user_oauth_identities lives in sm-user-plugin with the full PHP column set (locked D-01 and D-07) |
| routes.go in sm-user-plugin stays byte-identical; identity handlers are host-mounted on the fonoteka JWT group |
| Last-method 409 counts identities only (D-06); HasSelfSetPassword is unused |
| Restricted /me was re-recorded from the fonoteka reset so {{id:collection}} resolves; the Phase 2 {{id:token}} placeholder would not |
|
| OAuth identity list is an explicit {provider, linked_at} map; Encrypted tokens and profile_data are Hidden and json:"-" |
| DELETE {provider} is unconstrained on the mux so unknown providers reach WriteWinterHTTPError |
| MeToken: scopes use wire.Slice; collection_ids is a bare any that stays JSON null when empty |
|
|
| API-09 |
| HTTP-01 |
| HTTP-03 |
| DATA-02 |
| DATA-07 |
| I18N-01 |
|
| id |
description |
requirement |
verification |
human_judgment |
| D1 |
golem15_user_oauth_identities exists in sm-user-plugin via gormigrate with Encrypted tokens, Hidden secrets, and empty Fillable |
DATA-02 |
| kind |
ref |
status |
| unit |
plugins/golem15/user#TestOAuthIdentitiesIndexEmptyList |
pass |
|
|
false |
|
| id |
description |
requirement |
verification |
human_judgment |
| D2 |
JWT GET /_fonoteka/api/v1/oauth-identities returns {"data":[]} and, with extra oauth-identities-linked, facebook then google linked_at +00:00 without secrets |
HTTP-06 |
| kind |
ref |
status |
| e2e |
parity#TestParityCorpus coverage line recorded 175/175 passing 175 |
pass |
|
| kind |
ref |
status |
| unit |
plugins/golem15/user#TestOAuthIdentitiesIndexEmptyList |
pass |
|
|
false |
|
| id |
description |
requirement |
verification |
human_judgment |
| D3 |
JWT DELETE /oauth-identities/{provider} is throttle:10,1, unconstrained, 204 keeps the sibling row |
HTTP-01 |
| kind |
ref |
status |
| unit |
plugins/golem15/user#TestOAuthIdentitiesDestroyNoContentKeepsSibling |
pass |
|
| kind |
ref |
status |
| unit |
plugins/golem15/fonoteka#TestOAuthTokenSurfaceIsolationCoverage/test_oauth_identity_routes_exist_on_jwt_surface_only |
pass |
|
|
false |
|
| id |
description |
requirement |
verification |
human_judgment |
| D4 |
Unrestricted /me emits collection_ids JSON null; three manifest routes are ported at 175/175/0 |
API-09 |
| kind |
ref |
status |
| e2e |
parity#TestParityCorpus recorded 175/175 passing 175 failing 0 unrecorded 0 pending 0 |
pass |
|
|
false |
|
| id |
description |
verification |
human_judgment |
| D5 |
sm-user-plugin README names OAuthIdentitiesIndex/Destroy/Options as host-mounted constructors without a consuming-application name |
| kind |
ref |
status |
| other |
grep OAuthIdentitiesIndex plugins/golem15/user/README.md |
pass |
|
|
false |
|
|
90min |
2026-10-05 |
complete |