feat(v1.1.5): files SDK + files:* triggers

Filesystem-backed blob storage as the fifth concrete trigger kind.

- `files::collection(c).{create,head,get,update,delete,list}` Rhai SDK
  (blob in/out; metadata maps; missing-field throws naming the field).
- `FilesService` trait in picloud-shared; `FsFilesRepo` (atomic
  write: temp→fsync→rename→fsync-dir→DB; single-pass SHA-256;
  checksum-verified reads → Corrupted) + `FilesServiceImpl` in
  manager-core. Metadata in Postgres (0018), bytes on disk under
  PICLOUD_FILES_ROOT with 0o700 shard dirs.
- `files:*` trigger kind via the Layout-E pattern (0019: widen both
  CHECKs + files_trigger_details), TriggerEvent::Files (metadata only,
  no bytes), emit_files fan-out, dispatcher arm, admin endpoint
  POST /triggers/files (reuses validate_trigger_target).
- AppFilesRead/AppFilesWrite capabilities → script:read/script:write
  (seven-scope commitment held). AppPubsubPublish reserved for v1.1.6.
- Admin files API (list + delete) + dashboard Files view per app.

Cross-app isolation keyed on cx.app_id at every layer. ~45 new tests
(service in-memory, fs tempdir, bridge integration). No DB required
for the suite. publish_ephemeral and the orphan sweep stay deferred.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
MechaCat02
2026-06-03 21:18:17 +02:00
parent 03d03ea6e7
commit 6e132b6ee0
29 changed files with 3599 additions and 31 deletions

View File

@@ -0,0 +1,29 @@
-- v1.1.5: extend the triggers framework to recognise `files` as the
-- fifth concrete kind (after `kv`/`dead_letter` v1.1.1, `docs` v1.1.2,
-- `cron` v1.1.4). Mirrors the 0014/0017 extensions exactly: two CHECK
-- constraints widen (strictly gaining `'files'`), one new detail table.
--
-- Files rows route through the SAME generic dispatcher path as the
-- other event kinds (single match-arm extension on the Rust side). The
-- only new machinery is the FilesServiceImpl emitting ServiceEvents
-- that the OutboxEventEmitter fans out — identical to KV/docs.
-- Extend triggers.kind to include 'files'. No existing row carries a
-- value outside the widened set, so the drop+add is safe.
ALTER TABLE triggers DROP CONSTRAINT triggers_kind_check;
ALTER TABLE triggers ADD CONSTRAINT triggers_kind_check
CHECK (kind IN ('kv', 'dead_letter', 'docs', 'cron', 'files'));
-- Extend outbox.source_kind to include 'files'.
ALTER TABLE outbox DROP CONSTRAINT outbox_source_kind_check;
ALTER TABLE outbox ADD CONSTRAINT outbox_source_kind_check
CHECK (source_kind IN ('http', 'kv', 'dead_letter', 'docs', 'cron', 'files'));
-- One row per files trigger. Mirrors kv_trigger_details:
-- collection_glob — "*", "exact", or "prefix*"
-- ops — subset of {create, update, delete}, empty = any
CREATE TABLE files_trigger_details (
trigger_id UUID PRIMARY KEY REFERENCES triggers(id) ON DELETE CASCADE,
collection_glob TEXT NOT NULL,
ops TEXT[] NOT NULL
);