mirror of
https://github.com/MBombeck/HealthLog.git
synced 2026-11-08 12:32:43 +00:00
feat(share-links): add frozen document-membership join (migration 0229)
P3-1-T1. Introduce ClinicianShareLinkDocument, the write-once join binding a stored document to a clinician share link. The document set a share exposes is a relation, not a mutable column, so it inherits the link's frozen-scope discipline. Both foreign keys cascade so a deleted link or document takes its membership with it.
This commit is contained in:
1 parent
1474c87011
commit
32f51b4299
2 files changed
+77
-1
No files matched your search
@@ -0,0 +1,45 @@
|
||||
-- Document vault, Phase 3: attach hand-picked documents to a clinician share
|
||||
-- link.
|
||||
--
|
||||
-- `clinician_share_link_documents` — frozen, write-once membership rows
|
||||
-- binding a stored document to a share link. The document set a share
|
||||
-- exposes is modelled as this join, never a mutable column on the link, so
|
||||
-- it inherits the link's frozen-scope discipline: rows are created in the
|
||||
-- same transaction as the link, each document is owner-checked at create,
|
||||
-- and the set is never widened afterwards. The public share serve route
|
||||
-- serves ONLY a document id present in this set for the resolved token.
|
||||
--
|
||||
-- Both foreign keys cascade: deleting the link or the underlying document
|
||||
-- removes the membership cleanly (a shared document the owner later deletes
|
||||
-- simply disappears from the link).
|
||||
--
|
||||
-- Additive; applies clean on a 0228 database and on a fresh database as part
|
||||
-- of the ordered migration chain.
|
||||
|
||||
CREATE TABLE "clinician_share_link_documents" (
|
||||
"id" TEXT NOT NULL,
|
||||
"share_link_id" TEXT NOT NULL,
|
||||
"document_id" TEXT NOT NULL,
|
||||
"created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
|
||||
CONSTRAINT "clinician_share_link_documents_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
CREATE UNIQUE INDEX "clinician_share_link_documents_share_link_id_document_id_key"
|
||||
ON "clinician_share_link_documents" ("share_link_id", "document_id");
|
||||
|
||||
CREATE INDEX "clinician_share_link_documents_share_link_id_idx"
|
||||
ON "clinician_share_link_documents" ("share_link_id");
|
||||
|
||||
CREATE INDEX "clinician_share_link_documents_document_id_idx"
|
||||
ON "clinician_share_link_documents" ("document_id");
|
||||
|
||||
ALTER TABLE "clinician_share_link_documents"
|
||||
ADD CONSTRAINT "clinician_share_link_documents_share_link_id_fkey"
|
||||
FOREIGN KEY ("share_link_id") REFERENCES "clinician_share_links" ("id")
|
||||
ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
ALTER TABLE "clinician_share_link_documents"
|
||||
ADD CONSTRAINT "clinician_share_link_documents_document_id_fkey"
|
||||
FOREIGN KEY ("document_id") REFERENCES "inbound_documents" ("id")
|
||||
ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
+32
-1
@@ -4852,13 +4852,41 @@ model ClinicianShareLink {
|
||||
lastAccessAt DateTime? @map("last_access_at")
|
||||
accessCount Int @default(0) @map("access_count")
|
||||
|
||||
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
||||
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
||||
/// v1.28 — the hand-picked document set this link exposes (0..N). A relation,
|
||||
/// not a column: frozen write-once at create, owner-checked, never widened.
|
||||
documents ClinicianShareLinkDocument[]
|
||||
|
||||
@@index([userId, createdAt(sort: Desc)])
|
||||
@@index([expiresAt])
|
||||
@@map("clinician_share_links")
|
||||
}
|
||||
|
||||
/// v1.28 (document vault, Phase 3) — frozen, write-once membership binding a
|
||||
/// stored document to a clinician share link. The document set a share exposes
|
||||
/// is modelled as this relation, never a mutable column: the rows are created
|
||||
/// in the same transaction as the link, each `documentId` is validated as the
|
||||
/// caller's own live document at create time, and the set is never widened
|
||||
/// afterwards. The public share serve route serves ONLY a document id present
|
||||
/// in this set for the resolved token — a guessed / foreign id is a flat 404.
|
||||
/// Both foreign keys cascade: deleting the link or the underlying document
|
||||
/// removes the membership cleanly (a shared document the owner later deletes
|
||||
/// simply disappears from the link).
|
||||
model ClinicianShareLinkDocument {
|
||||
id String @id @default(cuid())
|
||||
shareLinkId String @map("share_link_id")
|
||||
documentId String @map("document_id")
|
||||
createdAt DateTime @default(now()) @map("created_at")
|
||||
|
||||
shareLink ClinicianShareLink @relation(fields: [shareLinkId], references: [id], onDelete: Cascade)
|
||||
document InboundDocument @relation(fields: [documentId], references: [id], onDelete: Cascade)
|
||||
|
||||
@@unique([shareLinkId, documentId])
|
||||
@@index([shareLinkId])
|
||||
@@index([documentId])
|
||||
@@map("clinician_share_link_documents")
|
||||
}
|
||||
|
||||
// v1.11.0 W3 — period-narrative cache (Pillar P1).
|
||||
//
|
||||
// One durable, typed row per (user, period, locale) carrying the latest
|
||||
@@ -5815,6 +5843,9 @@ model InboundDocument {
|
||||
|
||||
facts ExtractedFact[]
|
||||
conditionLinks DocumentConditionLink[]
|
||||
/// v1.28 — share-link memberships (m:n via `ClinicianShareLinkDocument`).
|
||||
/// Cascades: deleting this document removes it from every share it was on.
|
||||
shareLinks ClinicianShareLinkDocument[]
|
||||
|
||||
createdAt DateTime @default(now()) @map("created_at")
|
||||
updatedAt DateTime @updatedAt @map("updated_at")
|
||||
|
||||
Reference in new issue
Block a user