106 lines
4.3 KiB
Markdown
106 lines
4.3 KiB
Markdown
# QueueMed — Salle d'attente virtuelle pour cabinets médicaux
|
|
|
|
## Architecture
|
|
- **Frontend**: React 19, Vite 6, Tailwind CSS 4, shadcn/ui, wouter, Framer Motion, Recharts, Socket.io-client
|
|
- **Backend**: Express 4, tRPC 11, Socket.io 4, Drizzle ORM
|
|
- **Database**: MySQL 8
|
|
- **Auth**: JWT + session cookie (simple email/password login, no OAuth)
|
|
- **QR Code**: qrcode npm package with rotating anti-cheat tokens
|
|
- **Deploy**: Docker + docker-compose, Nginx Proxy Manager for HTTPS
|
|
|
|
## Theme — MEDICAL LIGHT
|
|
- **Primary**: #10b981 (emerald-500) and #06b6d4 (cyan-500)
|
|
- **Background**: white / #f0fdf4 (green-50) / #ecfeff (cyan-50)
|
|
- **Cards**: white with subtle shadow, glass-morphism (backdrop-blur, bg-white/70)
|
|
- **Accents**: #0d9488 (teal-600) for CTAs, #f97316 (orange-500) for alerts
|
|
- **Feel**: clean, hygienic, medical — light green/cyan, translucent panels, rounded corners
|
|
- **Font**: Inter (Google Fonts)
|
|
|
|
## Database Schema (see docs_ref/schema.ts)
|
|
5 tables: users, subscriptions, clinics, queueEntries, analyticsEvents
|
|
|
|
## Key Routes
|
|
| Route | Page | Access |
|
|
|---|---|---|
|
|
| / | Landing page (hero, features, pricing, testimonials) | Public |
|
|
| /login | Login page | Public |
|
|
| /dashboard | Doctor dashboard (KPIs, clinic list, quick actions) | Auth |
|
|
| /dashboard/clinics | Manage clinics (CRUD, QR code, settings) | Auth |
|
|
| /dashboard/queue/:clinicId | Real-time queue management | Auth |
|
|
| /dashboard/analytics | Charts, CSV export, AI recommendations | Auth |
|
|
| /dashboard/subscription | Subscription plans, trial, blocking | Auth |
|
|
| /display/:clinicId | Display screen for tablet/monitor | Public |
|
|
| /queue/:token | Patient interface (live position, alerts) | Public |
|
|
| /ticket/:entryId | Printable ticket | Public |
|
|
|
|
## Project Structure
|
|
```
|
|
/home/ubuntu/queue-med-deploy/
|
|
├── client/
|
|
│ ├── src/
|
|
│ │ ├── main.tsx # React entry + wouter router
|
|
│ │ ├── App.tsx # Layout shell
|
|
│ │ ├── lib/
|
|
│ │ │ └── trpc.ts # tRPC client setup
|
|
│ │ ├── components/
|
|
│ │ │ └── ui/ # shadcn/ui components
|
|
│ │ ├── _core/
|
|
│ │ │ └── hooks/
|
|
│ │ │ └── useAuth.ts
|
|
│ │ └── pages/
|
|
│ │ ├── Home.tsx # Landing
|
|
│ │ ├── Login.tsx
|
|
│ │ ├── Dashboard.tsx
|
|
│ │ ├── DoctorClinics.tsx
|
|
│ │ ├── QueueManagement.tsx
|
|
│ │ ├── Analytics.tsx
|
|
│ │ ├── PatientQueue.tsx
|
|
│ │ ├── DisplayScreen.tsx
|
|
│ │ ├── SubscriptionPage.tsx
|
|
│ │ ├── PrintTicket.tsx
|
|
│ │ ├── Onboarding.tsx
|
|
│ │ ├── Help.tsx
|
|
│ │ └── QrPoster.tsx
|
|
│ └── index.html
|
|
├── server/
|
|
│ ├── _core/
|
|
│ │ ├── index.ts # Express + Socket.io server
|
|
│ │ ├── trpc.ts # tRPC setup
|
|
│ │ └── context.ts # Auth context
|
|
│ ├── routers.ts # All tRPC procedures
|
|
│ ├── db.ts # Drizzle helpers
|
|
│ ├── schema.ts # Drizzle schema
|
|
│ └── auth.ts # JWT auth logic
|
|
├── shared/
|
|
│ └── types.ts # Shared types
|
|
├── drizzle.config.ts
|
|
├── vite.config.ts
|
|
├── tsconfig.json
|
|
├── package.json
|
|
├── Dockerfile
|
|
├── docker-compose.yml
|
|
└── .dockerignore
|
|
```
|
|
|
|
## Environment Variables
|
|
- DATABASE_URL — MySQL connection string
|
|
- JWT_SECRET — Secret for JWT signing
|
|
- PORT — Server port (default 5000)
|
|
- NODE_ENV — production/development
|
|
|
|
## Socket.io Rooms
|
|
- clinic:{clinicId} — Doctor + display screen
|
|
- patient:{patientToken} — Individual patient
|
|
- display:{clinicId} — Display screen only
|
|
|
|
## Commands
|
|
- pnpm dev — Start dev server
|
|
- pnpm build — Production build
|
|
- pnpm db:push — Push Drizzle migrations
|
|
- pnpm start — Start production server
|
|
|
|
## CRITICAL NOTES
|
|
- Use existing pages in src_ref/ as reference for UI patterns and tRPC calls
|
|
- The QR token rotation system is anti-cheat: tokens expire on schedule
|
|
- Subscription middleware blocks sensitive procedures when expired
|
|
- Socket.io is initialized in server/_core/index.ts and exposed globally
|