Implement file storage layer with local provider, upload/download API, tests

- StorageProvider interface with LocalProvider (S3 placeholder)
- File table with entity_type/entity_id references, content type, path
- POST /v1/files (multipart upload), GET /v1/files (list by entity),
  GET /v1/files/:id (metadata), GET /v1/files/serve/* (content),
  DELETE /v1/files/:id
- member_identifier drops base64 columns, uses file_id FKs
- File validation: type whitelist, size limits, per-entity max
- Fastify storage plugin injects provider into app
- 6 API tests for upload, list, get, delete, validation
- Test runner kills stale port before starting backend
This commit is contained in:
Ryan Moon
2026-03-28 15:29:06 -05:00
parent de4d2e0a32
commit 760e995ae3
19 changed files with 615 additions and 6 deletions

View File

@@ -66,8 +66,8 @@ export const MemberIdentifierCreateSchema = z.object({
issuingAuthority: opt(z.string().max(255)),
issuedDate: opt(z.string().date()),
expiresAt: opt(z.string().date()),
imageFront: opt(z.string()),
imageBack: opt(z.string()),
imageFrontFileId: opt(z.string().uuid()),
imageBackFileId: opt(z.string().uuid()),
notes: opt(z.string()),
isPrimary: z.boolean().default(false),
})