Files
zpan/migrations/0045_soft_outlaw_kid.sql
T
Jasper Van 7b8c8c915e refactor(api)!: unify object upload + rework delete/trash lifecycle (#448) (#454)
Resolve #448 — one upload entry point and an AIP-164 soft delete.

Upload: POST /objects now returns size-decided upload instructions
{ sessionId, partSize, urls }; the server picks single PutObject (<=5 GiB)
vs 5 GiB-part multipart (>5 GiB) and rejects >5 TiB. The client PUTs each
slice, reads its ETag, then POSTs them to
POST /objects/{id}/uploads/{sid}/completions (returns the live object).
DELETE /objects/{id}/uploads/{sid} aborts and discards the draft.

Trash: matters.status drops 'trashed' (enum is {draft,active}); trash is
tracked by the existing trashedAt timestamp. DELETE /objects/{id} now
soft-deletes; the recycle bin lives under /trash/objects (list roots, get,
restorations, purge). Empty-trash is a frontend loop over roots.

BREAKING CHANGE:
- removes PUT /objects/{id}/status and POST /objects/{id}/uploads
- PUT .../uploads/{sid}/status -> POST .../uploads/{sid}/completions {parts}
- DELETE /objects/{id} flips hard-purge -> soft-delete; permanent purge
  moves to DELETE /trash/objects/{id}
- DELETE /trash removed; restore is POST /trash/objects/{id}/restorations
- matters.status enum loses 'trashed' (migration backfills to trashedAt)

The migration swaps the matters_active_name_uniq partial index to exclude
trashed rows (WHERE status='active' AND trashed_at IS NULL). The single-PUT
presign is header-free so the uniform slice uploader's raw PUT matches the
S3 signature. Go downloader client + agent reworked to the unified flow.

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-18 21:21:43 -04:00

22 lines
1.3 KiB
SQL

PRAGMA foreign_keys=OFF;--> statement-breakpoint
CREATE TABLE `__new_object_upload_sessions` (
`id` text PRIMARY KEY NOT NULL,
`org_id` text NOT NULL,
`object_id` text NOT NULL,
`storage_id` text NOT NULL,
`storage_key` text NOT NULL,
`upload_id` text,
`part_size` integer NOT NULL,
`status` text NOT NULL,
`created_by` text NOT NULL,
`expires_at` integer NOT NULL,
`created_at` integer NOT NULL,
`updated_at` integer NOT NULL
);
--> statement-breakpoint
INSERT INTO `__new_object_upload_sessions`("id", "org_id", "object_id", "storage_id", "storage_key", "upload_id", "part_size", "status", "created_by", "expires_at", "created_at", "updated_at") SELECT "id", "org_id", "object_id", "storage_id", "storage_key", "upload_id", "part_size", "status", "created_by", "expires_at", "created_at", "updated_at" FROM `object_upload_sessions`;--> statement-breakpoint
DROP TABLE `object_upload_sessions`;--> statement-breakpoint
ALTER TABLE `__new_object_upload_sessions` RENAME TO `object_upload_sessions`;--> statement-breakpoint
PRAGMA foreign_keys=ON;--> statement-breakpoint
CREATE INDEX `object_upload_sessions_object_idx` ON `object_upload_sessions` (`org_id`,`object_id`);--> statement-breakpoint
CREATE INDEX `object_upload_sessions_expires_idx` ON `object_upload_sessions` (`expires_at`);