Skip to main content

Deployment

All CROW services are deployed as Cloudflare Workers using Wrangler. Each service has its own wrangler.jsonc configuration file with environment-specific overrides for local, dev, and prod.

Workspace Bootstrap

Use the local-dev repo to clone and synchronize the multi-repo workspace before deploying individual services:

git clone https://github.com/CROW-B3/local-dev.git
cd local-dev
bun install
bun run clone

See Local Development for sync, checkout, cleanup, and optional repo workflows.

Environments

EnvironmentDomain PatternDatabase SuffixNotes
locallocalhost:800x-localLocal Wrangler dev server
devdev.*.crowai.dev-devStaging environment
prod*.crowai.dev(none)Production

Domain Mapping

Complete domain-to-service mapping for dev and prod environments:

Public-Facing Domains

Dev DomainProd DomainService
dev.app.crowai.devapp.crowai.devdashboard-client
dev.auth.crowai.devauth.crowai.devauth-client
dev.crowai.devcrowai.devlanding-client
dev.rogue.crowai.devrogue.crowai.devrogue-store
dev.api.crowai.devapi.crowai.devcore-api-gateway
dev.mcp.crowai.devmcp.crowai.devmcp-service
dev.a2a.crowai.deva2a.crowai.deva2a-service
dev.cctv.crowai.dev--cctv-ingest-service

Internal Service Domains

Dev DomainProd DomainService
dev.internal.auth-api.crowai.devinternal.auth-api.crowai.devcore-auth-service
dev.internal.users.crowai.devinternal.users.crowai.devcore-user-service
dev.internal.orgs.crowai.devinternal.orgs.crowai.devcore-organization-service
dev.internal.products.crowai.devinternal.products.crowai.devcore-product-service
dev.interactions.crowai.devinteractions.crowai.devcore-interaction-service
dev.internal.interactions.crowai.dev--core-interaction-service (internal)
dev.internal.billing.crowai.devinternal.billing.crowai.devcore-billing-service
dev.internal.notifications.crowai.devinternal.notifications.crowai.devcore-notification-service
dev.internal.analytics.crowai.devinternal.analytics.crowai.devcore-analytics-service
dev.internal.chat.crowai.devinternal.chat.crowai.devcore-chat-service / bff-chat-service
dev.internal.qna.crowai.devinternal.qna.crowai.devbff-qna-service
dev.patterns.crowai.devpatterns.crowai.devcore-pattern-service
dev.internal.patterns.crowai.dev--core-pattern-service (internal)
dev.internal.ingest-worker.crowai.dev--web-ingest-service
dev.ingest.crowai.dev--web-ingest-service (public)
dev.social-collector.crowai.devsocial-collector.crowai.devcore-social-collector
dev.internal.social-collector.crowai.dev--core-social-collector (internal)

Deploying a Service

Deploy to Dev

cd core-auth-service
npx wrangler deploy --env dev

Deploy to Prod

cd core-auth-service
npx wrangler deploy

The --env flag selects the environment block from wrangler.jsonc. When omitted, the top-level (prod) configuration is used.

Tailing Logs

npx wrangler tail --env dev

This streams real-time logs from the deployed worker. Useful for debugging requests in dev.

Local Development

npx wrangler dev --env local

Starts a local development server. D1 databases run locally, but AI, Browser Rendering, and Vectorize bindings may require --remote for full functionality.

Workers Containers

Several services deploy as Workers Containers, which run Docker images alongside the Worker. The container configuration is in wrangler.jsonc under the containers key.

Services Using Containers

ServiceContainer ClassImageMax InstancesPurpose
core-pattern-servicePatternAnalyzerContainer./Dockerfile2Python with sklearn, numpy for pattern analysis
core-interaction-serviceInteractionAnalyzerContainer./Dockerfile2Interaction analysis
infra-crawl-serviceCrawlerContainer./container_src/Dockerfile10Web crawling with headless browser

Container Configuration Example

"containers": [
{
"class_name": "PatternAnalyzerContainer",
"image": "./Dockerfile",
"max_instances": 2
}
]

Deploying Container Services

Container images are built and pushed to Cloudflare's container registry as part of wrangler deploy:

cd core-pattern-service
npx wrangler deploy --env dev

Wrangler builds the Docker image from the specified Dockerfile, pushes it to the registry, and deploys the Worker alongside it.

Checking Container Health

# Tail logs for the container service
npx wrangler tail crow-core-pattern-service --env dev

# Check deployment status
npx wrangler deployments list --env dev

Container instances are managed as Durable Objects internally. Each container class has a corresponding durable_objects binding and SQLite migration for persistent state.

Frontend Deployment

The dashboard, auth, and rogue-store clients are deployed via OpenNext on Cloudflare. Their wrangler.jsonc references .open-next/worker.js as the main entrypoint and .open-next/assets as the assets directory. The landing client uses Astro's Cloudflare adapter and deploys the generated dist/_worker.js/index.js worker bundle directly.

Services Using OpenNext

ServiceDev DomainProd Domain
dashboard-clientdev.app.crowai.devapp.crowai.dev
auth-clientdev.auth.crowai.devauth.crowai.dev
rogue-storedev.rogue.crowai.devrogue.crowai.dev

