[vibe](../../README.md) > [Guidebooks](../README.md) > **ERP** # ERP > **Status:** ✅ Active > **Last Updated:** 2026-06-23 > **Upstream:** [Applications hub](../applications/README.md) · [01 · factory](../lab-ecosystem/01-factory.md) > **Downstream:** [Deployment](deployment.md) · [Backup & recovery](backup-and-recovery.md) · [Operations](operations.md) > **Related:** [tools secrets-and-vso](../tools/secrets-and-vso.md) · [factory postgres-iac](../factory-provisioning/opentofu/postgres-iac.md) · [storage concept](../lab-ecosystem/storage-and-recovery.md) · [factory recover playbooks](../factory-provisioning/ansible/06-recover.md) · [safe-prod-like-environment ADR](../../ADR/0001-safe-prod-like-environment.md) This guidebook maps **erp** — the lab's [Dolibarr **22.0.4**](https://gitea.arcodange.lab/arcodange-org/erp/src/branch/main/chart/Chart.yaml) accounting/business ERP and its **single most data-critical application**. It is a PHP/Apache workload built from the upstream `dolibarr/dolibarr` image, served internally at `erp.arcodange.lab` (Traefik `websecure` + `localIp@file` + a `letsencrypt`-resolver cert). Everything a reader needs to deploy it, keep its data safe, and operate it lives in the three child pages below; this page is the orientation map. ## What makes erp special `erp` is the complex sibling of the [webapp / url-shortener archetypes](../applications/README.md). It carries the **same four-ingredient app pattern** (Dockerfile-less reuse of an upstream image, a `chart/`, an `iac/`, `.gitea/workflows`) but layers several things on top that the archetypes do not: | Trait | erp specifics | Why it matters | |---|---|---| | **Upstream image** | `dolibarr/dolibarr:22.0.4` — not a repo-built image | No custom Dockerfile; the chart adapts the upstream container at runtime | | **Postgres, not MySQL** | Dolibarr classically assumes MySQL; erp runs on **PostgreSQL** (`DOLI_DB_TYPE: pgsql`) | A [custom entrypoint](https://gitea.arcodange.lab/arcodange-org/erp/src/branch/main/chart/scripts/custom_entrypoint.sh) rewrites the upstream `docker-run.sh` `mysql` invocation into `psql` before launch | | **DB path** | pod → `pgbouncer.tools:5432` → the `erp` Postgres database on `pi2` | Shares the [tools pgbouncer pooler](../tools/secrets-and-vso.md) like the webapp archetype | | **Vault wiring** | **dynamic** rotating DB creds (`postgres/creds/erp`) + **static** KV config (`kvv2` `erp/config`) via the shared [`app_roles` module](../tools/secrets-and-vso.md) | The pod cannot start without VSO-injected `DOLI_DB_USER` / `DOLI_DB_PASSWORD` | | **Document persistence** | a **50Gi Longhorn RWX PVC** (`storageClassName: longhorn`, `accessModes: ReadWriteMany`, `helm.sh/resource-policy: keep`) mounting `/var/www/documents`, `/var/www/html/custom`, and `/var/backups` | Uploaded invoices/PDFs/attachments are real business records — losing them is the worst case | | **Backup + ops** | its own [backup/restore subsystem](backup-and-recovery.md) plus a **read-only ops CLI** (`bin/arcodange`) | Data-criticality demands both an escape hatch for restores and a safe way to inspect live state | ## Overview — how erp is wired ```mermaid %%{init: {'theme': 'base'}}%% flowchart LR classDef src fill:#2563eb,stroke:#1e40af,color:#fff classDef proc fill:#059669,stroke:#047857,color:#fff classDef store fill:#7c3aed,stroke:#6d28d9,color:#fff classDef net fill:#b45309,stroke:#92400e,color:#fff CI["factory / erp CI
tofu apply (iac/)"]:::src VAULT["Vault
postgres/creds/erp (dynamic)
kvv2 erp/config (static)"]:::store ARGO["ArgoCD
syncs chart/ (ns erp)"]:::proc POD["Dolibarr pod
dolibarr/dolibarr:22.0.4
custom entrypoint → psql"]:::proc VSO["VSO
VaultAuth + VaultDynamicSecret
+ VaultStaticSecret"]:::proc PGB["pgbouncer.tools:5432"]:::net PG["Postgres erp db
(pi2)"]:::store PVC["50Gi Longhorn RWX PVC
/var/www/documents"]:::store BK["backup CronJob / runner
pg_dump → documents/admin/backup"]:::proc CI --> VAULT ARGO --> POD VAULT -. "creds + config" .-> VSO VSO -- "vso-db-credentials + secretkv" --> POD POD --> PGB --> PG PVC -- "mounts /var/www/documents" --- POD BK -- "dumps DB + writes to" --> PVC ``` 1. **factory / erp CI** runs `tofu apply` over `iac/` to declare erp's Vault objects — a Postgres dynamic-secret role and a Kubernetes auth role — through the shared [`app_roles` module](../tools/secrets-and-vso.md), and seeds the static `kvv2` `erp/config` KV (admin login, instance UUID). 2. **ArgoCD** (factory's [app-of-apps](../lab-ecosystem/01-factory.md)) syncs the `chart/` into the `erp` namespace. 3. The **Dolibarr pod** comes up from `dolibarr/dolibarr:22.0.4`; its [custom entrypoint](https://gitea.arcodange.lab/arcodange-org/erp/src/branch/main/chart/scripts/custom_entrypoint.sh) rewrites the upstream `docker-run.sh` so SQL runs through `psql` instead of `mysql`. 4. **VSO** authenticates to **Vault** (the `auth` `VaultAuth` CRD), materialising `vso-db-credentials` (dynamic, rotating DB user/password from `postgres/creds/erp`) and `secretkv` (static config from `kvv2` `erp/config`); both are injected into the pod, and a credential rotation triggers a rollout restart. 5. The pod connects to the **`erp` Postgres database** through the [tools `pgbouncer.tools:5432` pooler](../tools/secrets-and-vso.md). 6. A **50Gi Longhorn RWX PVC** mounts `/var/www/documents` (plus `/var/www/html/custom` and `/var/backups`), holding every uploaded document and generated PDF. 7. The **backup subsystem** dumps the `erp` database with a version-matched `pg_dump` and lands the archive under `documents/admin/backup` on that same PVC — see [Backup & recovery](backup-and-recovery.md). > [!CAUTION] > **Recovery ordering: Vault MUST be unsealed before erp is scaled up.** The Dolibarr pod has no usable DB credentials of its own — it depends entirely on VSO materialising `vso-db-credentials` from `postgres/creds/erp`. If erp is scaled up while Vault is still sealed, the pod crash-loops with no database access. During a cluster rebuild, unseal Vault first, confirm VSO has reconciled the erp secrets, and only then scale erp. The full sequence (cluster bring-up → Vault unseal → storage → apps) is covered by [Backup & recovery](backup-and-recovery.md), the [storage concept](../lab-ecosystem/storage-and-recovery.md), the [factory recover playbooks](../factory-provisioning/ansible/06-recover.md), and the cluster-wide CLUSTER_RECOVERY.md runbook. ## Index | Page | What it covers | Status | |---|---|---| | [Deployment](deployment.md) | The chart, the upstream image + custom entrypoint, the Postgres-over-pgbouncer wiring, the Vault CRDs (dynamic creds + static config), and the ingress | ✅ Active | | [Backup & recovery](backup-and-recovery.md) | The document PVC, the `pg_dump`-based backup subsystem, restore procedure, and where erp sits in cluster-recovery ordering | ✅ Active | | [Operations](operations.md) | The read-only `bin/arcodange` ops CLI and day-to-day operational tasks (table-ownership fix-ups, liveness checks, audits) | ✅ Active | ## Maintenance rule > [!IMPORTANT] > **When the erp repo changes shape, these pages change in the same PR.** If you alter the chart structure, the custom entrypoint, the Vault wiring, the document PVC, the backup subsystem, or the ops CLI, update this hub and the relevant child page in the same change. A reference map that drifts from the real `chart/`, `iac/`, and `backup/` sends agents confidently down dead paths — and for the lab's most data-critical app that risk is highest here. ## Cross-references - [Applications hub](../applications/README.md) — the common four-ingredient app pattern; erp is its complex sibling, beside the webapp and url-shortener archetypes. - [01 · factory](../lab-ecosystem/01-factory.md) — the ArgoCD app-of-apps that emits erp's `Application` CRD. - [tools secrets-and-vso](../tools/secrets-and-vso.md) — the `app_roles` module + VSO runtime that delivers erp's dynamic DB creds and static config, and the pgbouncer pooler the pod connects through. - [factory postgres-iac](../factory-provisioning/opentofu/postgres-iac.md) — the per-app `erp` PostgreSQL database + role erp runs on. - [storage concept](../lab-ecosystem/storage-and-recovery.md) — how the 50Gi Longhorn RWX document PVC is provisioned and recovered. - [factory recover playbooks](../factory-provisioning/ansible/06-recover.md) — the Ansible recovery steps that must precede scaling erp back up. - [safe-prod-like-environment ADR](../../ADR/0001-safe-prod-like-environment.md) — why the lab keeps erp deployed prod-like and the data-criticality trade-offs behind it.