- TypeScript 89.5%
- CSS 4.3%
- JavaScript 3.9%
- PLpgSQL 2.3%
| apps | ||
| docs | ||
| packages | ||
| scripts | ||
| tests/e2e | ||
| .env.example | ||
| .gitignore | ||
| .node-version | ||
| .nvmrc | ||
| design.md | ||
| docker-compose.yml | ||
| logo.svg | ||
| package-lock.json | ||
| package.json | ||
| playwright.config.ts | ||
| README.md | ||
| tsconfig.base.json | ||
🛠️ DuctOS
DuctOS is an all-in-one field service management ERP for HVAC and geothermal contractors. It covers tenant onboarding, CRM, equipment lifecycle, schedule/dispatch, field mobile work, invoices, payments, inventory, job costing, integrations, and DuctOS operator administration.
📚 Documentation
- 🗂️ Current workflow docs
- ✅ Expected outcomes matrix
- 🛡️ Operator admin phases
- 🧭 Technical specification
- 🛣️ Development plan
🧭 Current Product Surfaces
| Surface | Entry points | Purpose |
|---|---|---|
| Public SaaS site | /, /start, /help, /status |
Product overview, private trial tenant creation, public help, and public system status. |
| Tenant office app | /dashboard, /customers, /equipment, /schedule, /dispatch, /jobs, /invoices, /inventory, /job-costing, /integrations, /users, /technicians |
Day-to-day HVAC operations. |
| Field mobile app | apps/mobile/App.tsx via Expo |
Technician schedule, job execution, offline queue, photos, signatures, materials, timecards, and location heartbeat. |
| Operator admin | /operator/login, /operator, /operator/users, /operator/tenants/:id |
DuctOS internal tenant, billing, support, KB, status, feature flag, access grant, usage, and audit control plane. |
| API | /api/v1/* |
Tenant-aware and operator command/read APIs. |
| Database | packages/db/migrations |
PostgreSQL/PostGIS schema, RLS, seeds, and operational tables. |
🧱 Repository Layout
apps/api NestJS API
apps/web Next.js public site, tenant office app, and operator console
apps/mobile Expo/React Native field app
packages/shared Shared TypeScript contracts
packages/db SQL migrations and migration runner
docs Workflow docs, technical spec, and development plan
🎨 Design And UI Stack
The active product design contract lives in design.md. DuctOS uses a dense, utilitarian operational UI for HVAC and geothermal teams, not a marketing-style app shell.
- Web: Next.js 16, React 19, HeroUI v3, and Tailwind v4.
- Shared web primitives: HeroUI-backed controls, Tailwind utility classes, and
the app shell styles in
apps/web/app/globals.css. - Mobile: Expo 52 and React Native 0.76 for the technician field app.
- Theme support: light and dark mode through the repo CSS variables and
data-theme.
🚀 Local Setup
Prerequisites:
- Node.js
24.16.0;.nvmrcand.node-versionpin the same runtime. - npm
11.13.x. - Docker with Docker Compose for PostgreSQL and Redis.
nvm use
npm install
cp .env.example .env
npm run dev
npm run dev starts PostgreSQL and Redis with Docker Compose, runs database
migrations, and then starts the API on port 3001 and the web app on port 3000.
Local URLs:
- Web app: http://localhost:3000
- API: http://localhost:3001/api/v1/health
- Operator admin: http://localhost:3000/operator
Mobile app:
npm run dev:mobile
npm run dev:mobile starts Expo Metro from apps/mobile. Platform-specific
Expo launch commands are available through the mobile workspace:
npm --workspace @ductos/mobile run ios,
npm --workspace @ductos/mobile run android, and
npm --workspace @ductos/mobile run web.
✅ Current Workflow Coverage
- 🚀 SaaS onboarding and authentication
- 🧰 Office CRM and equipment lifecycle
- 🗓️ Schedule, dispatch, jobs, and field mobile
- 💵 Finance, inventory, and job costing
- 🔌 Integrations, notifications, and payment rails
- 🛡️ Operator admin and tenant operations
- 👷 Users, technicians, and RBAC
🧪 Verification
npm run typecheck
npm run build
npm test
npm run test:e2e
Browser checks use Playwright. Install the local Chromium runtime with:
npm run playwright:install
On Ubuntu 26.04, the install script uses Playwright's Ubuntu 24.04 x64 fallback browser build until Playwright ships a native Ubuntu 26.04 target.
Playwright smoke tests target a running local app at E2E_BASE_URL or
http://127.0.0.1:3000. The suite seeds deterministic operator and tenant demo
data through npm run e2e:seed; override E2E_API_URL,
E2E_OPERATOR_EMAIL, or E2E_OPERATOR_PASSWORD when pointing at a different
local stack.
The workflow docs describe implemented entry points and expected outcomes. Roadmap-only modules remain in the development plan until they have concrete app/API surfaces.