From 70cfff90ce601745363925ddedd339a08a654031 Mon Sep 17 00:00:00 2001 From: Potenz Date: Wed, 10 Sep 2025 01:21:15 +0530 Subject: [PATCH] chore: document and standardize hosts/ports across apps --- README.md | 3 + apps/Backend/.env.example | 5 +- apps/Backend/src/app.ts | 47 +++++++++- apps/Backend/src/index.ts | 15 +++- apps/Frontend/.env.example | 6 +- apps/Frontend/vite.config.ts | 33 +++---- apps/PatientDataExtractorService/.env.example | 2 + apps/PatientDataExtractorService/main.py | 44 +++++++--- apps/PaymentOCRService/main.py | 6 +- apps/SeleniumService/.env.example | 2 + apps/SeleniumService/agent.py | 7 +- docs/ports.md | 88 +++++++++++++++++++ package.json | 2 +- 13 files changed, 218 insertions(+), 42 deletions(-) create mode 100644 apps/PatientDataExtractorService/.env.example create mode 100644 apps/SeleniumService/.env.example create mode 100644 docs/ports.md diff --git a/README.md b/README.md index 9454046..751837e 100644 --- a/README.md +++ b/README.md @@ -45,6 +45,9 @@ cd apps/SeleniumService python3 agent.py ``` +## πŸ“– Developer Documentation + +- [Development Hosts & Ports](docs/ports.md) β€” which app runs on which host/port ## This in a Turborepo. What's inside? diff --git a/apps/Backend/.env.example b/apps/Backend/.env.example index 0737bf1..bf8de98 100644 --- a/apps/Backend/.env.example +++ b/apps/Backend/.env.example @@ -1,6 +1,7 @@ -HOST=localhost +NODE_ENV="development" +HOST=0.0.0.0 PORT=5000 -FRONTEND_URL=http://localhost:3000 +FRONTEND_URLS=http://localhost:3000,http://192.168.1.8:3000 JWT_SECRET = 'dentalsecret' DB_HOST=localhost DB_USER=postgres diff --git a/apps/Backend/src/app.ts b/apps/Backend/src/app.ts index 244403a..ba0dd03 100644 --- a/apps/Backend/src/app.ts +++ b/apps/Backend/src/app.ts @@ -9,7 +9,11 @@ import dotenv from "dotenv"; import { startBackupCron } from "./cron/backupCheck"; dotenv.config(); -const FRONTEND_URL = process.env.FRONTEND_URL; +const NODE_ENV = ( + process.env.NODE_ENV || + process.env.ENV || + "development" +).toLowerCase(); const app = express(); @@ -17,9 +21,48 @@ app.use(express.json()); app.use(express.urlencoded({ extended: true })); // For form data app.use(apiLogger); +// --- CORS handling (flexible for dev and strict for prod) --- +/** + * FRONTEND_URLS env value: comma-separated allowed origins + * Example: FRONTEND_URLS=http://localhost:3000,http://192.168.1.8:3000 + */ +const rawFrontendUrls = + process.env.FRONTEND_URLS || process.env.FRONTEND_URL || ""; +const FRONTEND_URLS = rawFrontendUrls + .split(",") + .map((s) => s.trim()) + .filter(Boolean); + +// helper to see if origin is allowed +function isOriginAllowed(origin?: string | null) { + if (!origin) return true; // allow non-browser clients (curl/postman) + + if (NODE_ENV !== "production") { + // Dev mode: allow localhost origins automatically + if ( + origin.startsWith("http://localhost") || + origin.startsWith("http://127.0.0.1") + ) + return true; + // allow explicit FRONTEND_URLS if provided + if (FRONTEND_URLS.includes(origin)) return true; + // optionally allow the server's LAN IP if FRONTEND_LAN_IP is provided + const lanIp = process.env.FRONTEND_LAN_IP; + if (lanIp && origin.startsWith(`http://${lanIp}`)) return true; + // fallback: deny if not matched + return false; + } + + // production: strict whitelist β€” must match configured FRONTEND_URLS exactly + return FRONTEND_URLS.includes(origin); +} + app.use( cors({ - origin: FRONTEND_URL, + origin: (origin, cb) => { + if (isOriginAllowed(origin)) return cb(null, true); + cb(new Error(`CORS: Origin ${origin} not allowed`)); + }, methods: ["GET", "POST", "PUT", "PATCH", "DELETE", "OPTIONS"], allowedHeaders: ["Content-Type", "Authorization"], credentials: true, diff --git a/apps/Backend/src/index.ts b/apps/Backend/src/index.ts index c684822..c2903c6 100644 --- a/apps/Backend/src/index.ts +++ b/apps/Backend/src/index.ts @@ -3,11 +3,18 @@ import dotenv from "dotenv"; dotenv.config(); -const HOST = process.env.HOST; -const PORT = process.env.PORT; +const NODE_ENV = ( + process.env.NODE_ENV || + process.env.ENV || + "development" +).toLowerCase(); +const HOST = process.env.HOST || "0.0.0.0"; +const PORT = Number(process.env.PORT) || 5000; -const server = app.listen(PORT, () => { - console.log(`βœ… Server running at http://${HOST}:${PORT}`); +const server = app.listen(PORT, HOST, () => { + console.log( + `βœ… Server running in ${NODE_ENV} mode at http://${HOST}:${PORT}` + ); }); // Handle startup errors diff --git a/apps/Frontend/.env.example b/apps/Frontend/.env.example index 1a40470..acfe8ff 100644 --- a/apps/Frontend/.env.example +++ b/apps/Frontend/.env.example @@ -1,2 +1,4 @@ -VITE_API_BASE_URL_BACKEND=http://localhost:5000 - \ No newline at end of file +NODE_ENV=development +HOST=0.0.0.0 +PORT=3000 +VITE_API_BASE_URL_BACKEND=http://localhost:5000 \ No newline at end of file diff --git a/apps/Frontend/vite.config.ts b/apps/Frontend/vite.config.ts index 0d3316a..5abcbd4 100644 --- a/apps/Frontend/vite.config.ts +++ b/apps/Frontend/vite.config.ts @@ -1,19 +1,20 @@ -import { defineConfig } from 'vite' -import react from '@vitejs/plugin-react' -import path from 'path'; +import { defineConfig, loadEnv } from "vite"; +import react from "@vitejs/plugin-react"; +import path from "path"; +export default defineConfig(({ mode }) => { + const env = loadEnv(mode, process.cwd(), ""); -// https://vite.dev/config/ -export default defineConfig({ - plugins: [ - react(), - ], - server: { - port: 3000, - }, - resolve: { - alias: { - '@': path.resolve(__dirname, 'src') - } - } + return { + plugins: [react()], + server: { + host: env.HOST, + port: Number(env.PORT), + }, + resolve: { + alias: { + "@": path.resolve(__dirname, "src"), + }, + }, + }; }); diff --git a/apps/PatientDataExtractorService/.env.example b/apps/PatientDataExtractorService/.env.example new file mode 100644 index 0000000..1aa231e --- /dev/null +++ b/apps/PatientDataExtractorService/.env.example @@ -0,0 +1,2 @@ +HOST=localhost +PORT=5001 \ No newline at end of file diff --git a/apps/PatientDataExtractorService/main.py b/apps/PatientDataExtractorService/main.py index 0ee840d..18ded14 100644 --- a/apps/PatientDataExtractorService/main.py +++ b/apps/PatientDataExtractorService/main.py @@ -1,8 +1,22 @@ -from flask import Flask, request, jsonify +from fastapi import FastAPI, UploadFile, File, HTTPException +from fastapi.middleware.cors import CORSMiddleware +import uvicorn import fitz # PyMuPDF import re +import os -app = Flask(__name__) +from dotenv import load_dotenv +load_dotenv() + +app = FastAPI() + +# Optional: allow CORS for development +app.add_middleware( + CORSMiddleware, + allow_origins=["*"], # change in production + allow_methods=["*"], + allow_headers=["*"], +) DOB_RE = re.compile(r'(?:3000` (only if HOST=0.0.0.0) + + +**Current setup:** +Frontend is running on `0.0.0.0` and is accessible via the device IP. + +**`.env` file:** +```env +NODE_ENV=development +HOST=0.0.0.0 +PORT=3000 +VITE_API_BASE_URL_BACKEND=http://192.168.1.8:5000 +``` + +Based on backend HOST and PORT. Currently Backend runs on 0.0.0.0 so its accessible all over the same network. +Change the Backend url if needed, + +And, VITE_API_BASE_URL_BACKEND shows the backend url of the network, make localhost if only own device to work with. +Or change accordingly with real IP. + +--- + +## βš™οΈ Backend (FastAPI) +- **Host:** `localhost` +- **Port:** `5000` +- **Access URL:** [http://localhost:5000](http://localhost:5000) + + +**Current setup:** +Currently runs for all network, and allow given frontend urls. Change accordingly. + + +**`.env` file:** +```env +NODE_ENV="development" +HOST=0.0.0.0 +PORT=5000 +FRONTEND_URLS=http://localhost:3000,http://192.168.1.8:3000 +``` + +--- + +## 🧾 Patient Data Extractor Service +- **Host:** `localhost` +- **Port:** `5001` +- **Access URL:** [http://localhost:5001](http://localhost:5001) + + +## πŸ’³ Selenium Service +- **Host:** `localhost` +- **Port:** `5002` +- **Access URL:** [http://localhost:5002](http://localhost:5002) + + +## πŸ’³ Payment OCR Service +- **Host:** `localhost` +- **Port:** `5003` +- **Access URL:** [http://localhost:5003](http://localhost:5003) + +--- + +## πŸ“– Notes +- These values come from per-app `.env` files: + - `HOST` controls binding (`localhost` = loopback only, `0.0.0.0` = all interfaces). + - `PORT` controls the service’s port. +- Frontend uses additional variables prefixed with `VITE_` for client-side access (e.g. `VITE_API_BASE_URL_BACKEND`). +- In production, ports and hosts may differ (configured by deployment platform). + +--- + +βœ… **Action for developers:** +1. Copy `.env.example` β†’ `.env` inside each app folder. +2. Adjust `HOST` / `PORT` if your ports are already taken. +3. Run `npm run dev` from the repo root. diff --git a/package.json b/package.json index 7735671..c294b8e 100644 --- a/package.json +++ b/package.json @@ -11,7 +11,7 @@ "db:generate": "prisma generate --schema=packages/db/prisma/schema.prisma && ts-node packages/db/scripts/patch-zod-buffer.ts", "db:migrate": "dotenv -e packages/db/.env -- prisma migrate dev --schema=packages/db/prisma/schema.prisma", "db:seed": "prisma db seed --schema=packages/db/prisma/schema.prisma", - "setup:env": "shx cp packages/db/prisma/.env.example packages/db/prisma/.env && shx cp apps/Frontend/.env.example apps/Frontend/.env && shx cp apps/Backend/.env.example apps/Backend/.env && shx cp apps/PaymentOCRService/.env.example apps/PaymentOCRService/.env", + "setup:env": "shx cp packages/db/prisma/.env.example packages/db/prisma/.env && shx cp apps/Frontend/.env.example apps/Frontend/.env && shx cp apps/Backend/.env.example apps/Backend/.env && shx cp apps/PatientDataExtractorService/.env.example apps/PatientDataExtractorService/.env && shx cp apps/SeleniumService/.env.example apps/SeleniumService/.env && shx cp apps/PaymentOCRService/.env.example apps/PaymentOCRService/.env", "postinstall": "npm --prefix apps/PatientDataExtractorService run postinstall && npm --prefix apps/PaymentOCRService run postinstall" }, "prisma": {