# Data Entry App

Initial MVP implementation of the costing platform described in `CLAUDE.MD`.

## Structure

```text
backend/   FastAPI API, SQLAlchemy models, costing engine, seed data, tests
frontend/  SvelteKit UI scaffold for dashboard and core modules
deploy/    nginx config and Docker deployment assets
```

## Docker Alpha Deployment

This repo now includes a production-oriented Docker setup for an alpha release:

- `backend/Dockerfile`
- `frontend/Dockerfile`
- `docker-compose.yml`
- `docker-compose.alpha.yml`
- `deploy/nginx/clients.lean-101.conf`
- `deploy/nginx/clients.lean-101.proxy.conf`
- `.env.alpha.example`

The compose stack runs three services:

- `backend` on internal port `8000`
- `frontend` on internal port `3000`
- `nginx` on host port `8081` by default

`nginx` routes:

- `/api/*`, `/docs`, `/openapi.json`, `/health` to the FastAPI backend
- everything else to the Svelte frontend

### Browser vs server API base URLs

The frontend now supports:

- `PUBLIC_API_BASE_URL` for browser requests
- `INTERNAL_API_BASE_URL` for server-side SvelteKit requests inside Docker

This is important for a same-domain deployment such as `https://clients.lean-101.com.au`, where the browser should call the public domain while the frontend container should call the backend container directly.

### Example `/srv` deploy

```bash
mkdir -p /srv/lean101-clients
cd /srv/lean101-clients
git clone <this-repo> .
cp .env.alpha.example .env.alpha
docker compose --env-file .env.alpha up -d --build
```

This follows the same external pattern as your website container:

- one compose project under `/srv/lean101-clients`
- one host-facing port, `8081`, for the app
- your existing public reverse proxy forwards `clients.lean-101.com.au` to `127.0.0.1:8081`

If your server already has a host-level nginx handling domains and TLS, use `deploy/nginx/clients.lean-101.proxy.conf` as the upstream template and point the domain at `http://127.0.0.1:8081`.

## Production deployment (Postgres + Digital Ocean)

`docker-compose.production.yml` provisions a managed-style stack with a containerised Postgres 16 service replacing the SQLite file used in alpha. The PowerShell script `deploy/Deploy.ps1` drives both first-time bootstrap and incremental updates from a Windows workstation against a Digital Ocean droplet.

1. **One-time droplet prep**: install Docker Engine + the compose plugin (`apt install docker.io docker-compose-plugin` or the official Docker repo). Open inbound 80/443 on your reverse proxy and forward to `127.0.0.1:${CLIENTS_APP_PORT}` (default 8081).
2. **Local secrets**: copy the example env and fill in real secrets — strong `POSTGRES_PASSWORD`, `AUTH_SECRET`, `CLIENT_PASSWORD`, `ADMIN_PASSWORD`. The compose file refuses to start without them.

   ```powershell
   Copy-Item .env.production.example .env.production
   notepad .env.production
   ```

3. **First deploy** (clones the repo on the droplet, uploads the env file, brings the stack up):

   ```powershell
   ./deploy/Deploy.ps1 `
     -RemoteHost 203.0.113.10 `
     -Bootstrap `
     -RepoUrl git@github.com:ponzischeme89/data-entry-app.git `
     -Seed
   ```

4. **Subsequent updates** (the same script — pulls latest `main`, rebuilds, and rolls containers without touching the Postgres volume):

   ```powershell
   ./deploy/Deploy.ps1 -RemoteHost 203.0.113.10
   ```

   Useful flags: `-Branch <name>` to deploy a feature branch, `-SkipBuild` for env-only changes, `-Seed` to re-run reference data seeding, `-Logs` to tail logs after the deploy, `-SshKey` to point at a specific private key.

5. **Database**: the backend reads `DATABASE_URL`. The production compose file synthesises it as `postgresql+psycopg://${POSTGRES_USER}:${POSTGRES_PASSWORD}@db:5432/${POSTGRES_DB}` so you only need to set the three `POSTGRES_*` vars. Override `DATABASE_URL` directly if you point at a managed Postgres (e.g. DigitalOcean managed databases).

The schema is auto-managed — `app/db/migrations.py` runs at backend startup and is idempotent across SQLite and Postgres. To migrate alpha SQLite data into the new Postgres instance, dump tables to CSV from the alpha container and import via `\copy` in `psql`; there is no automatic SQLite → Postgres path.

## Backend

Create a virtual environment, install dependencies, then run:

```bash
cd backend
pip install -e .
uvicorn app.main:app --host 0.0.0.0 --port 8000 --reload
```

API docs will be available at `http://localhost:8000/docs` on the server itself, or `http://<server-ip>:8000/docs` from another machine on the same network.

Useful commands:

```bash
python -m app.seed
pytest
```

The backend defaults to SQLite for the prototype and can be switched with the
`DATABASE_URL` environment variable.

## Frontend

Install dependencies and start the dev server:

```bash
cd frontend
npm install
npm run dev
```

The frontend dev server now binds to `0.0.0.0`, so you can open it from another machine at `http://<server-ip>:5173`.

By default the browser will call the backend on the same hostname and port `8000`. For example, if you open the UI at `http://10.0.0.124:5173`, it will call `http://10.0.0.124:8000`.

Useful environment variables:

```bash
PUBLIC_API_PORT=8000
PUBLIC_API_BASE_URL=http://10.0.0.124:8000
CORS_ALLOW_ORIGINS=http://10.0.0.124:5173
```

Set `PUBLIC_API_BASE_URL` when the API is on a different machine or behind a different public URL. Set `CORS_ALLOW_ORIGINS` or `CORS_ALLOW_ORIGIN_REGEX` if you want to narrow backend CORS more tightly than the default private-network allowance.

## Delivered in this MVP

- Raw materials with versioned prices
- Mixes with ingredient rows and calculated cost per kg
- Products with transparent cost breakdowns
- Scenario runs with override support
- Power BI-style reporting endpoints
- SvelteKit dashboard and module pages aligned to the API contract
