fix(po): upload attachments server-side so they persist & show #144
No reviewers
Labels
No labels
bug
claude-failed
claude-pr
claude-queue
claude-working
epic
feature
interactive
portal
triaged
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference: shad0w/pelagia-portal#144
Loading…
Add table
Reference in a new issue
No description provided.
Delete branch "claude/flamboyant-gagarin-370922"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Two parts
1. Fix: PO attachments never persisted (root cause)
PO/receipt attachments were uploaded via a browser presigned PUT straight to R2 (
POST /api/files/sign-> browser PUT ->linkDocument). That direct browser->R2 PUT needs an R2 CORS policy allowing PUT from the portal origin; in production it was missing, so the browser silently blocked the PUT,linkDocumentnever ran, and no PODocument row was created (0 rows in prod/staging).Now uploads go through a server action (
uploadPoDocuments) that writes the file withuploadBufferand creates the PODocument row atomically -- the same server-side pattern crewing already uses, within the 10mb serverActions limit. Removes the CORS dependency. Files still land in R2 (server-to-server). Removes the dead presigned path.2. Feature: add attachments to CLOSED POs (remediation)
New opt-in flag
NEXT_PUBLIC_CLOSED_PO_ATTACHMENTS_ENABLED. When on, a CLOSED PO's own submitter, plus Accounts / Manager / SuperUser, can attach documents to it -- so POs whose uploads were lost to the bug can be fixed without reopening them. Off by default (production unchanged); enabled on staging. Enforced both in the UI (PO detail Attachments card) and server-side inuploadPoDocuments.Tests
po-document-upload.test.ts-- upload creates a PODocument row, file bytes reach storage, doc is surfaced by the exact PO-detail include; plus the flag-off case (closed PO immutable).closed-po-attachments.test.ts-- flag-on role matrix (submitter / Accounts / Manager / SuperUser allowed; other submitter-role + auditor refused; non-closed PO unaffected).Full unit (338) + integration (293) suites green;
tsc --noEmitclean.Note on the earlier CI failure
The first run failed at the Checkout step -- the pms1 runner couldn't reach
code.forgejo.orgto fetchactions/checkout@v4(TCP timeout), unrelated to the diff. Re-triggered by this push.Generated with Claude Code.
Adds NEXT_PUBLIC_CLOSED_PO_ATTACHMENTS_ENABLED. When on, a CLOSED PO's own submitter -- plus Accounts / Manager / SuperUser -- can attach documents to it, so POs whose uploads were lost to the document-upload bug can be fixed without reopening them. Off by default, so production stays unchanged until enabled. - lib/permissions.ts: canAddClosedPoAttachment(role, { isSubmitter }) gated by the flag; allowed roles are ACCOUNTS/MANAGER/SUPERUSER (plus the PO's own submitter regardless of role). - uploadPoDocuments: a CLOSED PO is otherwise immutable, so it now enforces the permission server-side; the normal create/receipt flows upload while the PO is pre-CLOSED and are unaffected. - po-detail.tsx: when allowed, the Attachments card renders an uploader (ClosedPoAttachmentUploader) and shows even when the PO has no docs yet. - Enabled on staging (staging-up.sh) so the remediation can be exercised; documented in .env.example and CLAUDE.md. Tests: closed-po-attachments.test.ts covers the flag-on role matrix (own submitter / Accounts / Manager / SuperUser allowed; other submitter-role and auditor refused; non-closed PO unaffected); po-document-upload.test.ts adds the flag-off case (closed PO stays immutable). Full unit + integration suites green; tsc clean. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>