docs(07-08): plan avatar bucket publish on serve and Handler
This commit is contained in:
124
.planning/phases/07-user-plugin-and-authentication/07-08-PLAN.md
Normal file
124
.planning/phases/07-user-plugin-and-authentication/07-08-PLAN.md
Normal file
@@ -0,0 +1,124 @@
|
||||
---
|
||||
phase: 07-user-plugin-and-authentication
|
||||
plan: 08
|
||||
type: execute
|
||||
wave: 7
|
||||
depends_on: ["07-07"]
|
||||
files_modified:
|
||||
- surf/serve.go
|
||||
- surf/serve_test.go
|
||||
- ../fonoteka.go/app/app.go
|
||||
- ../fonoteka.go/parity/migrate_test.go
|
||||
- ../fonoteka.go/parity/genre_security_test.go
|
||||
- ../fonoteka.go/plugins/golem15/user/avatar_test.go
|
||||
autonomous: true
|
||||
requirements: []
|
||||
user_setup: []
|
||||
|
||||
must_haves:
|
||||
truths:
|
||||
- "surf.ServeCommand and app.Handler open storage.uploads.bucket_url and publish *blob.Bucket before Assemble, failing boot when the URL is empty"
|
||||
- "POST /_user/api/v1/avatar with a JPEG or PNG against app.Handler returns 200, has_avatar true, and a non-empty avatar_url; POST avatar/remove then clears has_avatar"
|
||||
- "Assembled parity/test configs set storage.uploads.bucket_url to mem:// so Handler and Serve still boot without a filesystem uploads dir"
|
||||
artifacts:
|
||||
- path: "surf/serve.go"
|
||||
provides: "attach.OpenBucket + attach.Publish next to lagoon.Publish in ServeCommand"
|
||||
- path: "../fonoteka.go/app/app.go"
|
||||
provides: "the same OpenBucket/Publish pair in Handler so in-process replay matches serve"
|
||||
- path: "../fonoteka.go/parity/migrate_test.go"
|
||||
provides: "testConfig sets storage.uploads.bucket_url=mem:// (and public_path_prefix)"
|
||||
key_links:
|
||||
- from: "surf/serve.go"
|
||||
to: "lagoon/attach/bucket.go"
|
||||
via: "OpenBucket then Publish"
|
||||
pattern: "attach.OpenBucket"
|
||||
- from: "../fonoteka.go/app/app.go"
|
||||
to: "lagoon/attach/bucket.go"
|
||||
via: "OpenBucket then Publish"
|
||||
pattern: "attach.OpenBucket"
|
||||
---
|
||||
|
||||
<objective>
|
||||
Close the UAT blocker: avatar upload against the assembled app is an opaque 500 because neither `surf.ServeCommand` nor `app.Handler` publishes `*blob.Bucket`. Wire `attach.OpenBucket`/`Publish` into both boot paths, give assembled tests a `mem://` URL, and add a Handler-level multipart upload so the missing-file 422 fixture cannot hide this again.
|
||||
|
||||
Purpose: make the Phase 7 avatar HTTP path work on the real boot, not only in unit tests that publish a memblob by hand.
|
||||
Output: serve and Handler publish the bucket; a JPEG upload against `app.Handler` is 200; `go vet` / `go test` stay green in both modules.
|
||||
</objective>
|
||||
|
||||
<execution_context>
|
||||
@$HOME/.codex/get-shit-done/workflows/execute-plan.md
|
||||
@$HOME/.codex/get-shit-done/templates/summary.md
|
||||
</execution_context>
|
||||
|
||||
<context>
|
||||
@.planning/phases/07-user-plugin-and-authentication/07-UAT.md
|
||||
@.planning/debug/avatar-bucket-not-published.md
|
||||
@surf/serve.go
|
||||
@lagoon/attach/bucket.go
|
||||
@../fonoteka.go/app/app.go
|
||||
@../fonoteka.go/plugins/golem15/user/controllers/api_controller.go
|
||||
</context>
|
||||
|
||||
<tasks>
|
||||
|
||||
<task type="auto">
|
||||
<name>Publish the uploads bucket on serve and Handler</name>
|
||||
<files>surf/serve.go, ../fonoteka.go/app/app.go, ../fonoteka.go/parity/migrate_test.go, ../fonoteka.go/parity/genre_security_test.go</files>
|
||||
<action>
|
||||
In `surf.ServeCommand`, after `lagoon.Publish` and before `Assemble`, call `attach.OpenBucket(ctx, app.Config)` then `attach.Publish(app, bucket)`. Return the OpenBucket error so an empty `storage.uploads.bucket_url` fails boot (same loud-fail as JWT secret). Do not swallow a missing bucket.
|
||||
|
||||
In `fonoteka.go/app.Handler`, do the same after `lagoon.Publish` and before `party.Activate`, using the passed `ctx` and `cfg`.
|
||||
|
||||
In every assembled-test config helper that feeds `app.Handler` (`testConfig` in `parity/migrate_test.go`, `testConfigCORS` in `parity/genre_security_test.go`, and any sibling that copies that pattern), set `storage.uploads.bucket_url` to `mem://` and `storage.uploads.public_path_prefix` to `/storage/uploads`. Production already has `fonoteka.go/config/storage.yaml`.
|
||||
|
||||
If a plugin-package boot helper (`bootConfig`, `sessionConfig`) is used to `Assemble` avatar HTTP without publishing a bucket, give it the same `mem://` key **or** keep publishing memblob in that test — do not leave a second assembled path that 500s.
|
||||
|
||||
`go vet` the touched packages. A ServeCommand unit test that the command errors when `bucket_url` is empty is enough for this task; the upload proof is the next task.
|
||||
</action>
|
||||
<verify>
|
||||
<automated>cd /media/nvme/dev/golem15/summercms.io/summercms/summercms.go && go vet ./surf/ && go test ./surf/ -count=1 -timeout 60s -run 'TestServe'</automated>
|
||||
</verify>
|
||||
<done>
|
||||
ServeCommand and app.Handler publish *blob.Bucket. Assembled test configs use mem://. Empty bucket_url still fails boot.
|
||||
</done>
|
||||
</task>
|
||||
|
||||
<task type="auto">
|
||||
<name>Assembled-app avatar upload and remove</name>
|
||||
<files>../fonoteka.go/plugins/golem15/user/avatar_test.go, ../fonoteka.go/parity/parity_test.go</files>
|
||||
<action>
|
||||
Add a test that boots `app.Handler` (or the user+fonoteka assembled router with a published mem bucket) and curls the real routes:
|
||||
|
||||
1. Register or insert an activated user, login, POST `/_user/api/v1/avatar` as multipart field `avatar` with a sniffed JPEG or PNG.
|
||||
2. Assert 200, `has_avatar` true, non-empty `avatar_url`.
|
||||
3. POST `/_user/api/v1/avatar/remove` with the same bearer; assert `has_avatar` false.
|
||||
|
||||
Prefer putting this next to the existing avatar tests if they can reach `app.Handler`; otherwise add it in `parity/` beside `newConfiguredTarget` so it uses the same boot as replay. Do not satisfy this with `controllers.UploadAvatar(app)` + a hand-published bucket only — that is the path that already passed and hid the gap.
|
||||
|
||||
Keep `TestUploadAvatar` / `TestRemoveAvatar`. They stay as handler-unit coverage.
|
||||
|
||||
If `TestParityCorpus` is still green with only the missing-file 422 fixture, leave that fixture alone. Do not invent a ported success-upload fixture unless a recorded PHP body already exists.
|
||||
</action>
|
||||
<verify>
|
||||
<automated>cd /media/nvme/dev/golem15/summercms.io/summercms/fonoteka.go && go test ./plugins/golem15/user/ -count=1 -timeout 180s -run 'TestUploadAvatar|TestRemoveAvatar|TestUploadAvatarAssembled' && go test ./parity/ -count=1 -timeout 15m -run 'TestParityCorpus$|TestUserAPINuxtFlows|TestAvatarAssembled'</automated>
|
||||
</verify>
|
||||
<done>
|
||||
A JPEG/PNG upload against the assembled handler is 200 with has_avatar and avatar_url; remove clears has_avatar. Existing avatar unit tests and the ported corpus stay green.
|
||||
</done>
|
||||
</task>
|
||||
|
||||
<task type="auto">
|
||||
<name>Race gate both modules</name>
|
||||
<files></files>
|
||||
<action>
|
||||
Run the phase gate: `go vet ./... && go test ./... -race` in `summercms.go`, then the same plus nested plugin packages in `fonoteka.go` (`./plugins/golem15/user`, `./plugins/golem15/fonoteka`, `./plugins/golem15/fonoteka/...`). Fix only compile or test fallout from the bucket publish (most likely a test config missing `bucket_url`). Do not change avatar response shapes.
|
||||
</action>
|
||||
<verify>
|
||||
<automated>cd /media/nvme/dev/golem15/summercms.io/summercms/summercms.go && go vet ./... && go test ./... -race -count=1 -timeout 20m</automated>
|
||||
</verify>
|
||||
<done>
|
||||
go vet and go test -race are green in summercms.go and fonoteka.go after the boot-path change.
|
||||
</done>
|
||||
</task>
|
||||
|
||||
</tasks>
|
||||
Reference in New Issue
Block a user