Build & Deploy

cd dashboard-client

# Build Next.js, then build for Cloudflare, then deploy
npx next build
npx opennextjs-cloudflare build
npx wrangler deploy --env dev

Or as a single chain:

npx next build && npx opennextjs-cloudflare build && npx wrangler deploy --env dev

Landing Client (Astro)

cd landing-client
bun run build
npx wrangler deploy --env dev

OpenNext Configuration Notes

  • Assets are served via the ASSETS binding pointing to .open-next/assets
  • KV namespaces (NEXT_INC_CACHE_KV) are used for Next.js incremental cache
  • Smart placement ("placement": { "mode": "smart" }) is enabled for optimal edge routing
  • Each Next.js client has its own custom domain configuration in routes

Durable Objects

Durable Objects provide persistent, single-threaded execution contexts. Several services use them for stateful workloads.

Services Using Durable Objects

ServiceDO ClassPurposeMigration Tag
core-pattern-servicePatternAnalyzerContainerContainer-backed pattern analysisv1 (new_sqlite_classes)
core-interaction-serviceInteractionAnalyzerContainerContainer-backed interaction analysisv1 (new_sqlite_classes)
web-ingest-serviceCrowWebSessionPersistent web session trackingv1/v3 (renamed from MyDurableObject)
cctv-ingest-serviceIngestSessionCCTV ingest sessions (deleted in v2)v1/v2
infra-crawl-serviceCrawlerContainerContainer-backed web crawlerv1 (new_sqlite_classes)

Migration Configuration

Durable Object migrations are defined in wrangler.jsonc under the migrations key:

"migrations": [
{ "tag": "v1", "new_sqlite_classes": ["PatternAnalyzerContainer"] }
]

For Workers Containers, the Durable Object class is the container class itself, using new_sqlite_classes for SQLite-backed persistent state.

Standard Durable Objects (non-container) use new_classes:

"migrations": [
{ "tag": "v1", "new_classes": ["IngestSession"] },
{ "tag": "v2", "deleted_classes": ["IngestSession"] }
]

Migrations are applied automatically on deploy. Ensure dev and prod migration arrays match to avoid drift.

D1 Database Migrations

Services Using D1

ServiceBindingMigrations DirDev Database Name
core-auth-serviceDBdrizzle/migrationscrow-core-auth-service-db-dev
core-user-serviceDBdrizzle/migrationscrow-core-user-service-db-dev
core-organization-serviceDBdrizzle/migrationscrow-core-organization-service-db-dev
core-product-serviceDBdrizzle/migrationscrow-core-product-service-db-dev
core-interaction-serviceDBdrizzle/migrationscrow-core-interaction-service-db-dev
core-pattern-serviceDBdrizzle/migrationscrow-core-pattern-service-db-dev
core-billing-serviceDBdrizzle/migrationscrow-core-billing-service-db-dev
core-analytics-serviceDBdrizzle/migrationscrow-core-analytics-service-db-dev
core-chat-serviceDBdrizzle/migrationscrow-core-chat-service-db-dev
mcp-serviceDB(default)crow-mcp-service-db-dev
bff-chat-serviceDBmigrationscrow-bff-chat-service-db-dev
bff-qna-serviceDB(default)crow-bff-qna-service-db-dev
cctv-ingest-serviceDBmigrationscrow-cctv-ingest-db-dev
web-ingest-serviceDB(default)crow-web-ingest-service-db-dev
core-social-collectorDBdrizzle/migrationscrow-social-collector-db-dev
dashboard-clientDB_MAIN(default)crow-dashboard-client-db-dev
landing-clientDB_MAIN(default)crow-landing-client-db-dev

Creating a New D1 Database

npx wrangler d1 create crow-my-service-db-dev

Copy the returned database_id into the service's wrangler.jsonc.

Running Migrations

Migrations are stored in each service's drizzle/migrations/ directory (or migrations/ for bff-chat-service, cctv-ingest-service):

npx wrangler d1 migrations apply DB --env dev --remote

The --remote flag applies migrations to the remote D1 database (not local).

Generating Migrations

After modifying src/db/schema.ts:

npx drizzle-kit generate

This generates a new SQL migration file in the migrations directory.

Querying a Database

npx wrangler d1 execute DB --env dev --command "SELECT * FROM user LIMIT 5"

Queue Workers

Queues provide asynchronous message passing between services. Queue names include the environment suffix (e.g., crow-interaction-queue-dev).

Queue Topology

Queue NameProducer(s)ConsumerDLQ
crow-interaction-queueweb-ingest-service, core-social-processorcore-interaction-service--
crow-cctv-batch-queuecctv-ingest-service, core-interaction-servicecore-interaction-service--
crow-product-crawl-queuecore-auth-servicecore-product-service--
crow-organization-context-queuecore-organization-servicecore-organization-servicecrow-organization-context-dlq
crow-social-processing-queuecore-social-collectorcore-social-processor--
crow-session-expiry-queueweb-ingest-serviceweb-ingest-service--
crow-web-session-exportweb-ingest-service----
email-queuecore-notification-servicecore-notification-serviceemail-dlq
crow-notification-queue--core-notification-service--

