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
+3
View File
@@ -12,6 +12,7 @@ import { activityRouter } from "./routes/activity.js";
import { analyticsRouter } from "./routes/analytics.js";
import { appointmentsRouter } from "./routes/appointments.js";
import { conversationsRouter } from "./routes/conversations.js";
import { inventoryRouter } from "./routes/inventory.js";
import { notesRouter } from "./routes/notes.js";
import { notificationsRouter } from "./routes/notifications.js";
import { patientsRouter } from "./routes/patients.js";
@@ -59,6 +60,7 @@ app.use("/api/patients", patientsRouter);
app.use("/api/notes", notesRouter);
app.use("/api/appointments", appointmentsRouter);
app.use("/api/prescriptions", prescriptionsRouter);
app.use("/api/inventory", inventoryRouter);
app.use("/api/tasks", tasksRouter);
app.use("/api/staff", staffRouter);
app.use("/api/activity", activityRouter);
@@ -81,6 +83,7 @@ server.listen(env.PORT, () => {
console.log(` • notes: /api/notes`);
console.log(` • appts: /api/appointments`);
console.log(` • rx: /api/prescriptions`);
console.log(` • stock: /api/inventory`);
console.log(` • tasks: /api/tasks`);
console.log(` • staff: /api/staff`);
console.log(` • activity: /api/activity`);