DarDev Ops is a company operating system built around one organizing unit: the Solution. Hesabi, 20.tn, DarDev Services, DarDevLab, EscaHire, and company mail each own a heterogeneous connector graph—Twenty CRM tags, Listmonk lists, Stalwart identities, GoDaddy DNS, GitHub repos, scrapers—operated from a single console at ops.dardev.net. The console is a runtime that renders capabilities as actions, not a static config viewer filtered by product name.
This story documents the architecture locked in June 2026 after years of coupling mailer platform, company ERP, and product control plane without abstractions. The fix is not shared infrastructure with tabs—it is Solution → typed connectors → capabilities → UI actions and bus executors, aligned with crm-orchestrates-bus-executes and honest scope in deployed-realities-explained.
The problem we solved
Three systems had grown together on dardev-vps: the Unified Mailer stack (Stalwart, Listmonk, Twenty, platform bus), company operations (news CMS, DNS drift, CI visibility), and product-specific outreach (Hesabi OECT, Services webhooks, 20.tn workflows). Hardcoded Ops panels duplicated integration knowledge. Every new DNS provider or scraper meant bespoke React—not one provider file implementing standard capability IDs.
Missing foundations hurt twice: no connector abstraction and no capability registry. Ops showed that Listmonk existed; it did not offer Sync templates or Draft campaign as first-class actions derived from manifest data. inside-unified-mailer-stack documents the mail layer; solution-centric Ops documents who operates it per product.
Three domains
- Domain A — dardev-ops: workspace UI, RBAC, news CMS, capability proxy (ops.dardev.net)
- Domain B — dardev-platform: connector providers, integration bus execution, Docker stack on dardev-vps
- Domain C — product repos: hesabi.tn, 20.tn API, etc.—couple only via manifest, no shared code with A or B
Rules are strict: Domain A never direct-db-accesses Twenty or Listmonk. Domain B never stores third-party product business logic—only connection metadata and handlers. Domain C references solutions/{id}/manifest.json as the coupling point.
Solution object model
Each solution manifest carries id, label, kind (product, services, company, hub), status (active, pending, archived), connectors array, content surfaces, pipelines, team bindings, and visibility for the switcher. Everything hangs off that record—replacing registry.json, tracks.json, overlays, and scattered integration index files.
Hesabi's graph includes crm-twenty, list-listmonk, smtp-stalwart for send.hesabi.tn, dns-ovh, github-repo, and scraper-oect. DarDev Services might emphasize webhook-inbound routes and a narrower Listmonk footprint. EscaHire while waitlisted stays pending with showInSwitcher false—deployed-realities-explained applies to internal tools too.
Physical topology today
dardev-vps hosts nginx, Twenty :3001, Listmonk :9002, Stalwart, Roundcube :8888, platform-bus :3100, news, and ops console :5180. Subdomains: crm, mail, news, mta, webmail, ops.dardev.net. Product apps—hesabi.tn on dedicated OVH, 20.tn on 20tn-vps—deploy separately; Ops monitors via health URLs and GitHub connectors, not by co-hosting product code.
Operator PC remains permanent for OECT, Startup Tunisia fetch, and ecoles Playwright—hybrid model is not technical debt. Remote Ops displays pipeline status; trigger-resume runs locally where bots are blocked or rate limits are friendlier.
Eight architectural verdicts
- Solution is the unit of organization
- Connectors are typed with capabilities
- Console is a runtime, not a label viewer
- dardev-ops extracts from platform monolith—no cross-domain imports
- Manifest is the single solution record
- Hybrid operator PC is permanent
- Per-product SMTP via connector config (send.hesabi.tn first)
- RBAC per solution scope: admin, operator, viewer on capabilities
Data flows that must not bleed
Four canonical flows: cold import Operator PC → staging → Twenty CRM-only; CRM ↔ Listmonk sync via webhooks → bus; outbound mail Listmonk or bus → Stalwart; Ops monitoring read-mostly via bus and GitHub. Mixing cold import with automatic Listmonk subscribe was the pre-2025 failure mode—now blocked by consent fields and ops policy.
Workspace UX (M15)
Six-tab shell: Overview, Configure, Inspect, Metrics, Operate, plus Pipelines, Content, GitHub where capabilities allow. Job-first navigation at suite level: Home, Monitor, Run, Configure. Tailwind and shadcn/ui primitives extend shared layout—no legacy bespoke CSS for new panels.
Migration state (honest)
M0–M3 milestones shipped: console baseline, Hesabi reference workspace, remote ops.dardev.net, Services webhook catalog. M8 manifest migration and M9 connector runtime are in progress—some panels remain transitional. M16–M22 maturity V1 backlog covers TanStack Query state, security gates, Swarm, multi-SMTP—see ops-maturity-v1-milestones article when published.
What we refuse to build
- Replace Twenty, Listmonk, or Stalwart admin UIs
- Edit DNS from Ops (GoDaddy manual; drift display only)
- Slack or WhatsApp API notifications—team alerts in-app plus optional staff email
- OECT scrape on VPS
- Embedded CRM iframe
Connector runtime in daily work
A Hesabi operator opens Integrations tab: Listmonk connector renders Sync templates and Draft campaign from list-listmonk capabilities—not a static card saying connected. DNS connector shows check-drift result with link to GoDaddy. OECT scraper connector shows staging row count and Trigger resume with confirm dialog—execution stays on laptop. 20.tn workspace swaps OECT for ecoles scraper and outreach bus health capabilities; tab shell unchanged.
Viewer role sees counts and health GET actions; admin invokes DNS verify and daily send confirm. Audit log stores capability id plus role—replacing anonymous script buttons from legacy console. This runtime behavior is why M9 connector interface work matters as much as manifest migration.
Company vs product VPS boundaries
dardev-vps hosts company platform only—CRM, mail, news, ops, bus—not hesabi.tn product app or 20.tn API. Solution manifests record deploy targets and health URLs so Ops monitors product VPS without merging codebases. licence.hesabi.dardev.net license control plane is separate Go service. Agents reading AGENTS.md should not assume one SSH host runs everything; manifests document which connector probes which URL.
Success looks like
Open Hesabi workspace → Integrations tab shows Listmonk connector with live Sync templates and Draft campaign buttons from list-listmonk capabilities. Open 20.tn → different graph, same shell. Add dns-ovh provider → one implementation file; drift UI works for OVH zones. Viewer role cannot trigger admin sends; audit logs capability plus role.
That is the company OS promise: one place to operate every DarDev product integration surface without pretending every product integrates the same way—documented alongside inside-unified-mailer-stack for mail truth and crm-orchestrates-bus-executes for outreach execution.
Related architecture docs
Readers diving deeper should follow manifest spine (solution-manifest-config-spine), connector runtime (connector-capability-runtime-model), JSON Schema gates (json-schema-ops-validate-contracts), and mail orchestration policy (ops-orchestrates-never-configures-mail)—together they explain how ops.dardev.net stays a control plane without becoming a second mail admin panel.
External customers never log into DarDev Ops—this is internal staff software at roughly one thousand users scale. Product end users interact with hesabi.tn, 20.dardev.net, and subscribe forms on mail.dardev.net. Keeping that boundary clear prevents solution-centric design from leaking into customer-facing UX scope creep.
Is DarDev Ops the same as the mailer repo?
Today ops/ lives in dardev-platform monorepo transitioning to extract dardev-ops. Architecturally Domain A is separate deploy from Domain B bus and mail stack.
Why not one integration pattern for all products?
Hesabi needs OECT scraper and fiscal lists; EscaHire waitlist may use third-party API only; 20.tn needs school fields. Forcing one pattern created bespoke panels—connectors fix that.
Where is the canonical architecture doc?
docs/roadmaps/DARDEV-OPS-ARCHITECTURE.md in the monorepo—this article is the public summary without internal tracker IDs.
Does solution-centric mean multi-tenant SaaS Ops?
No. Internal ~1K users, staff RBAC. Enterprise client dedicated connectors are a future pattern via solution-dedicated scope.
How does news CMS fit?
Company news-cms connector; solution content[] references tags. Ops Mail tab publishes to news.dardev.net SQLite pipeline.



