- Python 63.2%
- JavaScript 16.8%
- CSS 13.2%
- Dockerfile 3.5%
- Makefile 2.5%
- Other 0.8%
ruff flagged an unused loop variable and a zip() without strict= in the seeder, an unsorted import block and an unused import in the tests. None of them changed behaviour, which is exactly why a linter in the pipeline is worth having. |
||
|---|---|---|
| .forgejo/workflows | ||
| backend | ||
| frontend | ||
| schemas | ||
| tests | ||
| .gitignore | ||
| AGENTS.md | ||
| Dockerfile | ||
| env.schema.yaml | ||
| Makefile | ||
| platform.yaml | ||
| pyproject.toml | ||
| README.md | ||
Invoice AI
AI-assisted invoice processing. A small but real application: React frontend, FastAPI backend, PostgreSQL, and an optional AI gateway for invoice summaries.
All data is synthetic.
This repository is managed by the DevCloud platform. It follows the platform contract, so the platform knows how to build, deploy and describe it without anyone configuring that separately.
Getting started
If you opened this in a Coder workspace, everything is already installed and OpenCode is available. Otherwise:
cd backend && pip install -r requirements-dev.txt
cd ../frontend && npm install
Then:
make dev # backend on :8000, frontend on :5173
make test # pytest against a real database
make lint # ruff
make migrate # apply migrations
make seed # synthetic demo data, fixed seed
Architecture
React frontend ──▶ FastAPI backend ──┬──▶ PostgreSQL
└──▶ AI gateway (optional)
The frontend is built into the same image as the backend, which serves it as static files. One image, one container, one port.
| Path | What lives there |
|---|---|
backend/app |
FastAPI application |
backend/migrations |
SQL migrations, applied in filename order |
frontend/src |
React application |
tests |
pytest suite, runs against a real PostgreSQL in CI |
schemas |
the platform contract schema and its validator |
The platform contract
Four files make this repository legible to the platform:
| File | Purpose |
|---|---|
platform.yaml |
What this application is: components, services, environments, health endpoint, deployment strategy. Validated against schemas/platform-v1.schema.json. |
env.schema.yaml |
Which environment variables exist and which are secrets. Never their values. |
AGENTS.md |
Rules for OpenCode and other agents working here. |
Makefile |
The standard commands the platform and every developer can rely on. |
Validate them:
python schemas/validate.py platform.yaml env.schema.yaml
CI runs exactly this, so a broken contract fails the build rather than surfacing later as a confusing deployment.
Secrets
Nothing secret is in this repository. env.schema.yaml declares that
DATABASE_URL and AI_GATEWAY_TOKEN exist and are secrets; the values live in
Infisical, separately per environment, and are injected at deploy time.
Your Coder workspace receives development secrets only. Integration and production secrets are never available to a developer workspace.
How a change reaches production
feature branch ──▶ CI (lint, contract, tests)
│
▼
pull request ──▶ review ──▶ merge to dev
│
▼
build image tagged with the commit SHA
│
▼
Shared DEV
│ promote the same image
▼
Integration
│ request + approval
▼
Production
The image built once on dev is the image that reaches production. Nothing is
rebuilt in between, so what was tested is what ships.
Your personal Coder workspace is not Shared DEV. Shared DEV is what exists
after a merge to dev; until then your work is yours alone.
Environments
| Environment | URL | Deploys when |
|---|---|---|
| Development | http://invoice-dev.192.168.122.60.nip.io |
automatically on merge to dev |
| Integration | http://invoice-int.192.168.122.60.nip.io |
on promotion of a DEV artefact |
| Production | http://invoice.192.168.122.60.nip.io |
on approved release request |
Current state, deployed version, pipeline and logs are all on the project page in the platform portal, each with a link to the system it came from.
API
| Method | Path | What it does |
|---|---|---|
| GET | /health |
Liveness plus a database check. The platform polls this. |
| GET | /version |
Version, commit SHA, environment. |
| GET | /api/customers |
List customers |
| GET | /api/invoices |
List invoices, optionally filtered by status |
| GET | /api/invoices/{number} |
One invoice with its line items |
| GET | /api/stats |
Counts and amounts per status |
| POST | /api/invoices/{number}/summary |
Summarise an invoice; uses the AI gateway when configured, a deterministic summary otherwise |
Interactive documentation is at /docs on any running instance.