Consumer Configuration

Consumers are configured with batch size, timeout, retries, and optional DLQ:

"consumers": [
{
"queue": "crow-interaction-queue-dev",
"max_batch_size": 10,
"max_batch_timeout": 30,
"max_retries": 3,
"retry_delay": 60
}
]

Dead Letter Queues

DLQs are configured for critical queues:

  • crow-organization-context-dlq / crow-organization-context-dlq-dev
  • email-dlq / email-dlq-dev

Failed messages that exhaust all retries are routed to the DLQ for manual inspection.

Cron Triggers

ServiceSchedulePurpose
core-pattern-service0 * * * * (hourly), 0 2 * * * (daily 2am), 0 3 * * 1 (weekly Mon 3am), 0 4 1 * * (monthly 1st 4am), 0 5 1 1 * (yearly Jan 1st 5am)Pattern analysis at multiple intervals
bff-qna-service0 */12 * * * (every 12 hours)QnA index refresh
core-social-collector0 */2 * * * (every 2 hours)Social media data collection

Secrets Management

Secrets are never stored in wrangler.jsonc. They are set via the Wrangler CLI:

npx wrangler secret put SECRET_NAME --env dev

This prompts for the secret value interactively. The secret is stored in Cloudflare's encrypted secrets store and injected into the worker environment at runtime.

Listing Secrets

npx wrangler secret list --env dev

Common Secrets by Service

ServiceSecrets
core-api-gatewayINTERNAL_GATEWAY_KEY, SERVICE_API_KEY_ORG_SERVICE, CRAWLER_SERVICE_SECRET
core-auth-serviceBETTER_AUTH_SECRET, GOOGLE_CLIENT_ID, GOOGLE_CLIENT_SECRET, SERVICE_API_KEY_GATEWAY, SERVICE_API_KEY_WEB_INGEST, SERVICE_API_KEY_*
core-user-serviceBETTER_AUTH_SECRET, INTERNAL_GATEWAY_KEY, SERVICE_API_KEY_AUTH, SERVICE_API_KEY_ORGANIZATION, SERVICE_API_KEY_BILLING
core-organization-serviceINTERNAL_GATEWAY_KEY, SERVICE_API_KEY_GATEWAY, SERVICE_API_KEY_ORGANIZATION
core-product-serviceCRAWLER_SERVICE_SECRET
core-interaction-serviceSYSTEM_SECRET, INTERNAL_GATEWAY_KEY
core-pattern-serviceSYSTEM_SECRET, INTERNAL_GATEWAY_KEY
core-billing-serviceBETTER_AUTH_SECRET, INTERNAL_GATEWAY_KEY, STRIPE_SECRET_KEY, STRIPE_WEBHOOK_SECRET
core-notification-serviceBETTER_AUTH_SECRET, INTERNAL_GATEWAY_KEY, RESEND_API_KEY
core-analytics-serviceINTERNAL_GATEWAY_KEY
bff-qna-serviceINTERNAL_GATEWAY_KEY, CLOUDFLARE_API_TOKEN, CLOUDFLARE_R2_ACCESS_KEY_ID, CLOUDFLARE_R2_SECRET_ACCESS_KEY
mcp-serviceSERVICE_API_KEY, INTERNAL_GATEWAY_KEY
core-chat-serviceINTERNAL_GATEWAY_KEY
bff-chat-serviceINTERNAL_GATEWAY_KEY
a2a-serviceINTERNAL_GATEWAY_KEY
web-ingest-serviceINTERNAL_GATEWAY_KEY, SERVICE_API_KEY
core-social-collectorTAVILY_API_KEY, SYSTEM_SECRET
core-social-processor(inherits via queue binding)
infra-crawl-serviceCRAWLER_SERVICE_SECRET

Wrangler Configuration Structure

Every service's wrangler.jsonc follows this pattern:

{
"name": "crow-{service-name}",
"main": "src/index.ts",
"compatibility_date": "2025-12-17",
// Top-level = prod config
"vars": { "ENVIRONMENT": "prod", ... },
"d1_databases": [{ "binding": "DB", ... }],
"routes": [{ "pattern": "*.crowai.dev", "custom_domain": true }],
"env": {
"dev": {
"vars": { "ENVIRONMENT": "dev", ... },
"d1_databases": [{ ... }],
"routes": [{ "pattern": "dev.*.crowai.dev", ... }]
},
"local": {
"vars": { "ENVIRONMENT": "local", ... },
"d1_databases": [{ ... }]
}
}
}

Observability

All services have observability enabled in their wrangler config:

"observability": {
"enabled": true,
"head_sampling_rate": 1
}

This enables Cloudflare's built-in observability with 100% sampling. Logs can be viewed via wrangler tail or the Cloudflare dashboard.

Monitoring Commands

npx wrangler tail --env dev                    # Stream live logs
npx wrangler tail --env dev --format json # JSON formatted logs
npx wrangler d1 info DB --env dev # Database info
npx wrangler secret list --env dev # List all secrets
npx wrangler deployments list --env dev # Deployment history