# 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` | --- ## Claude Code Memory Claude Code (the AI assistant used to build this project) stores its memory locally on the PC. This memory contains project context, architecture decisions, feature history, and working preferences — allowing Claude to pick up where it left off in new sessions. **Memory location:** ``` /home/ff/.claude/projects/-home-ff-Desktop-DentalManagementMH06/memory/ ``` **To copy to a new PC:** 1. On the old PC, copy the memory folder: ```bash cp -r /home/ff/.claude/projects/-home-ff-Desktop-DentalManagementMH06/memory/ /media/usb/claude-memory-backup/ ``` 2. On the new PC, recreate the directory and paste: ```bash mkdir -p /home/ff/.claude/projects/-home-ff-Desktop-DentalManagementMH06/memory/ cp -r /media/usb/claude-memory-backup/* /home/ff/.claude/projects/-home-ff-Desktop-DentalManagementMH06/memory/ ``` The memory is plain markdown files and can also be copied manually via a USB drive or file manager. Enable "show hidden files" (Ctrl+H) in the file manager to see the `.claude` folder.