# Service Factory — ERPNext Custom App Project > **Current Version: V0.1.0015** — Each completed prompt/step increments the patch number by 1 (V0.1.0000 → V0.1.0001 → V0.1.0002…). The agent automatically commits and pushes after every step. ## Project Overview **Service Factory** is a custom Frappe/ERPNext application that productizes professional services by treating human teams as structured "Resource Centers" and engagements as "Production Orders." Built for Frappe v16/ERPNext. --- ## Architecture ### ERPNext Deployment (Production) | Attribute | Value | |-----------|-------| | **Location** | `/opt/erpnext/frappe-bench/` | | **System user** | `erpnext` | | **Frappe version** | v16 (via `bench`) | | **Database** | MariaDB | | **Domain** | `erp.lohmar.co.uk` | | **Port** | 8080 (web via nginx proxy, proxies web + SocketIO) | | **Direct port** | 8000 (gunicorn direct — SocketIO won't work) | | **Reverse proxy** | Nginx on ports 8000+8080 → gunicorn:8001 (web) + node:9000 (SocketIO) | | **Zoraxy config** | WebSocket passthrough: **enabled** — Virtual directory: `/socket.io` → `http://172.16.8.20:9000/socket.io` | | **Static assets** | `/assets/` served directly by nginx (bypasses gunicorn) — essential for correct MIME handling behind Zoraxy | | **Process manager** | systemd (5 services managed via `frappe-bench.target`) | | **Reverse proxy** | Zoraxy (unifies web + SocketIO on port 8080) | ### Sites | Site | URL | Purpose | |------|-----|---------| | `erp.lohmar.co.uk` | http://erp.lohmar.co.uk:8000 | **Production** — ERPNext with all default apps + service_factory | | `test_sf.lohmar.co.uk` | (site created) | **Testing** — isolated site for Service Factory development | ### Installed Apps (on production site) ``` frappe, erpnext, service_factory ``` Default ERPNext apps active: Framework, Organization, Accounting, Assets, Buying, Manufacturing, Projects, Quality, Selling, Stock, Subcontracting, ERPNext Settings. ### Bench Services (systemd) | Service | Description | |---------|-------------| | `frappe-bench-web.service` | Gunicorn web server (port 8001, behind nginx on ports 8000+8080) | | `frappe-bench-worker.service` | Background async worker | | `frappe-bench-schedule.service` | Scheduled job runner | | `frappe-bench-socketio.service` | Realtime WebSocket (port 9000) | | `frappe-bench-watch.service` | File watcher for dev/assets | All services managed via `frappe-bench.target` (start/stop/status as a unit). ### Credentials ``` Location: /root/erpnext-admin-credentials.txt Site: http://erp.lohmar.co.uk:8080 Username: Administrator ``` --- ## Development Repository Structure ``` ~/development/ ├── erp-next/ # Git repository (Forgejo: cclohmar/erp-next.git) │ ├── service_factory/ # Frappe app source (DEV COPY — may be behind bench) │ ├── pyproject.toml │ ├── README.md │ └── .pre-commit-config.yaml └── sow.md # Statement of Work — the authoritative blueprint ``` The **actual live app** lives at: ``` /opt/erpnext/frappe-bench/apps/service_factory/ ``` **IMPORTANT**: The bench app and the dev repo are two separate git clones. The bench app contains the latest development work (all milestones complete). The dev repo at `~/development/erp-next/` may be behind and needs syncing after changes are made in the bench. --- ## Milestone Status (ALL COMPLETE in bench) | # | Milestone | Status | |---|-----------|--------| | **M1** | Custom App Scaffold & DB Schema (5 DocTypes) | ✅ Done | | **M2** | Backend Python Controllers (cost rollup, card generation, capacity warnings) | ✅ Done | | **M3+4** | Frontend JS Components + Role-Based Workspaces | ✅ Done | | **M5** | Test Suite (4 integration tests) | ✅ Done | | — | Deployment config with systemd, nginx, Zoraxy proxy | ✅ Done | | — | App icon + fixtures (seed data) | ✅ Done | ### DocTypes Created **Setup (Master)** - `Engagement Task Type` — Task categories (Demo, POC, Deployment, RFP/RFI, Other) - `Team Template` — Pre-defined teams by department - Child: `Team Template Member` — Employee assignment with role **Transaction** - `Engagement Card` — Universal work card (TEC) - Child: `Engagement Card Assignment` — Multi-person team allocation - Child: `Engagement Card Activity` — Activity log with milestones - Child: `Engagement Card Time Log` — Per-employee hours tracking - Child: `Engagement Card Subtask` — Delegatable breakdown items ### Business Logic (server-side) - `EngagementOrder.validate()` — Recipe step auto-population, capacity warnings, cost totals - `EngagementOrder.on_submit()` — Auto-generates Execution Cards for assigned steps - `ExecutionCard.on_update()` — Rollup of actual hours → parent order costs/billing ### Dashboards (3 role-based workspaces) - **Engineer Workspace** — My Execution Cards, Timer, Hours chart, Quick actions - **Manager Workspace** — Schedule Gantt, Capacity Alerts, Active/Stalled KPIs - **Director Workspace** — Margin Ledger, Delivery Efficiency, Resource Burn-Down ### Tests (bench app) ``` test_engagement_order.py — 4 integration tests: 1. Execution Cards generated on Order submit 2. Cost/billing rollup from Card hours 3. Recipe steps auto-populate from template 4. Capacity warning fires on overallocation ``` --- ## Git Operations Git server: `git.lohmar.co.uk` (self-hosted Forgejo) Two `.gitenv` files exist: - `/root/.gitenv` — template (placeholder, ignore) - `/root/bin/.gitenv` — **actual credentials** ```bash source /root/bin/.gitenv ``` | Setting | Value | |---------|-------| | Remote | `https://cclohmar:${TOKEN}@git.lohmar.co.uk/cclohmar/erp-next.git` | | Default branch | `main` | | Commit prefix | `chore:` | | Auto-stash | enabled | ### Two Git Repos — Keep in Sync ``` DEV REPO: ~/development/erp-next/ (1 commit — scaffold only) BENCH APP: /opt/erpnext/frappe-bench/apps/service_factory/ (10 commits — all milestones) ``` The bench app has all the development work. When making changes: 1. Develop in the bench's app directory (or sync bench → dev repo first) 2. Commit from the bench app OR the dev repo 3. Push to Forgejo ### Auto-Push Workflow After **every completed prompt/step**, the agent MUST: 1. Stage all changes (`git add -A`) 2. Commit with prefix `chore:` and a concise description 3. Increment the version in this file's header (V0.1.xxxx → V0.1.xxxx+1) 4. Push to `origin/main` 5. If the dev repo is behind the bench app, sync first before committing This ensures every interaction is checkpointed and version-tracked. --- ## Development Environment | Tool | Location | |------|----------| | OpenAgentsControl | `/root/.opencode/` | | Context files | `/root/.opencode/context/` | | Tmux manager | `/root/bin/workspace` (`tmux-project new\|return\|list\|kill`) | | Linting | ruff (Python), eslint (JS), prettier | | Python | ≥3.14 | | Runtime | Node.js/Bun, `@opencode-ai/plugin` | ### Agent Modes (Toggle) OpenAgent operates in two explicit modes during conversation: | Mode | Trigger | Behaviour | |------|---------|-----------| | 🗣️ **Discuss** | **Default** — every interaction starts here | Ideas, trade-offs, architecture sketches (text-only), questions, exploration. **Not a single file is touched, no bash executed.** | | 🔧 **Build** | Only when you say `"build it"` or equivalent | Execute the agreed plan — write files, edit code, run benchmarks, deploy, commit & push. All standard approval gates still apply. | The toggle is conversational: I stay in 🗣️ Discuss until you explicitly switch to 🔧 Build. This ensures we align on direction before any work begins. ### Agent Rules - **OpenAgent** — General purpose, workflow orchestration (toggle mode: discuss / build) - **OpenCoder** — Production development - Load context via ContextScout before any code/doc/test work - Approval gates required before file writes and bash execution - STOP on test failure — never auto-fix