tx-agent-kit
Enforcement

Closed Invariants

Complete list of all enforced invariants organized by category.

This is the complete list of mechanically enforced invariants. Each invariant is checked by at least one of the three enforcement layers (ESLint, structural scripts, shell scripts).

Web Architecture

InvariantDescription
API-first webapps/web never imports @tx-agent-kit/db or drizzle-orm
Web runtime simplicityapps/web must not import effect/effect/*
Client-only runtimeNo apps/web/app/api, no proxy/middleware, no next/server/next/headers
Client component contractAll .tsx under app/ and components/ start with 'use client'

Web Contracts

InvariantDescription
Auth-token contractOnly apps/web/lib/auth-token.ts manages browser-visible access token state; refresh persistence stays in an HttpOnly cookie
Transport contractapps/web/lib must not use /api/* proxy paths
URL-state contractnuqs usage centralized in apps/web/lib/url-state.tsx
Notification contractsonner usage centralized in apps/web/lib/notify.tsx
Browser API contractDirect window.location access is forbidden
Transport disciplineDirect fetch in apps/web is forbidden

Logging and Isolation

InvariantDescription
Logging disciplineconsole.* is banned; use @tx-agent-kit/logging
Drizzle isolationOnly packages/infra/db imports drizzle-orm
Schema-first boundariesValidation uses effect/Schema only (Zod banned)

Database Parity

InvariantDescription
Table schema parityEach table has a corresponding Effect schema in effect-schemas/
Table factory parityEach table has a corresponding factory in factories/
Contract governanceopenapi.json is generated and carries DDD metadata
Trigger coverageEach CREATE TRIGGER is referenced in pgTAP suites

Domain Architecture

InvariantDescription
Kind governanceRepository ports and API routes declare crud or custom markers
Core domain folder contractDomains use domain/ports/application/adapters, not repositories/services
Persistence boundaryConcrete persistence lives only in packages/infra/db/src/repositories/
Domain legibilityNamed exports only (no default exports)
Source hygieneNo TODO/FIXME/HACK comments in source
Domain determinismNo Date.now, new Date, Math.random in domain layer
Layer directionEnforced import restrictions per DDD layer

Temporal

InvariantDescription
Workflow determinismNo native timer calls in workflows
No infra importsWorkflows must not import database clients or I/O modules
API Temporal banapps/api/ must not import @temporalio/*; events flow via the outbox only

Domain Events

InvariantDescription
Event type registryAll event type strings used in code must be registered in domainEventTypes in packages/contracts/src/literals.ts
Payload interface parityEach registered event type must have export interface <Type>EventPayload in the domain's domain/*-events.ts
Payload schema parityEach registered event type must have export const <Type>EventPayloadSchema in packages/temporal-client/src/types/
Transactional writeDomain event inserts in repositories must be inside a db.transaction() block
Handler completenessEvery registered event type must have a case '...' handler in apps/worker/src/workflows*.ts
Idempotent workflow dispatchEvery startChild/executeChild call must include a workflowId containing event.id
No payload as casts.payload as <Type> is forbidden in worker files; use Schema decode
Naming conventionEvent type strings must match ^[a-z][a-z_]*\.[a-z][a-z_]*$
Retention settings parityEvery table in retentionTableNames must have an entry in the generated retention_settings reconcile schema
Insert helper enforcementInline .insert(domainEvents).values(...) outside repositories/domain-events.ts is banned; use insertDomainEventInTransaction
Port-level write contractDirect outbox repository access from service/application layers is banned; use *WithEvent port methods

Environment

InvariantDescription
Env governanceWeb and worker read env through dedicated modules
Source env governanceprocess.env only in allowed env files
Single env fileOnly .env and .env.example at root

Type Safety

InvariantDescription
No as anyForbidden in source modules
No chained assertionsas unknown as ... forbidden in source
Suppression governanceNo @ts-ignore, @ts-expect-error, eslint-disable in source
No empty catch blocksHandle, classify, or rethrow errors

Testing

InvariantDescription
Test colocationNo __tests__/, no .spec.ts, no .integration.ts without .test
API harnessMust use createDbAuthContext(...), no manual spawning
Path resolutionHarness callers use fileURLToPath(import.meta.url)
Web lifecycleTest files must not call setup/reset/teardown directly
No local globalSetupIntegration configs defer to root workspace setup

Critical Integration Baselines

InvariantDescription
API coverageHealth, auth, organization, invitation endpoints + idempotency
API health latencyHealth endpoint readiness assertion required
Web coverageDashboard, Organizations, Invitations pages + all form components
Web auth flowUnauthenticated redirect + invalid token handling
Worker coverageIdempotent activities.processOperation(...)
Observability coverageAll four services with Jaeger + Prometheus queries

Infrastructure

InvariantDescription
Local composedocker-compose.yml is infra-only (no api or worker services)
Deploy composeStaging and prod compose files must include api and worker
No build artifacts in source.js, .d.ts, .js.map forbidden under src/

On this page