feat(v1.1.2-docs): migrations + shared DocsService trait + TriggerEvent::Docs
Migrations 0013_docs.sql + 0014_docs_triggers.sql land the docs table (JSONB body + GIN-on-jsonb_path_ops index, PK keyed on (app_id, collection, id) for cross-app isolation) and widen the triggers.kind and outbox.source_kind CHECK constraints to include 'docs', plus the docs_trigger_details detail table mirroring kv_trigger_details. picloud-shared grows the DocsService trait + DocRow/DocsListPage/ DocsError + NoopDocsService, the TriggerEvent::Docs variant with the prev_data change-data-capture surface, the DocsEventOp enum, the docs field on the Services bundle, and the SDK_VERSION bump 1.2 -> 1.3. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
39
crates/manager-core/migrations/0013_docs.sql
Normal file
39
crates/manager-core/migrations/0013_docs.sql
Normal file
@@ -0,0 +1,39 @@
|
||||
-- v1.1.2: Documents — schemaless JSONB store with basic query semantics.
|
||||
--
|
||||
-- Identity tuple `(app_id, collection, id)`. `id` is a server-generated
|
||||
-- UUID; scripts never supply it on create. `app_id` is first in the
|
||||
-- primary key so the implicit index is always per-app — cross-app reads
|
||||
-- are impossible even under a buggy query.
|
||||
--
|
||||
-- `data` is JSONB so scripts can store nested structures without a
|
||||
-- separate serialization step. The GIN-on-`jsonb_path_ops` index
|
||||
-- accelerates the v1.1.2 query DSL's equality and containment operators
|
||||
-- (`docs::find` with `$eq` / `$in`); range/comparison operators rely on
|
||||
-- the per-collection seq scan within the small `app_id` partition.
|
||||
--
|
||||
-- `created_at` / `updated_at` are server-managed: created on insert,
|
||||
-- bumped on every successful update. The returned doc envelope surfaces
|
||||
-- both fields to scripts for read-only access (no script-side override).
|
||||
|
||||
CREATE TABLE docs (
|
||||
app_id UUID NOT NULL REFERENCES apps(id) ON DELETE CASCADE,
|
||||
collection TEXT NOT NULL,
|
||||
id UUID NOT NULL,
|
||||
data JSONB NOT NULL,
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||||
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||||
PRIMARY KEY (app_id, collection, id)
|
||||
);
|
||||
|
||||
-- The dispatcher/find hot path: "all docs in app X / collection Y."
|
||||
-- The PK already covers (app_id, collection) as a prefix but spelling
|
||||
-- out the explicit index makes intent clear for the planner. Mirrors
|
||||
-- 0007_kv.sql's idx_kv_entries_app_collection.
|
||||
CREATE INDEX idx_docs_app_collection ON docs (app_id, collection);
|
||||
|
||||
-- GIN on JSONB with the `jsonb_path_ops` opclass: smaller index than
|
||||
-- the default `jsonb_ops`, supports `@>` (containment) which is what
|
||||
-- equality filters compile to under the GIN-friendly path. Range
|
||||
-- operators ($gt/$gte/$lt/$lte/$ne) fall back to per-collection scans;
|
||||
-- those are still bounded by the (app_id, collection) selectivity.
|
||||
CREATE INDEX idx_docs_data_gin ON docs USING GIN (data jsonb_path_ops);
|
||||
Reference in New Issue
Block a user