backend: org-scoped pharmacy inventory model

Add an `inventory` resource mirroring the prescriptions feature end-to-end:
Drizzle table (org-scoped, indexed), domain type, zod validation, service
(list/get/create/update/delete), and an RBAC-gated CRUD router mounted at
/api/inventory. Grant the new `inventory` statement to roles — pharmacy gets
read/write, full clinicians read/write/delete, reception/lab none — in both the
backend access control and (mirrored) the frontend. Record writes in the
activity log via a new `inventory` entity type. Includes the migration and an
idempotent demo seed script.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Khalid Abdi
2026-06-12 19:16:28 +03:00
parent 91e4f4ed30
commit 67fdf15de4
13 changed files with 3061 additions and 0 deletions
+20
View File
@@ -0,0 +1,20 @@
CREATE TABLE "inventory" (
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
"organization_id" text NOT NULL,
"name" text NOT NULL,
"form" text DEFAULT '' NOT NULL,
"strength" text DEFAULT '' NOT NULL,
"unit" text DEFAULT '' NOT NULL,
"stock_quantity" integer DEFAULT 0 NOT NULL,
"reorder_threshold" integer DEFAULT 0 NOT NULL,
"location" text DEFAULT '' NOT NULL,
"expires_at" date,
"notes" text,
"created_by" text,
"created_at" timestamp DEFAULT now() NOT NULL,
"updated_at" timestamp DEFAULT now() NOT NULL
);
--> statement-breakpoint
ALTER TABLE "inventory" ADD CONSTRAINT "inventory_organization_id_organization_id_fk" FOREIGN KEY ("organization_id") REFERENCES "public"."organization"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
ALTER TABLE "inventory" ADD CONSTRAINT "inventory_created_by_user_id_fk" FOREIGN KEY ("created_by") REFERENCES "public"."user"("id") ON DELETE set null ON UPDATE no action;--> statement-breakpoint
CREATE INDEX "inventory_org_idx" ON "inventory" USING btree ("organization_id");
File diff suppressed because it is too large Load Diff
+7
View File
@@ -85,6 +85,13 @@
"when": 1781196252617,
"tag": "0011_remap_viewer_to_member",
"breakpoints": true
},
{
"idx": 12,
"version": "7",
"when": 1781279151289,
"tag": "0012_wonderful_terrax",
"breakpoints": true
}
]
}