151 lines
5.7 KiB
Markdown
151 lines
5.7 KiB
Markdown
# 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
|