Reading this on a fork? If a
README-fork.mdexists at this repo root, that's the fork's overview — start there. This document describes arqitool itself and stays inherited unchanged in forks (perOWNERSHIP.md).
Arqitech platform monorepo template
Opinionated TypeScript monorepo with auth, access control, shared tooling, and an admin panel. Fork this to start a new Arqitech service — all monoliths share the same structure so they can be composed into microservices later.
| Category | Technology |
|---|---|
| Monorepo | Turborepo + Bun workspaces |
| Runtime | Bun 1.3.5+ |
| Backend | Hono |
| Frontend | React + Vite + TanStack Router/Query |
| Cache/Sessions | Redis + ioredis |
| State Management | Zustand |
| Styling | Tailwind CSS |
| Type Checking | TypeScript 5.9.2 |
| Testing | Playwright (E2E), Vitest (unit) |
| Infra (dev) | Docker Compose |
# Install Bun if needed
curl -fsSL https://bun.sh/install | bash
# Install gitleaks (required by the pre-commit secret gate) — see https://github.com/gitleaks/gitleaks#installing
# Copy root env template (single source of truth for every service)
cp .env.example .env
# Install dependencies — postinstall creates services/*/.env → ../../.env symlinks
bun install
# Start everything (Docker infra + all services)
bun run devbun run dev automatically:
- Checks Docker is running and starts containers (
docker compose up -d) - Waits for Postgres and Redis to be healthy
- Runs migrations and seeds for each service
- Starts all dev servers in parallel
| Service | Port | Notes |
|---|---|---|
| gateway | 3005 | Reverse proxy — all frontend traffic |
| auth service | 3001 | Hono API (via gateway) |
| access service | 3002 | Hono API (via gateway) |
| email service | 3003 | Hono API (internal only) |
| access-dashboard | 3000 | React + Vite |
| postgres (auth) | 5432 | DB: auth |
| postgres (access) | 5434 | DB: access |
| redis | 6379 |
Each workspace declares its port and env vars in package.json. See docs/systems/workspace-registry.md.
Adding a service:
- Create
services/<name>/package.jsonwitharqitoolblock - Run
bun run generate-env - Commit
.env.exampleandports.lock.json
All env vars live in root .env (gitignored). Each service's .env symlinks to root, created automatically by bun install.
Generation workflow:
- Edit
package.json— add/change env vars in thearqitoolblock bun run generate-env— regenerates.env.examplefrom all workspacearqitoolblocksbun run setup:env— regenerates.envfrom.env.example(preserves existing values)
bun run check-env fails if any process.env.X in code is missing from .env.example.
arqitool/
├── apps/
│ └── access-dashboard/ # React admin panel — auth & access UI (port 3000)
│
├── services/
│ ├── gateway/ # Reverse proxy — cookie→JWT, routing, filtering (port 3005)
│ ├── auth/ # Authentication service — Hono (port 3001)
│ ├── access/ # RBAC/ABAC service — Hono (port 3002)
│ └── email/ # Email delivery service — Hono (port 3003)
│
├── packages/
│ ├── theme/ # Token-based theming engine (@arqitool/theme)
│ ├── i18n/ # Shared i18n client library
│ ├── redis/ # Shared Redis client (singleton)
│ └── shared/
│ ├── types/ # TypeScript type definitions
│ ├── constants/ # Shared constants
│ ├── utils/ # Helper functions
│ ├── eslint-config/
│ └── typescript-config/
│
├── infra/
│ ├── docker-compose.yml # Dev infrastructure (Postgres, Redis)
│ └── scripts/
│ └── check-infra.ts # Health-checks Docker before dev starts
│
├── turbo.json
└── package.json
bun run dev # Start infra + all services (full dev environment; twin tZERO)
bun run dev:twin # Same as `dev` — explicit twin (local digital twin)
bun run dev:live # Same stack, trading wired to the live tZERO QA venue
bun run infra:down # Stop Docker containers
bun run build # Build all packages
bun run check-types # Type check everything
bun run lint # Lint all code
bun run format # Format with Prettierbun run dev defaults to twin — a fully local digital twin of tZERO, no external
egress. bun run dev:live brings the same stack up with the trading path pointed
at the real tZERO QA venue.
"Live" flips only the trading path; the rest stays local:
| Path | twin | live |
|---|---|---|
| orders / executions | local twin | live tZERO QA FIX (tzero-live) |
| drop-copy reconcile | n/a (synthetic) | live drop-copy session |
| balances / positions | local twin | live REST if creds present, else twin |
| onboarding / KYC | local twin | local twin (always) |
dev:live injects this env matrix and runs turbo --env-mode=loose (turbo's globalEnv
omits ATS_*/TZERO_*, so strict mode would prune it):
ATS_MODE=live,TZERO_FIX_TARGET=live,TZERO_DC_ENABLED=1(+TZERO_DC_ADDR/ comp IDs)TZERO_MODE=twin— pinned:tzero-twinkeeps serving onboarding + balances-fallback locally. Its live REST passthrough is a separate, incomplete path and must not engage here.- REST creds (
TZERO_BASE_URL/_API_KEY/_CLIENT_ID/_CLIENT_SECRET) are read from the gitignored root.env;dev:livewarns if they look like placeholders.
Live prerequisites (not handled by the script):
- Network egress to the tZERO QA FIX IPs must be allowlisted (the endpoints are reachable only from an approved egress).
- Live order execution + drop-copy fills require a funded/ACTIVE tZERO account and an ACTIVE
tzero-livemux customer row. Until those land,dev:livebrings the live session up (logon/ack path) but real fills are unavailable.
| Goal | Command |
|---|---|
| Stop dev servers | CTRL-C in the turbo TUI |
| Stop Docker infra | bun run infra:down |
| Full teardown | CTRL-C, then bun run infra:down |
Docker containers stay running after CTRL-C by design — the next bun run dev skips healthcheck waits.
infra:up → db:migrate → db:seed → dev
Run tasks for a single service: turbo run dev --filter=@arqitool/auth-service
The service directory name is the single source of identity:
services/{name}/ → ports.lock.json key: "{name}" → routes: /api/{name}/*
The gateway auto-discovers services from ports.lock.json in dev. In production, set {NAME}_SERVICE_URL env vars on the gateway.
- Create
services/<name>/with the same structure asservices/auth - Add
arqitoolblock toservices/<name>/package.jsondeclaring port and env vars - Run
bun run generate-envto regenerate.env.exampleandports.lock.json - Add
db:migrateanddb:seedscripts to itspackage.jsonif it needs a DB - Add a new Postgres service to
infra/docker-compose.ymlif it needs its own DB
- Frontend-facing routes:
/api/{name}/*— exposed through the gateway - Service-internal routes:
/api/{name}/internal/*— blocked by the gateway, used for health checks, service-to-service APIs, and debug endpoints - No CORS: services must not configure CORS — the gateway is the only browser-facing entry point
See CONTRIBUTING.md for TypeScript conventions.
- Type Safety First — strict TypeScript, validate at system boundaries
- ESM Imports — use
.jsextensions in imports - Workspace Dependencies — internal packages use
workspace:*
All branches are created from master. Branch name prefixes:
| Prefix | Purpose | Example |
|---|---|---|
feature/ |
New functionality or modules | feature/auth, feature/access |
dev/ |
Tooling, config, DX improvements | dev/arqitool-agent, dev/prompts |
test/ |
Experiments and cleanup | test/slopCleanup |
- Start with a lowercase verb describing the change (adds, removes, implements, updates, fixes)
- No conventional-commits prefixes (
feat:,fix:, etc.) - No scope tags
- Keep it short and direct
Examples:
adds /grill-me skill
implements RBAC
updates agents to stop assuming out of scope
- Create branch from
masterusing the prefix convention above - Run
bun run check-typesandbun run buildbefore committing - Write tests for business logic (Vitest) and critical UI flows (Playwright)
- Submit PR with clear description
- CONTRIBUTING.md — TypeScript and clean code standards
- docs/packages/ — Package documentation (theme, logger)
- docs/services/ — Service architecture docs
- Turborepo Docs
- Hono Docs
- TanStack Router
| Component | Owner | Contact |
|---|---|---|
| All | Rado | rado@arqitech.com |
License: Proprietary — Arqitech © 2025