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