Integrate group files: nullable room for uploads, archive class, claim idempotency, upload route
Wires the three parallel group-cloud tracks to one surface and fixes the seams between them: - chat_media_archive.room_id becomes nullable (direct web uploads have no Matrix room yet — the contract's null-event pattern extends to the room); core GroupFile.roomId and ArchiveEntryInput.roomId follow. - mime_class gains 'archive' (zip) across the 029 CHECK, validation MIME_CLASSES and the bot classifier — one vocabulary everywhere. - registerArchiveEntry claim keys are null-safe for room-less uploads. - New: POST /files/groups/:groupId/upload — FileInterceptor (20 MiB) streams through magic-byte sniffing, library-safe naming, oCIS upload and the metadata index, behind group-membership ACL (Owner/Admin bypass). - safeFileName/sniffMime promoted to packages/core (file-names.ts, file-mime.ts) so the bot and the api share one implementation; the bot's local modules become re-export shims; @types/node added to core. Verified: api typecheck clean, group-files 22/22, bot 74/74, web typecheck clean; 029 re-applied clean on a fresh scratch DB (room_id nullable, archive class, claim_key unique all confirmed in the catalog).
This commit is contained in:
parent
688a2ce996
commit
e7e703c105
21 changed files with 473 additions and 227 deletions
|
|
@ -44,8 +44,9 @@ CREATE TABLE chat_media_archive (
|
|||
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
workspace_id uuid NOT NULL REFERENCES workspaces(id) ON DELETE CASCADE ON UPDATE RESTRICT,
|
||||
group_id uuid NOT NULL REFERENCES groups(id) ON DELETE CASCADE ON UPDATE RESTRICT,
|
||||
-- Immutable Matrix room ID, never an alias. Tenant-pinned below.
|
||||
room_id text NOT NULL CHECK (btrim(room_id) <> '' AND room_id ~ '^!'),
|
||||
-- Matrix room ID when the file arrived through a room; NULL for direct
|
||||
-- uploads/exports that have not been announced into one yet. Tenant-pinned.
|
||||
room_id text CHECK (btrim(room_id) = '' OR room_id ~ '^!'),
|
||||
-- NULL for direct uploads/pad exports until a room announcement supplies one.
|
||||
event_id text CHECK (event_id IS NULL OR btrim(event_id) <> ''),
|
||||
origin text NOT NULL CHECK (origin IN ('matrix','bridge','upload','pad-export')),
|
||||
|
|
@ -58,8 +59,8 @@ CREATE TABLE chat_media_archive (
|
|||
-- Normalized safe display filename (app-side sanitizeName).
|
||||
safe_name text NOT NULL CHECK (btrim(safe_name) <> '' AND char_length(safe_name) <= 255),
|
||||
mime text NOT NULL CHECK (mime <> ''),
|
||||
-- Coarse class derived from mime (image/video/audio/document/other).
|
||||
mime_class text NOT NULL CHECK (mime_class IN ('image','video','audio','document','other')),
|
||||
-- Coarse class derived from mime (image/video/audio/document/archive/other).
|
||||
mime_class text NOT NULL CHECK (mime_class IN ('image','video','audio','document','archive','other')),
|
||||
byte_size bigint NOT NULL CHECK (byte_size >= 0),
|
||||
-- SHA-256 of verified payload bytes, lowercase hex. Never an S3 ETag.
|
||||
sha256 text NOT NULL CHECK (sha256 ~ '^[0-9a-f]{64}$'),
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue