Files
summercms/.planning/debug/resolved/avatar-bucket-not-published.md
Jakub Zych b435304570 docs(phase-7): complete phase execution
Avatar bucket publish closed the last UAT blocker. Phase 7 is 8/8
verified. Next is discuss Phase 8; do not auto-advance.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-23 10:53:42 +02:00

44 lines
1.8 KiB
Markdown

---
status: resolved
updated: 2026-09-23T08:52:00Z
---
# DEBUG: Avatar upload 500 on assembled app
**Discovered:** 2026-09-23 during `$gsd-verify-work 7`
**Status:** resolved
**Goal:** find_root_cause_only
## Symptoms
- POST `/_user/api/v1/avatar` with a JPEG multipart against `app.Handler` returns `500 {"error":true,"message":"Internal server error"}`
- Profile update, marketing consent, and change-password on the same handler succeed
- `TestUploadAvatar` / `TestRemoveAvatar` pass
## Reproduction
1. Boot `app.Handler` with parity `testConfig` (app.yaml + http.yaml + JWT secret)
2. Register, then `curl -F avatar=@tiny.jpg`
3. Observe 500
## Root Cause
Phase 5 shipped `attach.OpenBucket` / `attach.Publish` but never called them from serve. Phase 5 verification recorded that as info because there was no HTTP upload yet. Phase 7 added `UploadAvatar`, which does `app.Lookup[*blob.Bucket]()` and `writeOpaque500` when the lookup fails.
Neither boot path publishes the bucket:
- `fonoteka.go/app/app.go` `Handler` — `lagoon.Publish` then `party.Activate` then `surf.Assemble`
- `surf.ServeCommand` — `lagoon.OpenFromApp` / `lagoon.Publish` then `Assemble`
Unit tests call `publishAvatarBucket` (memblob) themselves. The ported parity fixture is `avatar-missing` (JSON `{}` → 422), so `TestParityCorpus` never uploads a file.
## Suggested Fix
1. Open and publish the bucket next to `lagoon.Publish` in `ServeCommand` and `app.Handler`. Empty `storage.uploads.bucket_url` already fails loud.
2. Set `storage.uploads.bucket_url=mem://` on assembled-test configs.
3. Add a Handler-level multipart upload test so this cannot regress behind the 422 fixture.
## Resolution
07-08 published the bucket on both boot paths. `TestAvatarAssembled` POSTs a JPEG through `app.Handler` (200, `has_avatar`, `avatar_url`) then remove.