4.3 KiB
4.3 KiB
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