Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
90 changes: 90 additions & 0 deletions .dependency-cruiser.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,96 @@
/** @type {import('dependency-cruiser').IConfiguration} */
module.exports = {
forbidden: [
{
name: "no-direct-db-import",
severity: "error",
comment:
"App and integration code must reach the database through a service or repository.",
from: {
path: "^(apps/(builder|worker)|integrations)/",
// Existing violations are an explicit ratchet baseline. New app or
// integration imports must go through a service or repository.
pathNot: [
"apps/builder/__tests__/integration-sendgrid-api[.]test[.]ts$",
"apps/builder/__tests__/upload-logo-action[.]test[.]ts$",
"apps/builder/src/app/integrations/\\[\\.\\.\\.integration\\]/callback[.]ts$",
"apps/builder/src/app/integrations/\\[\\.\\.\\.integration\\]/webhook[.]ts$",
"apps/builder/src/features/conversations/queries/build-conversation-where[.]ts$",
"apps/builder/src/features/dynamic-images/actions/create-dynamic-image[.]action[.]ts$",
"apps/builder/src/features/dynamic-images/actions/update-dynamic-image[.]action[.]ts$",
"apps/builder/src/features/error-logs/actions/delete-error-log-action[.]ts$",
"apps/builder/src/features/integration-instagram/actions/disconnect-instagram[.]ts$",
"apps/builder/src/features/integration-instagram/actions/update-instagram-action[.]ts$",
"apps/builder/src/features/integration-instagram/queries/index[.]ts$",
"apps/builder/src/features/integration-messenger/actions/__tests__/toggle-tag-sync[.]test[.]ts$",
"apps/builder/src/features/integration-messenger/actions/disconnect-messenger[.]ts$",
"apps/builder/src/features/integration-messenger/actions/update-messenger-action[.]ts$",
"apps/builder/src/features/integration-messenger/queries/index[.]ts$",
"apps/builder/src/features/integration-whatsapp/actions/disconnect[.]action[.]ts$",
"apps/builder/src/features/integration-whatsapp/automation/actions/update-ice-breakers[.]ts$",
"apps/builder/src/features/integration-whatsapp/queries/index[.]ts$",
"apps/builder/src/features/integration-zalo/actions/__tests__/toggle-tag-sync[.]test[.]ts$",
"apps/builder/src/features/invitations/queries/index[.]ts$",
"apps/builder/src/features/magic-links/actions/delete-magic-links[.]action[.]ts$",
"apps/builder/src/features/magic-links/actions/update-magic-link[.]action[.]ts$",
"apps/builder/src/features/messages/actions/create-webchat-message[.]action[.]ts$",
"apps/builder/src/features/workspace-members/actions/delete-workspace-member[.]action[.]ts$",
"apps/builder/src/features/workspace-members/actions/invite-workspace-member[.]action[.]ts$",
"apps/builder/src/features/workspaces/actions/upload-logo[.]ts$",
"apps/builder/src/lib/safe-action[.]ts$",
"apps/worker/__tests__/coexist-whatsapp-flush-lifecycle[.]test[.]ts$",
"apps/worker/__tests__/messenger-template-handler[.]test[.]ts$",
"apps/worker/__tests__/send-messenger-template[.]test[.]ts$",
"apps/worker/__tests__/sync-channel-labels[.]test[.]ts$",
"apps/worker/__tests__/sync-tag[.]test[.]ts$",
"apps/worker/__tests__/wa-template-handler[.]test[.]ts$",
"apps/worker/__tests__/wait-for-chat-job-completion[.]test[.]ts$",
"apps/worker/src/ai-agent/handlers/process-conversation-source-embedding[.]ts$",
"apps/worker/src/ai-agent/handlers/process-pending-embeddings[.]ts$",
"apps/worker/src/chat/handlers/send-message[.]ts$",
"apps/worker/src/default/handlers/export-contacts[.]ts$",
"apps/worker/src/default/handlers/imports/handler/contacts/handler[.]ts$",
"apps/worker/src/default/handlers/send-audit-log[.]ts$",
"apps/worker/src/default/handlers/sync-channel-labels[.]ts$",
"apps/worker/src/default/handlers/sync-tag[.]ts$",
"apps/worker/src/events/error-log/handlers/write-error-log[.]ts$",
"apps/worker/src/integration/handlers/coexist/attachment-download[.]ts$",
"apps/worker/src/integration/handlers/coexist/bulk-historical-import[.]ts$",
"apps/worker/src/integration/handlers/coexist/messenger-sync[.]ts$",
"apps/worker/src/integration/handlers/flow[.]ts$",
"apps/worker/src/integration/handlers/received-message[.]ts$",
"apps/worker/src/integration/handlers/ref[.]ts$",
"apps/worker/src/integration/handlers/step-handlers[.]ts$",
"apps/worker/src/integration/utils/message[.]ts$",
"apps/worker/src/lib/db[.]ts$",
"apps/worker/src/schedule/handlers/enqueue-broadcast[.]ts$",
"apps/worker/src/schedule/handlers/maintain-mac-partitions[.]ts$",
"apps/worker/src/schedule/handlers/prepare-broadcast[.]ts$",
"apps/worker/src/schedule/handlers/process-broadcast-contacts[.]ts$",
"apps/worker/src/schedule/handlers/reconcile-broadcasts[.]ts$",
"apps/worker/src/schedule/handlers/sync-user-quota[.]ts$",
"apps/worker/src/sequence-scheduler/revert-dispatch[.]ts$",
"apps/worker/src/sequence-scheduler/services/dispatch-processor[.]service[.]ts$",
"apps/worker/src/sequence-scheduler/services/retry-scheduler[.]service[.]ts$",
"apps/worker/src/sequence-scheduler/services/step-executor[.]service[.]ts$",
"apps/worker/src/sequence-scheduler/services/types[.]ts$",
"apps/worker/src/sequence-scheduler/worker-producer[.]ts$",
"apps/worker/src/sequence-scheduler/worker[.]ts$",
"apps/worker/src/services/integrations[.]ts$",
"apps/worker/src/trigger/services/action-executor[.]ts$",
"apps/worker/src/trigger/services/condition-evaluator[.]ts$",
"apps/worker/src/trigger/services/datetime-trigger-evaluator[.]ts$",
"apps/worker/src/trigger/services/handoff-executor[.]service[.]ts$",
"apps/worker/src/trigger/services/trigger-executor[.]service[.]ts$",
"apps/worker/src/trigger/services/trigger-matcher[.]service[.]ts$",
"apps/worker/src/webhook/services/webhook-matcher[.]service[.]ts$",
"apps/worker/src/webhook/services/webhook-payload[.]builder[.]ts$",
],
},
to: {
path: "^packages/database/src/client[.]ts$",
},
},
{
name: "no-circular",
severity: "warn",
Expand Down
95 changes: 95 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,21 @@ jobs:
- name: Lint
run: pnpm lint

- name: Check circular dependencies
run: pnpm check:circular

- name: Check unused exports
run: pnpm check:unused

- name: Check workspace-scoping ratchet
run: pnpm check:workspace-scoping

- name: Check dependency boundaries
run: pnpm exec depcruise --config .dependency-cruiser.js --output-type err --focus '^packages/database/src/client[.]ts$' --focus-depth 1 apps packages integrations

- name: Check dependency deduplication
run: pnpm dedupe --check

test:
name: Tests
runs-on: ubuntu-latest
Expand Down Expand Up @@ -131,3 +146,83 @@ jobs:
# contend with builder's own workers on a 4-vCPU runner.
- name: Test
run: pnpm turbo run test --concurrency=2

coverage:
name: Coverage
runs-on: ubuntu-latest
timeout-minutes: 20
steps:
- name: Checkout repository
uses: actions/checkout@v7

- name: Set up pnpm
uses: pnpm/action-setup@v6.1.0

- name: Set up Node.js
uses: actions/setup-node@v7
with:
node-version: 24
cache: pnpm

- name: Install dependencies
run: pnpm install --frozen-lockfile

- name: Set up Turbo cache
uses: rharkor/caching-for-turbo@v2.5.1

# Keep this starter scope narrow enough for predictable CI wall time.
# The shared Vitest preset enforces its 80% thresholds because this job
# deliberately does not set VITEST_SKIP_COVERAGE_THRESHOLDS.
- name: Verify coverage thresholds
run: pnpm --filter @chatbotx.io/business --filter worker test -- --coverage

database-integration:
name: Database integration
runs-on: ubuntu-latest
timeout-minutes: 20
env:
DATABASE_URL: postgresql://chatbotx:secretkey@localhost:5432/chatbotx?schema=public
REDIS_URL: redis://localhost:6379
services:
postgres:
image: timescale/timescaledb-ha:pg18-all
env:
POSTGRES_DB: chatbotx
POSTGRES_USER: chatbotx
POSTGRES_PASSWORD: secretkey
ports: ["5432:5432"]
options: >-
--health-cmd "pg_isready -d chatbotx -U chatbotx"
--health-interval 10s
--health-timeout 5s
--health-retries 5
--health-start-period 20s
redis:
image: redis:8-alpine
ports: ["6379:6379"]
options: >-
--health-cmd "redis-cli ping"
--health-interval 10s
--health-timeout 5s
--health-retries 5
steps:
- name: Checkout repository
uses: actions/checkout@v7

- name: Set up pnpm
uses: pnpm/action-setup@v6.1.0

- name: Set up Node.js
uses: actions/setup-node@v7
with:
node-version: 24
cache: pnpm

- name: Install dependencies
run: pnpm install --frozen-lockfile

- name: Migrate database from zero
run: pnpm --filter @chatbotx.io/database db:migrate

- name: Run database integration tests
run: pnpm --filter @chatbotx.io/database test:db
4 changes: 2 additions & 2 deletions biome.json
Original file line number Diff line number Diff line change
Expand Up @@ -68,8 +68,8 @@
"noDuplicateCustomProperties": "off"
},
"complexity": {
"noExcessiveLinesPerFunction": "off",
"noExcessiveCognitiveComplexity": "off"
"noExcessiveLinesPerFunction": "warn",
"noExcessiveCognitiveComplexity": "warn"
},
"performance": {
"noBarrelFile": "off"
Expand Down
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@
"test:coverage": "turbo run test -- --coverage",
"clean": "pnpm store prune && pnpm dlx rimraf --glob '**/{node_modules,.next,.turbo}'",
"check:circular": "pnpm dlx madge --circular --extensions ts,tsx --exclude generated {apps/**/src,packages/**/src}",
"check:unused": "knip"
"check:unused": "knip",
"check:workspace-scoping": "node scripts/check-workspace-scoping.mjs"
},
"devDependencies": {
"@biomejs/biome": "^2.4.16",
Expand Down
Loading
Loading