docs(05): create phase plan
This commit is contained in:
@@ -2,8 +2,8 @@
|
||||
phase: 05-data-layer-full-fidelity
|
||||
plan: 03
|
||||
type: execute
|
||||
wave: 2
|
||||
depends_on: ["05-01"]
|
||||
wave: 3
|
||||
depends_on: ["05-01", "05-02"]
|
||||
files_modified:
|
||||
- summercms.go/lagoon/encrypted.go
|
||||
- summercms.go/lagoon/encrypted_test.go
|
||||
@@ -203,7 +203,7 @@ func (c *Config) Lookup(path string) (any, bool)
|
||||
.planning/phases/05-data-layer-full-fidelity/05-RESEARCH.md (Full Per-Model Inventory rows 4, 13, 14, 15, 16, 17, 21, 23; "Pattern: Encrypted-at-rest cast" code example)
|
||||
</read_first>
|
||||
<action>
|
||||
Create `updates/11_secrets_slice.go` (package `updates`) with three migrations, IDs following `updates/10_album_slice.go`'s date/sequence convention (independent numbering from Plan 05-02's file — both are new files in the same wave, no shared line edited):
|
||||
Create `updates/11_secrets_slice.go` (package `updates`) with three migrations, IDs continuing Plan 05-02's `updates/10_album_slice.go` date/sequence (Wave 2 already shipped that file; this plan is Wave 3, no shared line edited):
|
||||
1. `create_api_tokens` — `golem15_fonoteka_api_tokens (id SERIAL PRIMARY KEY, user_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE, name TEXT, token_hash TEXT NOT NULL UNIQUE, scopes TEXT, collection_ids TEXT, expires_at TIMESTAMPTZ, revoked_at TIMESTAMPTZ, last_used_at TIMESTAMPTZ, last_used_ip TEXT, oauth_client_id TEXT, created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW())` (verify exact types against the two folded files; `scopes`/`collection_ids` are `text` jsonable columns per RESEARCH.md row 4, not native `jsonb`).
|
||||
2. `create_oauth_tables` — `golem15_fonoteka_oauth_clients (id SERIAL PRIMARY KEY, client_id TEXT NOT NULL UNIQUE, client_secret_hash TEXT NOT NULL, client_name TEXT, redirect_uris TEXT, grant_types TEXT, token_endpoint_auth_method TEXT, registration_ip TEXT, consented_at TIMESTAMPTZ, revoked_at TIMESTAMPTZ, scope_ceiling TEXT, created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW())`, `golem15_fonoteka_oauth_auth_codes (id SERIAL PRIMARY KEY, request_id TEXT NOT NULL UNIQUE, code_hash TEXT NOT NULL UNIQUE, client_id TEXT NOT NULL, user_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE, redirect_uri TEXT, scopes TEXT, collection_ids TEXT, code_challenge TEXT, code_challenge_method TEXT, resource TEXT, state TEXT, expires_at TIMESTAMPTZ, used_at TIMESTAMPTZ, offline_access BOOLEAN NOT NULL DEFAULT false, created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW())`, `golem15_fonoteka_oauth_refresh_tokens (id SERIAL PRIMARY KEY, token_hash TEXT NOT NULL UNIQUE, api_token_id INTEGER REFERENCES golem15_fonoteka_api_tokens(id) ON DELETE CASCADE, client_id TEXT NOT NULL, user_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE, scopes TEXT, collection_ids TEXT, expires_at TIMESTAMPTZ, revoked_at TIMESTAMPTZ, rotated_to_id INTEGER, offline_access BOOLEAN NOT NULL DEFAULT false, created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW())` (verify against both folded files including `scope_ceiling`).
|
||||
3. `create_credentials_tables` — `golem15_fonoteka_user_ai_credentials (id SERIAL PRIMARY KEY, user_id INTEGER NOT NULL UNIQUE REFERENCES users(id) ON DELETE CASCADE, provider TEXT NOT NULL, api_key TEXT NOT NULL, model TEXT, base_url TEXT, created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW())`, `golem15_fonoteka_org_ai_credentials` (same shape, `organisation_id INTEGER NOT NULL UNIQUE REFERENCES golem15_user_organisations(id) ON DELETE CASCADE` in place of `user_id`), `golem15_fonoteka_user_discogs_credentials (id SERIAL PRIMARY KEY, user_id INTEGER NOT NULL UNIQUE REFERENCES users(id) ON DELETE CASCADE, token TEXT NOT NULL, created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW())`, `golem15_fonoteka_org_discogs_credentials` (same shape with `organisation_id`) — `api_key`/`token` are `text` columns (never `varchar`, confirmed live per RESEARCH.md). This migration depends on `create_organisations` (Task 2) for the FK target; since gormigrate runs each plugin's set independently in `party.Activate` dependency order and `golem15.fonoteka` `Requires()` `golem15.user`, this ordering is already guaranteed — do not add an explicit cross-plugin migration dependency mechanism.
|
||||
|
||||
Reference in New Issue
Block a user