Reads our Candy PDF (deterministically, no OCR or model needed) and populates the consultant's own workbook using their formulas, column layout and PAYMENT column. Nothing is ever silently overwritten: every disagreement is reported, can be settled inside the app, and regenerated. - extract Candy text PDF -> tree (x-position column detection) - template layout detect, sequence align, write, totals, overrides - validate qty x rate and children-vs-subtotal reconciliation - profiles per-consultant layout profiles, stored on a volume Shipped with a Dockerfile + docker-compose for Coolify.
3.4 KiB
Deploying MEGA BOQ Converter to Coolify
Docker Compose, using the Dockerfile in this repo. Coolify builds the image,
publishes the port and puts its own HTTPS certificate in front — you do not
need nginx, certbot or a separate database.
Before you start
Push the repo (already done if you followed the setup below), then in Coolify:
- New Resource → Docker Compose
- Source Type: Git Repository
- Repository:
http://forgejo-b82b4lpyyzyg40thdsjdd38i.163.245.214.68.sslip.io/David/MEGA-BOQ-WEBAPP.gitBranchmain - Docker Compose File:
docker-compose.yml - Base Directory:
/(leave as-is) - Deploy
Coolify reads expose: "8501" from the compose file and routes your domain to
it. Set the domain in the resource's Domain tab and Coolify issues Let's
Encrypt automatically.
First deploy checklist
| check | why |
|---|---|
GET /_stcore/health returns ok |
the container is actually serving, not just running |
| Page loads over https with a valid cert | Coolify's proxy is in front |
| Upload both files and regenerate | proves the PDF path works with the container's libraries |
| Enter a consultant name, reload the page | proves the profile volume is mounted |
Environment variables
Only one matters, and it is already set in docker-compose.yml:
BOQ_PROFILES: /data/profiles
That path is on the named volume boq-profiles. If you move it, every saved
consultant layout is lost on the next rebuild.
TZ: Africa/Johannesburg is set so container timestamps match SAST.
Override anything in Coolify's Environment Variables tab rather than editing the compose file, so redeploys do not fight you.
Things that will bite you
The container binds 0.0.0.0, not 127.0.0.1. The CMD in the Dockerfile
passes --server.address=0.0.0.0 on purpose. .streamlit/config.toml binds
127.0.0.1 for local development, and that override would make the app
invisible from outside the container. CLI flags beat the config file, which is
why both exist.
XSRF protection is off (--server.enableXsrfProtection=false). Coolify's
Traefik rewrites the request origin, and Streamlit's built-in origin check then
rejects its own POSTs as forged. The app has no auth and no CSRF-sensitive
state, so this is safe here — but it is another reason not to expose it to the
open internet without putting auth in front.
Do not scale past one replica unless you move BOQ_PROFILES to a real
shared store. Two replicas would each keep their own copy of the consultant
profiles and quietly disagree. One replica is plenty for internal use.
Uploads are in-memory. Each conversion stages files in /tmp and discards
them. Nothing about a client's BOQ persists unless you download the result, and
the profile store holds only consultant names and column maps — never document
content.
Rolling back
Coolify keeps the previous image. Rollback on the deployment reverts to it.
If a redeploy somehow loses the profiles, the volume is still there — check that
BOQ_PROFILES still points at /data/profiles in the environment tab.
Running it locally without Coolify
docker compose up -d # http://127.0.0.1:8501
Or plain Docker:
docker build -t mega-boq .
docker run --rm -p 8501:8501 -v boq-profiles:/data/profiles mega-boq
Or without Docker at all:
./run_app.sh # creates a venv, runs on port 8501