From 51d604d6eecda2c6cb1bb8f6b80a9f56ac26a6e5 Mon Sep 17 00:00:00 2001 From: Ashir Ali <32892597+AshirAli@users.noreply.github.com> Date: Thu, 23 Apr 2026 15:00:57 +0530 Subject: [PATCH] fix: docker compose .env, gitignore updates --- .gitignore | 1 + CLAUDE.md | 102 +++++++++++++++++++++++++++++++++++++++++ backend/.gitignore | 2 +- docker-compose.dev.yml | 74 +++++++++++++++--------------- frontend/.gitignore | 2 +- 5 files changed, 142 insertions(+), 39 deletions(-) create mode 100644 .gitignore create mode 100644 CLAUDE.md diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..2eea525 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +.env \ No newline at end of file diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..06e47b1 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,102 @@ +# CLAUDE.md + +This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. + +## Repository layout + +Monorepo with two independent npm packages plus a shared Docker dev stack: + +- `backend/` — Node.js + Express 5 (ESM) API, Prisma ORM over PostgreSQL. +- `frontend/` — React 19 + Vite + TypeScript admin dashboard, styled with Tailwind 4 + shadcn/ui. +- `docker/` — Dev Dockerfiles + `entrypoint.sh` (used by `docker-compose.dev.yml` at repo root). + +There is no root-level package script — run npm commands inside `backend/` or `frontend/`. + +## Common commands + +### Docker (full stack) + +```bash +docker compose -f docker-compose.dev.yml up --build # backend :5008, frontend :3008, postgres :5432 (internal) +docker compose -f docker-compose.dev.yml down +``` + +The backend container's `entrypoint.sh` runs `prisma generate` then `prisma db push` (NOT `migrate deploy`) on every start — schema changes propagate without a migration step in the Docker dev flow. + +### Backend (`cd backend`) + +```bash +npm run dev # nodemon src/app.js +npm start # node src/app.js +npm run migrate # npx prisma migrate dev (use this locally; Docker uses db push) +npm run generate # npx prisma generate +npx prisma studio # GUI for the DB +npm run create-user [role] # role defaults to "admin" +``` + +In Docker, create an admin via: +```bash +docker exec -it gg-backend-api-backend-1 node src/utils/createUser.js +``` + +### Frontend (`cd frontend`) + +```bash +npm run dev # Vite dev server +npm run build # tsc -b && vite build +npm run lint # eslint . +npm run preview +``` + +There is no test runner configured in either package. + +## Architecture + +### Backend + +Single Express app assembled in `backend/src/app.js`. Each domain follows the same triplet: + +- `src/routes/.routes.js` — declares the Express router, applies `jwtAuthMiddleware` per-route (mixed public/protected within the same router; see `blog.routes.js` for the pattern: list/detail public, admin endpoints + writes protected). +- `src/controllers/.controller.js` — handler logic; uses Prisma directly. +- Mounted at `/api/` in `app.js`. + +Domains: `departments`, `auth`, `blogs`, `upload`, `doctors`, `careers`, `candidates`, `appointments`, `inquiry`, `academics`, `email`, `newsMedia`, `import`. Static `uploads/` is served at `/uploads`. + +Cross-cutting pieces: + +- **Prisma client** — `src/prisma/client.js` exports a singleton. Always import from there rather than instantiating `new PrismaClient()` (the import controller currently instantiates its own — match the singleton pattern when adding new code). +- **Auth** — `src/middleware/auth.js` expects `Authorization: Bearer `, attaches the decoded payload to `req.user`. Tokens are issued by `src/utils/jwt.js` using `JWT_SECRET`. Passwords hashed via `src/utils/password.js` (bcrypt). +- **Email** — `src/utils/sendEmail.js` wraps Postmark with `EMAIL_FROM` as sender. Recipient lists are looked up by category via `getEmailsByType(type)` against the `EmailConfig` table — controllers call this to fan out notifications (e.g. on new appointments/inquiries). +- **CORS** — `CORS_ALLOWED_ORIGINS` is a **space-separated** list (not comma-separated). Requests with no `Origin` header are allowed. +- **Body limits** — JSON/urlencoded bodies are capped at 50mb to support image-laden Editor.js payloads and bulk Excel imports. + +### Data model (Prisma — `backend/prisma/schema.prisma`) + +Note the natural-key relations: `Appointment.doctorId` references `Doctor.doctorId` (the string business ID), not `Doctor.id`. Same for `Department`. The `SL_NO` / `GG_ID` columns from imports become these business IDs. `Doctor` ↔ `Department` is many-to-many through `DoctorDepartment`, which has a 1:1 `DoctorTiming` for weekday schedules. `NewsMedia` has cascading `NewsImage` children. + +### Frontend + +- Routing in `src/App.tsx`: `PublicRoute` wraps `/` (Login); everything else is wrapped by `ProtectedRoute` → `DashboardLayout`. Unknown paths redirect to `/department`. +- `src/context/AuthContext.tsx` is the auth source of truth; `src/services/api.ts` is the shared Axios instance that auto-injects `Authorization: Bearer ` from `localStorage.getItem("token")`. +- `src/api/.ts` files are thin wrappers around that axios client, one per backend domain — keep this pattern when adding endpoints. +- Path alias `@/*` → `src/*` (configured in both `vite.config.ts` and `tsconfig`). +- File uploads go through Bytescale (`src/components/BytescaleUploader`) — server only stores the resulting URL. +- The `/import` page parses Excel via `xlsx` and POSTs structured payloads to `/api/import`, where `importController.js` upserts across multiple tables. When changing import behavior, the frontend's column names (`SL_NO`, `GG_ID`, `Department`, `Working Status`, etc.) and the controller's destructured keys (`departments`, `doctors`, `timings`, …) must stay in sync. + +## Environment variables + +`backend/.env`: +``` +DATABASE_URL=postgresql://user:password@db:5432/mydb +PORT=5008 +JWT_SECRET=... +CORS_ALLOWED_ORIGINS=http://localhost:5173 # space-separated for multiple +BYTESCALE_SECRET_API_KEY=... +POSTMARK_API_KEY=... +EMAIL_FROM=admin@example.com +``` + +`frontend/.env`: +``` +VITE_API_URL=http://localhost:5008/api +``` diff --git a/backend/.gitignore b/backend/.gitignore index 126419d..a97f88f 100644 --- a/backend/.gitignore +++ b/backend/.gitignore @@ -1,5 +1,5 @@ node_modules # Keep environment variables out of version control -.env +.env* /src/generated/prisma diff --git a/docker-compose.dev.yml b/docker-compose.dev.yml index dad81f7..680b0b3 100644 --- a/docker-compose.dev.yml +++ b/docker-compose.dev.yml @@ -1,44 +1,44 @@ version: "3.8" services: - backend: - build: - context: . - dockerfile: docker/dev/Dockerfile.main - ports: - - "5008:5008" - env_file: - - ./backend/.env - depends_on: - db: - condition: service_healthy - restart: unless-stopped + backend: + build: + context: . + dockerfile: docker/dev/Dockerfile.main + ports: + - "127.0.0.1:5008:5008" + env_file: + - ./backend/.env + depends_on: + db: + condition: service_healthy + restart: unless-stopped - frontend: - build: - context: . - dockerfile: docker/dev/Dockerfile.frontend - ports: - - "3008:3000" - env_file: - - ./frontend/.env - restart: unless-stopped + frontend: + build: + context: . + dockerfile: docker/dev/Dockerfile.frontend + ports: + - "127.0.0.1:3008:3000" + env_file: + - ./frontend/.env + restart: unless-stopped - db: - image: postgres:16-alpine - container_name: postgres_db - environment: - POSTGRES_USER: user - POSTGRES_PASSWORD: password - POSTGRES_DB: mydb - volumes: - - postgres_data:/var/lib/postgresql/data - healthcheck: - test: ["CMD-SHELL", "pg_isready -U user -d mydb"] - interval: 5s - timeout: 5s - retries: 5 - restart: unless-stopped + db: + image: postgres:16-alpine + container_name: postgres_db + environment: + - POSTGRES_USER=${POSTGRES_USER} + - POSTGRES_PASSWORD=${POSTGRES_PASSWORD} + - POSTGRES_DB=${POSTGRES_DB} + volumes: + - postgres_data:/var/lib/postgresql/data + healthcheck: + test: ["CMD-SHELL", "pg_isready -U $$POSTGRES_USER -d $$POSTGRES_DB"] + interval: 5s + timeout: 5s + retries: 5 + restart: unless-stopped volumes: - postgres_data: + postgres_data: diff --git a/frontend/.gitignore b/frontend/.gitignore index 577121c..3a74d5d 100644 --- a/frontend/.gitignore +++ b/frontend/.gitignore @@ -24,6 +24,6 @@ dist-ssr *.sw? #env files -.env +.env* .env.*.local