-
Notifications
You must be signed in to change notification settings - Fork 12
Divyashree v/develop #7
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,38 +1,344 @@ | ||
| # Appointment Booking | ||
| # Appointment Booking System | ||
|
|
||
| ## Setup | ||
| A full-stack appointment booking platform built with Next.js, TypeScript, and Supabase with comprehensive testing and role-based access control. | ||
|
|
||
| 1. Go to [supabase.com](https://supabase.com), sign in, and create a new project | ||
| --- | ||
|
|
||
| 2. Once the project is ready, go to **SQL Editor** and run the contents of `schema.sql` | ||
| ## Table of Contents | ||
|
|
||
| 3. Place the `.env` file you received into the root of this project | ||
| - [Quick Start](#quick-start) | ||
| - [Architecture](#architecture) | ||
| - [API Endpoints](#api-endpoints) | ||
| - [Workflows](#workflows) | ||
| - [Database Schema](#database-schema) | ||
| - [Testing](#testing) | ||
|
Comment on lines
+13
to
+14
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Fix the broken table-of-contents links.
🧰 Tools🪛 markdownlint-cli2 (0.22.1)[warning] 13-13: Link fragments should be valid (MD051, link-fragments) [warning] 14-14: Link fragments should be valid (MD051, link-fragments) 🤖 Prompt for AI Agents |
||
| - [Credentials](#test-credentials) | ||
|
|
||
| 4. Install dependencies: | ||
| ```bash | ||
| npm install | ||
| ``` | ||
| --- | ||
|
|
||
| 5. Seed the database (creates all users, slots, and a sample appointment): | ||
| ```bash | ||
| npm run seed | ||
| ``` | ||
| ## Quick Start | ||
|
|
||
| 6. Start the dev server: | ||
| ```bash | ||
| npm run dev | ||
| ``` | ||
| ### 1. Setup Supabase | ||
|
|
||
| Go to [supabase.com](https://supabase.com), sign in, and create a new project. Once ready: | ||
|
|
||
| - Go to **SQL Editor** | ||
| - Click **"+ New Query"** | ||
| - Paste contents of `schema.sql` | ||
| - Click **Run** | ||
|
|
||
| ### 2. Configure Environment | ||
|
|
||
| Place the `.env` file in the root directory: | ||
|
|
||
| ```bash | ||
| NEXT_PUBLIC_SUPABASE_URL=your_supabase_url | ||
| NEXT_PUBLIC_SUPABASE_ANON_KEY=your_anon_key | ||
| SUPABASE_SERVICE_ROLE_KEY=your_service_role_key | ||
| ``` | ||
|
|
||
| ### 3. Install & Seed | ||
|
|
||
| ```bash | ||
| npm install | ||
| npm run seed # Creates users, admin, slots, and sample appointment | ||
| npm run dev # Start dev server | ||
| ``` | ||
|
|
||
| Open [http://localhost:3000](http://localhost:3000) | ||
|
|
||
| ### 4. Run Tests | ||
|
|
||
| ```bash | ||
| npm test # Run all tests | ||
| npm run test:unit # Unit tests only | ||
| npm run test:integration # Integration tests only | ||
| ``` | ||
|
|
||
| --- | ||
|
|
||
| ## Architecture | ||
|
|
||
| ### System Components | ||
|
|
||
| ``` | ||
| ┌─────────────────────────────────────────────────────────────┐ | ||
| │ Next.js Frontend │ | ||
| ├──────────────────┬──────────────────┬──────────────────────┤ | ||
| │ Patient Login │ Doctor Login │ Admin Login │ | ||
| │ Book/Cancel │ Mark Done │ View All Appts │ | ||
| └──────────────────┴──────────────────┴──────────────────────┘ | ||
| │ │ │ | ||
| ├────────────────┼────────────────────┤ | ||
| ▼ ▼ ▼ | ||
| ┌────────────────────────────────────────────────────┐ | ||
| │ API Routes (Next.js) │ | ||
| ├────────────────────────────────────────────────────┤ | ||
| │ POST /api/appointments/book │ | ||
| │ POST /api/appointments/cancel │ | ||
| │ POST /api/admin/login │ | ||
| └────────────────────────────────────────────────────┘ | ||
| │ | ||
| ▼ | ||
| ┌────────────────────────────────────────────────────┐ | ||
| │ Supabase (PostgreSQL + Auth) │ | ||
| ├────────────────────────────────────────────────────┤ | ||
| │ • Row-Level Security (RLS) Policies │ | ||
| │ • RPC Functions with SECURITY DEFINER │ | ||
| │ • Database Constraints & Indexes │ | ||
| └────────────────────────────────────────────────────┘ | ||
| ``` | ||
|
Comment on lines
+64
to
+90
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Add fence languages to the ASCII blocks. markdownlint is already flagging these unlabeled code fences. Using Also applies to: 307-333 🧰 Tools🪛 markdownlint-cli2 (0.22.1)[warning] 64-64: Fenced code blocks should have a language specified (MD040, fenced-code-language) 🤖 Prompt for AI Agents |
||
|
|
||
| ### Security Layers | ||
|
|
||
| 1. **Authentication**: Supabase Auth (JWT tokens) | ||
| 2. **Authorization**: Bearer tokens + role-based checks | ||
| 3. **Database**: RLS policies + RPC functions with SECURITY DEFINER | ||
| 4. **Sessions**: httpOnly cookies (24-hour expiry, sameSite="lax") | ||
|
|
||
| --- | ||
|
|
||
| ## API Endpoints | ||
|
|
||
| | Method | Endpoint | Authentication | Description | | ||
| | :--- | :--- | :--- | :--- | | ||
| | `POST` | `/api/admin/login` | None | Authenticates system admin and sets session cookie. | | ||
| | `POST` | `/api/appointments/book` | Bearer Token | Books an appointment for a patient. | | ||
| | `POST` | `/api/appointments/cancel` | Bearer Token | Cancels or completes an appointment. | | ||
|
|
||
|
|
||
| ### 1. Book Appointment | ||
|
|
||
| **POST** `/api/appointments/book` | ||
|
|
||
| **Authentication**: Bearer Token (Required) | ||
|
|
||
| **Request Body**: | ||
|
|
||
| ```json | ||
| { | ||
| "slotId": "uuid", | ||
| "doctorId": "uuid" | ||
| } | ||
| ``` | ||
|
|
||
| **Response** (201 Created): | ||
|
|
||
| ```json | ||
| { | ||
| "id": "uuid", | ||
| "patient_id": "uuid", | ||
| "doctor_id": "uuid", | ||
| "slot_id": "uuid", | ||
| "status": "active", | ||
| "created_at": "2026-04-29T10:00:00Z" | ||
| } | ||
| ``` | ||
|
|
||
| **Error Responses**: | ||
|
|
||
| - `401 Unauthorized` - Missing or invalid token | ||
| - `400 Bad Request` - Missing slotId or doctorId | ||
| - `404 Not Found` - Slot not found | ||
| - `409 Conflict` - Slot already booked, invalid doctor, slot in past, or duplicate active appointment | ||
|
|
||
| **Business Rules**: | ||
|
|
||
| - Slot must be available (is_booked = false) | ||
| - Slot must be in the future | ||
| - Slot must belong to selected doctor | ||
| - Patient cannot have another active appointment with same doctor | ||
| - All validated before database operation | ||
|
|
||
| --- | ||
|
|
||
| ### 2. Cancel/Done Appointment | ||
|
|
||
| **POST** `/api/appointments/cancel` | ||
|
|
||
| **Authentication**: Bearer Token (Required) | ||
|
|
||
| **Request Body**: | ||
|
|
||
| ```json | ||
| { | ||
| "appointmentId": "uuid", | ||
| "action": "cancel" | "done" | ||
| } | ||
| ``` | ||
|
|
||
| **Response** (200 OK): | ||
|
|
||
| ```json | ||
| { | ||
| "id": "uuid", | ||
| "patient_id": "uuid", | ||
| "doctor_id": "uuid", | ||
| "slot_id": "uuid", | ||
| "status": "cancelled" | "done", | ||
| "created_at": "2026-04-29T10:00:00Z" | ||
| } | ||
| ``` | ||
|
|
||
|
|
||
|
|
||
| **Business Rules**: | ||
|
|
||
| - Patient can cancel anytime (except within 1 hour of start) | ||
| - Doctor can cancel/mark done anytime | ||
| - Cannot cancel already done/cancelled appointments | ||
| - Slot marked as available (is_booked = false) on cancellation | ||
| - Only doctors can mark appointments as "done" | ||
|
|
||
| **Role-Based Access**: | ||
| | Role | Can Cancel | Can Mark Done | 1-Hour Rule | | ||
| |------|-----------|---------------|------------| | ||
| | Patient | Yes (>1hr) | No | Yes | | ||
| | Doctor | Yes | Yes | No | | ||
|
|
||
| --- | ||
|
|
||
| ### 3. Admin Login | ||
|
|
||
| **POST** `/api/admin/login` | ||
|
|
||
| **Authentication**: None (Public) | ||
|
|
||
| **Request Body**: | ||
|
|
||
| ```json | ||
| { | ||
| "email": "admin@test.com", | ||
| "password": "admin123" | ||
| } | ||
| ``` | ||
|
|
||
| **Response** (200 OK): | ||
|
|
||
| ```json | ||
| { | ||
| "success": true | ||
| } | ||
| ``` | ||
|
|
||
| Sets `admin_session` cookie: `admin_<adminId>` (httpOnly, 24-hour expiry) | ||
|
|
||
| **Error Responses**: | ||
|
|
||
| - `400 Bad Request` - Missing email or password | ||
| - `401 Unauthorized` - Invalid credentials | ||
|
|
||
| --- | ||
|
|
||
| ## Workflows | ||
|
|
||
| ### Booking Flow | ||
|
|
||
| ```mermaid | ||
| sequenceDiagram | ||
| Patient->>UI: Enter slot & doctor | ||
| UI->>API: POST /api/appointments/book<br/>Authorization: Bearer token | ||
| API->>API: Validate token & user | ||
| API->>DB: Fetch slot details | ||
| API->>API: Validate slot available | ||
| API->>API: Validate slot in future | ||
| API->>API: Validate no duplicate booking | ||
| API->>DB: RPC book_appointment() | ||
| DB->>DB: Lock slot FOR UPDATE | ||
| DB->>DB: Verify slot available | ||
| DB->>DB: Update slot is_booked=true | ||
| DB->>DB: Insert appointment | ||
| DB-->>API: Return appointment | ||
| API-->>UI: 201 Created + appointment | ||
| UI->>UI: Show success & refresh | ||
| ``` | ||
|
|
||
| ### Cancellation Flow | ||
|
|
||
| ```mermaid | ||
| sequenceDiagram | ||
| User->>UI: Click cancel appointment | ||
| UI->>API: POST /api/appointments/cancel<br/>Authorization: Bearer token | ||
| API->>API: Validate token & user | ||
| API->>DB: Fetch appointment | ||
| API->>API: Check authorization (owner) | ||
| API->>DB: Fetch slot details | ||
| API->>API: Validate appointment cancellable | ||
| API->>API: Check cancellation window (if patient) | ||
| DB->>DB: Update appointment status='cancelled' | ||
| DB->>DB: Update slot is_booked=false | ||
| DB-->>API: Return updated appointment | ||
| API-->>UI: 200 OK + updated status | ||
| UI->>UI: Show success & refresh | ||
| ``` | ||
|
|
||
| ### Admin Dashboard Flow | ||
|
|
||
| ```mermaid | ||
| sequenceDiagram | ||
| Admin->>UI: Visit /admin/dashboard | ||
| UI->>UI: Check admin_session cookie | ||
| UI->>DB: Fetch all appointments (server-side) | ||
| DB->>DB: Apply RLS policies | ||
| DB-->>UI: Return appointments | ||
| UI->>UI: Render table | ||
| ``` | ||
|
|
||
| --- | ||
|
|
||
| --- | ||
|
|
||
| ## Test Credentials | ||
|
|
||
| | Role | Email | Password | | ||
| |----------|---------------------|------------| | ||
| | Doctor 1 | doctor1@test.com | doctor123 | | ||
| | Doctor 2 | doctor2@test.com | doctor123 | | ||
| | Doctor 3 | doctor3@test.com | doctor123 | | ||
| | Patient 1| patient1@test.com | patient123 | | ||
| | Patient 2| patient2@test.com | patient123 | | ||
| | Patient 3| patient3@test.com | patient123 | | ||
| | Admin | admin@test.com | admin123 | | ||
| | Role | Email | Password | | ||
| | --------- | ----------------- | ---------- | | ||
| | Doctor 1 | doctor1@test.com | doctor123 | | ||
| | Doctor 2 | doctor2@test.com | doctor123 | | ||
| | Doctor 3 | doctor3@test.com | doctor123 | | ||
| | Patient 1 | patient1@test.com | patient123 | | ||
| | Patient 2 | patient2@test.com | patient123 | | ||
| | Patient 3 | patient3@test.com | patient123 | | ||
| | Admin | admin@test.com | admin123 | | ||
|
|
||
| --- | ||
|
|
||
| ## Project Structure | ||
|
|
||
| ``` | ||
| ├── app/ | ||
| │ ├── api/ | ||
| │ │ ├── admin/login/ # Admin authentication | ||
| │ │ └── appointments/ | ||
| │ │ ├── book/ # Booking endpoint | ||
| │ │ └── cancel/ # Cancellation endpoint | ||
| │ ├── admin/ | ||
| │ │ ├── dashboard/ # Admin dashboard (SSR) | ||
| │ │ └── login/ # Admin login page | ||
| │ ├── doctor/dashboard/ # Doctor portal | ||
| │ ├── patient/dashboard/ # Patient portal | ||
| │ └── layout.tsx | ||
| ├── lib/ | ||
| │ ├── supabase.ts # Client Supabase | ||
| │ ├── supabaseAdmin.ts # Admin Supabase | ||
| │ └── validators.ts # Business logic | ||
| ├── tests/ | ||
| │ ├── unit/validators.test.ts | ||
| │ ├── integration/ | ||
| │ │ ├── booking.test.ts | ||
| │ │ ├── cancellation.test.ts | ||
| │ │ └── guards.test.ts | ||
| ├── schema.sql # Database schema | ||
| └── seed.mjs # Database seeding | ||
|
|
||
| ``` | ||
|
|
||
| --- | ||
|
|
||
| ## Security Considerations | ||
|
|
||
| ### Implemented | ||
|
|
||
| - **Token Validation** - All API routes verify JWT tokens | ||
| - **Role-Based Access** - Different rules for patient/doctor/admin | ||
| - **SQL Injection Prevention** - Using RPC functions & parameterized queries | ||
| - **Password Security** - bcrypt hashing (admin passwords) | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Don't ignore versioned SQL migrations by filename pattern.
migration-*.sqlandmigration-*.txtare broad enough to hide real schema migrations, which makes database changes easy to ship without source control. Scope these ignores to a temp directory or to exact generated filenames instead.🤖 Prompt for AI Agents