Add notes API: clinic + author-scoped CRUD

New `note` table (src/db/schema/notes.ts) referencing organization + user,
with org+author scoping so a doctor only sees their own notes within the active
clinic. Adds:

- src/types/note.ts + src/lib/note-validation.ts (zod)
- src/services/notes.ts (CRUD, treats non-uuid ids as not-found)
- src/routes/notes.ts mounted at /api/notes, gated requireAuth → requireOrg
- schema barrel + generated migration drizzle/0001_*.sql (applied on startup
  by the runtime migrator)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Khalid Abdi
2026-06-04 19:48:39 +03:00
parent 8bb341ea27
commit 7d6641ef59
10 changed files with 1698 additions and 0 deletions
+1
View File
@@ -1,2 +1,3 @@
export * from "./auth.js";
export * from "./patients.js";
export * from "./notes.js";
+27
View File
@@ -0,0 +1,27 @@
import { index, pgTable, text, timestamp, uuid } from "drizzle-orm/pg-core";
import { organization, user } from "./auth.js";
// A doctor's freeform note, scoped to a clinic (organization) AND its author —
// notes are private to the doctor who wrote them within that clinic. `content`
// holds the rich-text editor's HTML.
export const notes = pgTable(
"notes",
{
id: uuid("id").primaryKey().defaultRandom(),
organizationId: text("organization_id")
.notNull()
.references(() => organization.id, { onDelete: "cascade" }),
authorId: text("author_id")
.notNull()
.references(() => user.id, { onDelete: "cascade" }),
title: text("title").notNull(),
content: text("content").notNull().default(""),
createdAt: timestamp("created_at").defaultNow().notNull(),
updatedAt: timestamp("updated_at")
.defaultNow()
.$onUpdate(() => new Date())
.notNull(),
},
(t) => [index("notes_org_author_idx").on(t.organizationId, t.authorId)],
);