abdulrehmankz1/clinic-management

GitHub: abdulrehmankz1/clinic-management

基于 Payload CMS 3、Next.js 16 和 MongoDB 构建的多租户诊所管理 SaaS,为小型诊所提供预约排班、患者登记和严格的数据隔离能力。

Stars: 1 | Forks: 0

# matab — 诊所管理 [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE) [![Stars](https://img.shields.io/github/stars/abdulrehmankz1/clinic-management?style=social)](https://github.com/abdulrehmankz1/clinic-management/stargazers) [![Forks](https://img.shields.io/github/forks/abdulrehmankz1/clinic-management?style=social)](https://github.com/abdulrehmankz1/clinic-management/network/members) 一个基于 **Payload CMS 3**、**Next.js 16** 和 **MongoDB** 构建的多租户**诊所管理** 系统。多家诊所共享一个部署,但每家诊所只能看到自己的 数据 —— 围绕着一条不可妥协的核心原则构建:**一家诊所永远无法查看或触碰另一家 诊所的数据。** v1 包含多租户核心:员工与角色、患者、 带有双重预订防护的预约、Walk-in token 以及仪表盘。 ![matab 日视图](https://static.pigsec.cn/wp-content/uploads/repos/2026/06/c0a8396858051942.png) ## 🎬 演示 — 所有者操作指南 以诊所**所有者**身份进行的一次完整的端到端操作,涵盖了日常的前台流程: 三种方式的预订(预约、Walk-in 以及在预订时内联添加全新患者)、查看 预订在日视图中的位置、注册患者、添加医生以及查看 诊所设置。 Owner walkthrough — booking, patients, staff & settings ▶ 高清版:观看 MP4 **展示内容** - **三种方式的预订** — 为现有患者安排的(在线)预约、获取 排队 token 的**Walk-in**,以及在预订时内联添加的全新患者。 - **预订位置** — 每个预订都会显示在每位医生的**日视图 (day view)** 时间线上。 - **患者** — 可搜索的目录 + 使用完整病历 (自动分配 MRN)注册新患者。 - **员工** — 添加具有专业、费用和每周空闲时间的新医生。 - **设置** — 诊所资料、工作时间、货币与时区。 ## 痛点 小诊所 —— 一到几个医生,一名接待员 —— 仍然在依赖纸质预约 登记本、散落文件袋中的患者历史记录以及现金抽屉。现有的医院系统 昂贵、复杂,且需要 IT 人员维护。这里缺少一个廉价、简单、 接待员能在半小时内学会的多诊所工具。 ## ✨ 功能 (v1) - **多租户** — 一个应用,一个数据库,完全隔离的诊所(“租户”)。 - **身份验证与角色** — `superAdmin`(平台级),以及每家诊所的 `owner`、`doctor`、 `receptionist`,每个角色都有独立的访问权限。 - **患者** — 按姓名、电话或 MRN 注册/搜索;自动分配每家诊所的患者编号 (`P-0001`);过敏提示横幅;相同号码重复警告(家庭成员共享电话)。 - **预约** — 具有两种模式的日视图:**队列列表**(按时间排序,一键 *Check in / Complete* — 专为非技术前台员工设计)和每位医生的 **时间线**(空闲窗口、当前时间线、并排显示重叠时段的通道)。 状态流程(`scheduled → checked-in → completed / cancelled / no-show`)以及 一个会拒绝重叠时段的**双重预订防护**。 - **医生排班** — 每位医生可以是 `regular`(设定工作日 + 每日窗口,例如 周一/周三/周五 4-6 点)、`on-call`(任何时间)或 `by-appointment`(客座外科医生 — 在 自动查找器中隐藏)。在常规医生的窗口之外禁止预订,并且 **“这个时间哪些医生有空?”** 查找器为电话预约流程提供支持。 - **Walk-in** — 先到先得,每家诊所每天自动分配 **token 编号**(`T-01`,`T-02`…) 显示在 Day Rail 上。 - **仪表盘** — 今天的 KPI、14 天活动图表、即将到来的列表、值班医生、 快捷操作和最近注册的患者。 - **超级管理控制台** — 创建诊所(所有者原子化创建),暂停/重新激活。 - **UI** — 基于 Tailwind v4 + shadcn/ui 的青色“临床宁静”设计系统;深色侧边栏应用 外壳;带有一键演示登录的着陆页;对每个待处理操作提供 spinner 反馈。 ## 🔐 多租户设计 租户隔离墙存在于**一个地方** — 访问控制函数(`src/access/`),该函数 返回一个 Mongo `where` 约束,Payload 将其合并到每个查询中,例如 `{ tenant: { equals: user.tenant } }`。它是**默认拒绝**的:任何无法 明确确定租户的请求都会返回 `false`。 - **设定它,而不是信任它** — 一个 `beforeChange` hook 会从 登录用户那里强制设定 `tenant`;无论客户端发送什么都会被覆盖。`tenant` 在创建后是不可变的。 - **客户端永远不决定范围** — tenant 始终在服务端派生。 - **自定义,而不是插件** — 一组约 150 行的访问辅助函数,而不是官方的 多租户插件,因此每一行都是可解释的,并且没有版本耦合。 - **通过测试证明** — `tests/int/isolation.int.spec.ts` 断言跨租户的 读取/写入会失败,并且植入的外部租户会被强制纠正。 ## ⏱️ 双重预订防护 同一位医生的两个预约在以下情况下冲突: `existing.start < new.end && existing.end > new.start`(边缘接触不冲突)。 检查运行**在请求的 MongoDB transaction 内部**,并且 在 `(tenant, doctor, start)` 上的**部分唯一索引**(仅限有效状态)是确定性的兜底方案,因此对 同一时段的两个同时预订不可能同时成功 — 其中一个会中止。竞态测试 (两个相同预订的 `Promise.all`)证明了只有一个会成功。 ## 🌍 设计上的市场无关性 没有硬编码任何特定于地区的内容。每家诊所都有各自的**货币**和**时区** 作为设置(默认 `PKR` / `Asia/Karachi`)。所有资金流经 `formatMoney(amount, tenant)`,所有时间流经 `formatTime(date, tenant)`。巴基斯坦是 首发市场,而不是限制。 ## 🧱 技术栈 | 层级 | 选择 | |---|---| | CMS / API / Auth | Payload CMS 3 | | Web | Next.js 16 (App Router) + React 19 | | DB | MongoDB (replica set — 用于 transaction) | | 样式 | Tailwind CSS v4 + shadcn/ui (Base UI) + lucide-react | | 测试 | Vitest (Payload Local API 集成测试) | ## 🚀 快速开始 ``` pnpm install cp .env.example .env # then fill PAYLOAD_SECRET docker compose up -d # MongoDB as a single-node replica set (rs0) pnpm seed # 3 demo clinics, staff, patients, appointments pnpm dev # http://localhost:3000 ``` ### 演示登录(密码:`password123`) | 角色 | 邮箱 | |---|---| | Super Admin | `super@clinic.app` | | Owner — City Care | `owner@city.app` | | Receptionist — City Care | `reception@city.app` | | Doctor — City Care | `doctor1@city.app` | | Owner — Shifa | `owner@shifa.app` | 先以 City Care 登录,然后以 Shifa 登录 — 数据完全不同。这就是租户隔离墙。 ## ✅ 测试 ``` pnpm test # 34 integration tests: isolation, booking guard, availability, walk-in tokens ``` ## 📁 项目结构 ``` src/ access/ # the tenant wall — isSuperAdmin, tenantScoped, field-level rules app/(frontend)/ # landing, login, dashboard/* (appointments, patients, staff, settings), super app/(payload)/ # admin panel & REST/GraphQL API (super admin only) collections/ # Tenants, Users, Patients, Appointments components/ # DayRail (List + Timeline), BookingForm, StaffManager, SuperConsole, Sidebar, ui/ hooks/ # forceTenant (set-it-don't-trust-it) lib/ # booking.ts, availability.ts, reports.ts, format.ts, constants.ts seed.ts payload.config.ts public/images/ # landing/login photography (Unsplash) + product shot tests/int/ # isolation, booking, overlap, availability, walk-in suites ``` ## 🗺️ 路线图 v1(当前版本)是多租户基础。后续版本(临床就诊与处方、 计费、自助注册)已规划,但在目前有意排除在范围之外。 ## 📜 许可证 该项目基于 **MIT License** 授权 — 详情请参阅 [LICENSE](LICENSE) 文件。 您可以将其用于商业和私人用途、修改并分发它;只需保留 版权和许可证声明完整即可。
标签:MongoDB, Payload CMS, SaaS, 医疗管理, 自动化攻击, 请求拦截, 预约系统