# Dental Manager - Starter A monorepo setup to manage both Backend and Frontend of the Dental Manager application. ## 🖥️ Setup Guide (Fresh Machine) Follow these steps in order after cloning the repository. ### Step 1 — Clone the repository ```sh git clone cd DentalManagementMHAprilgg ``` ### Step 2 — Install Node.js Required to run the Backend and Frontend. ```sh curl -fsSL https://deb.nodesource.com/setup_20.x | sudo -E bash - sudo apt-get install -y nodejs # Verify node -v # should print v20.x.x npm -v ``` ### Step 3 — Install Python Required to run the Selenium and OCR services. ```sh sudo apt-get install -y python3 python3-pip python3-venv # Verify python3 --version # should print 3.10 or higher ``` ### Step 4 — Install Chrome Required for the Selenium service to control a browser. ```sh wget -q -O - https://dl.google.com/linux/linux_signing_key.pub | sudo apt-key add - echo "deb [arch=amd64] http://dl.google.com/linux/chrome/deb/ stable main" | sudo tee /etc/apt/sources.list.d/google-chrome.list sudo apt-get update sudo apt-get install -y google-chrome-stable # Verify google-chrome --version ``` > The `webdriver-manager` package (included in `requirements.txt`) automatically downloads the matching ChromeDriver — no manual driver setup needed. ### Step 5 — Install PostgreSQL Primary database for the application. ```sh sudo apt-get install -y postgresql postgresql-contrib sudo systemctl enable postgresql sudo systemctl start postgresql # Create the database the app uses sudo -u postgres psql -c "CREATE DATABASE dentalapp OWNER postgres;" # Set the postgres user password to match packages/db/.env sudo -u postgres psql -c "ALTER USER postgres WITH PASSWORD 'mypassword';" ``` #### Enable password authentication over TCP By default Debian uses `scram-sha-256` or `peer` auth for local connections, which blocks password login. Switch to `md5`: ```sh sudo sed -i 's/scram-sha-256/md5/g' /etc/postgresql/*/main/pg_hba.conf sudo systemctl restart postgresql ``` #### Verify ```sh psql -U postgres -d dentalapp -h 127.0.0.1 -W # Enter: mypassword # You should see: dentalapp=# ``` > The `DATABASE_URL` in `packages/db/.env` is already set to: > ``` > DATABASE_URL="postgresql://postgres:mypassword@localhost:5432/dentalapp" > ``` ### Step 6 — Install Redis Used as the job queue for Selenium and OCR background tasks. ```sh sudo apt-get install -y redis-server sudo systemctl enable redis-server sudo systemctl start redis-server # Verify redis-cli ping # should print: PONG ``` ### Step 7 — Install Node.js dependencies ```sh npm install ``` ### Step 8 — Install Python dependencies Python dependencies are installed automatically by `npm install` (Step 7) via each service's `postinstall` script. Each service creates its own `.venv` virtual environment — no manual pip commands needed. > This approach is required on Debian 13+ where system-wide pip installs are blocked (PEP 668). ### Step 9 — Set up environment variables Copy the `.env.example` files and fill in the required values. ```sh npm run setup:env ``` ### Step 9a — Set the Cloudflare subdomain for this office After running `npm run setup:env`, open the two `.env` files and fill in this office's Cloudflare subdomain. **`apps/Frontend/.env`** ```env VITE_CLOUDFLARE_HOST=yoursubdomain.mydentalofficemanagement.com ``` **`apps/Backend/.env`** ```env CLOUDFLARE_HOST=yoursubdomain.mydentalofficemanagement.com FRONTEND_URLS=http://localhost:3000,http://yoursubdomain.mydentalofficemanagement.com,https://yoursubdomain.mydentalofficemanagement.com ``` Replace `yoursubdomain` with this office's actual subdomain (e.g. `summitdentalcare`). > If you skip this step, Cloudflare tunnel access will not work. LAN access still works without it. ### Step 10 — Set up the database ```sh # Run migrations npm run db:migrate # Generate Prisma types npm run db:generate # Insert seed data npm run db:seed ``` ### Step 11 — Configure nginx The repo includes `nginx.conf` in the project root. Install it as the active site config: ```sh sudo cp nginx.conf /etc/nginx/sites-available/dental-app sudo ln -sf /etc/nginx/sites-available/dental-app /etc/nginx/sites-enabled/dental-app sudo nginx -t && sudo systemctl reload nginx ``` > **Important:** The `/api/` location block must include `proxy_set_header Authorization $http_authorization;` > Without it, nginx strips the Authorization header and the backend returns "Access denied. No token provided." ### Step 12 — Run the app Open two terminals: **Terminal 1** — Backend + Frontend: ```sh npm run dev ``` > On first boot the server automatically seeds all AI chat templates, SMS templates, and greeting messages for every user — no manual configuration needed. **Terminal 2** — Selenium service: ```sh cd apps/SeleniumService .venv/bin/python3 agent.py ``` ### Step 13 — Create desktop shortcut (optional) Instead of opening two terminals manually every time, you can create a desktop shortcut that starts both services with a single double-click. Run this once after cloning and installing: ```sh bash ~/Desktop/DentalManagementMH06/setup-desktop-shortcut.sh ``` A **Dental App** shortcut will appear on your desktop. Double-clicking it opens: - A terminal running `npm run dev` (Backend + Frontend) - A terminal running the Selenium service > No username or path editing needed — the script automatically detects the current user's home folder. --- ## 📖 Developer Documentation - [Setting up server environment](docs/server-setup.md) — the first step, to run this app in environment. - [Development Hosts & Ports](docs/ports.md) — which app runs on which host/port, and how to configure `.env` for LAN or single-device access --- ## This is a Turborepo. What's inside? ### Apps and Packages - `apps/Backend` — Express.js API server - `apps/Frontend` — React + Vite frontend - `apps/SeleniumService` — Python FastAPI service for browser automation (insurance eligibility, claims) - `apps/PaymentOCRService` — Python service for payment OCR extraction - `@repo/eslint-config` — shared ESLint configuration - `@repo/typescript-config` — shared `tsconfig.json`s Each package/app is 100% [TypeScript](https://www.typescriptlang.org/) (except the Python services). ### Utilities - [Tailwind CSS](https://tailwindcss.com/) for styles - [TypeScript](https://www.typescriptlang.org/) for static type checking - [ESLint](https://eslint.org/) for code linting - [Prettier](https://prettier.io) for code formatting --- ## Cloudflare Tunnel Setup (Remote Access per Office) This connects each office's local app to a public subdomain via a Cloudflare Tunnel — no port forwarding needed, local network access is unchanged. **How it works:** - Local network: other office PCs reach the app directly at `http://:3000` - Internet: anyone reaches the app via `https://.mydentalofficemanagement.com` - Both paths hit the same app simultaneously with no conflict --- ### Step 1 — Add domain to Cloudflare (done once for all offices) > Skip this step if the domain is already on Cloudflare. 1. Go to `dash.cloudflare.com` → **Add a site** → enter `mydentalofficemanagement.com` (free plan) 2. Cloudflare scans existing DNS records — review and keep them 3. Cloudflare gives you 2 nameservers (e.g. `holly.ns.cloudflare.com`, `amir.ns.cloudflare.com`) 4. Log into **Ionos** → replace the domain's nameservers with Cloudflare's two 5. Wait 10–30 min → Cloudflare emails you when active 6. DNSSEC: if not purchased on Ionos, it was never enabled — nothing to turn off ### Step 2 — Install `cloudflared` on the office PC Run this in a terminal on the office machine: ```bash curl -L https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-linux-amd64.deb -o cloudflared.deb sudo dpkg -i cloudflared.deb cloudflared --version ``` ### Step 3 — Authenticate with Cloudflare ```bash cloudflared tunnel login ``` A browser window opens → click `mydentalofficemanagement.com` → terminal shows success and saves a certificate to `~/.cloudflared/cert.pem`. ### Step 4 — Create a tunnel for this office Use a unique tunnel name per office: ```bash cloudflared tunnel create # Example: cloudflared tunnel create summit-dental-app ``` Note the **tunnel ID** (UUID) printed — you need it in Step 5. ### Step 5 — Create the config file ```bash sudo mkdir -p /etc/cloudflared sudo nano /etc/cloudflared/config.yml ``` Paste (replace tunnel ID, credentials path, and subdomain for this office): ```yaml tunnel: credentials-file: /home/ee/.cloudflared/.json ingress: - hostname: .mydentalofficemanagement.com service: http://localhost:3000 - service: http_status:404 ``` Save: `Ctrl+O` → Enter → `Ctrl+X`. ### Step 6 — Route DNS for this office's subdomain ```bash cloudflared tunnel route dns .mydentalofficemanagement.com ``` ### Step 7 — Install as a system service (auto-starts on boot) ```bash sudo cloudflared service install sudo systemctl enable cloudflared sudo systemctl start cloudflared sudo systemctl status cloudflared ``` ### Step 8 — Allow the subdomain in Vite In `apps/Frontend/vite.config.js`, add the subdomain to `server.allowedHosts` so Vite does not block external requests. ### Step 9 — Allow the subdomain in backend CORS In `apps/Backend`, add the subdomain URL to the allowed CORS origins so login and API calls work from the public URL. --- ### Example — Adding Summit Dental Care **Office subdomain:** `summitdentalcare.mydentalofficemanagement.com` **Step 1:** Already done (domain is on Cloudflare). **Step 2:** Install `cloudflared` on Summit Dental's PC. **Step 3:** Run `cloudflared tunnel login` on Summit Dental's PC. **Step 4:** ```bash cloudflared tunnel create summit-dental-app # Example output: Created tunnel summit-dental-app with id a1b2c3d4-... ``` **Step 5 — `/etc/cloudflared/config.yml`:** ```yaml tunnel: a1b2c3d4-xxxx-xxxx-xxxx-xxxxxxxxxxxx credentials-file: /home/ee/.cloudflared/a1b2c3d4-xxxx-xxxx-xxxx-xxxxxxxxxxxx.json ingress: - hostname: summitdentalcare.mydentalofficemanagement.com service: http://localhost:3000 - service: http_status:404 ``` **Step 6:** ```bash cloudflared tunnel route dns summit-dental-app summitdentalcare.mydentalofficemanagement.com ``` **Step 7:** ```bash sudo cloudflared service install sudo systemctl enable cloudflared sudo systemctl start cloudflared ``` **Step 8:** Add `summitdentalcare.mydentalofficemanagement.com` to `allowedHosts` in `vite.config.js`. **Step 9:** Add `https://summitdentalcare.mydentalofficemanagement.com` to backend CORS allowed origins. --- ### Multi-office overview Each office runs its own `cloudflared` tunnel on its own PC. Ports never conflict because each PC is a separate machine. | Office | Local access | Public access | Tunnel name | |---|---|---|---| | Community Dentists of Lowell | `http://192.168.1.236:3000` | `https://communitydentistsoflowell.mydentalofficemanagement.com` | `dental-app` | | Summit Dental Care | `http://:3000` | `https://summitdentalcare.mydentalofficemanagement.com` | `summit-dental-app` | | Next office | `http://:3000` | `https://.mydentalofficemanagement.com` | `-app` |