Deployment
AI Supreme Council is deployed as static files on Cloudflare Pages with API logic running on Cloudflare Workers. A unified deploy script handles all targets.
Deployment Targets
| Target | URL | Type | Command |
|---|---|---|---|
| App | aiscouncil.com | CF Pages (static) | scripts/deploy.sh pages |
| Staging | aiscouncil.net | CF Pages (static) | scripts/deploy.sh pages-staging |
| API Worker | api.aiscouncil.com | CF Worker | scripts/deploy.sh worker |
| Auth Worker | auth.aiscouncil.com | CF Worker | scripts/deploy.sh worker-auth |
| App Store | store.aiscouncil.com | CF Pages (static) | scripts/deploy.sh store |
| All | Everything above | All | scripts/deploy.sh all |
Environment Variables
Export these in ~/.bashrc (never commit them):
export CF_ACCOUNT_ID_AISCOUNCIL="your-cloudflare-account-id"
export CF_PAGES_TOKEN_AISCOUNCIL="your-pages-api-token"
export CF_WORKER_TOKEN_AISCOUNCIL="your-worker-api-token"
Optional overrides:
export CF_PAGES_PROJECT_AISCOUNCIL="aiscouncil" # default
export CF_PAGES_PROJECT_AISCOUNCIL_STAGING="aiscouncil-staging" # default
These tokens grant deploy access to your Cloudflare account. Never commit them to the repository. The deploy script will exit with an error if required variables are missing.
Pages Deployment (Production)
Step-by-Step
- Assemble the app from source:
./build.sh
- Deploy to production:
scripts/deploy.sh pages
This command:
- Creates a clean
_deploy/directory - Copies static files via
rsync, excluding development artifacts - Minifies
index.htmlwithhtml-minifier-terser(~40% size reduction) - Deploys to Cloudflare Pages with
--branch=main - Cleans up
_deploy/
Production deploys always use --branch=main. This is required for CF Pages to serve on the production domain (aiscouncil.com).
What Gets Deployed
The rsync step excludes everything that is not a browser-facing asset:
Excluded directories: src/, tools/, kernel/, serve/, worker/, worker-auth/, doc.aiscouncil.com/, node_modules/, .git/, .github/, .carl/, .claude/, modules/, scripts/, core-types/, bridge/, i18n/, dist/, build/
Excluded file types: *.py, *.zig, *.zon, *.md, *.sh, *.css, .env*
Excluded config files: package.json, package-lock.json, vitest.config.*, tsconfig.json, .cfignore, .gitignore
What remains are the production assets: index.html, sw.js, icons, manifest.webmanifest, registry/ JSON files, sdk/, ads.json, sitemap.xml, and any mini-program or app directories.
Minification
Production deploys pass index.html through html-minifier-terser with these options:
- Collapse whitespace
- Remove comments
- Remove redundant attributes
- Collapse boolean attributes
- Minify inline CSS
- Minify inline JavaScript
Typical size reduction is ~40% (e.g., 980 KB down to ~580 KB).
Staging Deployment
Deploy to the staging environment without minification:
scripts/deploy.sh pages-staging
Staging is served from aiscouncil.net. The app auto-detects its domain at runtime and adjusts API URLs, cookie domains, and cross-origin references accordingly.
Promoting Staging to Production
After validating on staging, promote the same build to production:
scripts/deploy.sh promote
This redeploys the current code to the production Pages project with minification enabled. The app code is identical -- only the domain changes.
Worker Deployment
API Worker
scripts/deploy.sh worker
This runs npx wrangler deploy inside the worker/ directory using the account ID and Worker token from your environment.
Auth Worker
scripts/deploy.sh worker-auth
Same process for the worker-auth/ directory.
Worker Secrets
Workers require secrets that are set separately from code deploys. Use wrangler secret put from the worker directory:
cd worker
npx wrangler secret put JWT_SECRET
npx wrangler secret put STRIPE_SECRET_KEY
npx wrangler secret put STRIPE_WEBHOOK_SECRET
npx wrangler secret put WEBHOOK_PATH_SECRET
cd worker-auth
npx wrangler secret put JWT_SECRET
npx wrangler secret put GOOGLE_CLIENT_SECRET
npx wrangler secret put APPLE_CLIENT_SECRET
npx wrangler secret put GITHUB_CLIENT_SECRET
Secrets persist across deploys. You only need to set them once, or when rotating credentials.
Worker Configuration
Each worker has a wrangler.toml that defines:
- Worker name and routes
- KV namespace bindings
- Environment variable references
- Compatibility settings
Service Worker Cache
The client-side Service Worker (sw.js) uses a versioned cache:
const CACHE = 'ais-v1.0.0';
When to bump the cache version:
- Breaking changes to the app shell (HTML structure, critical CSS)
- Changes to precached assets (icons, manifest)
- Major version releases
Bumping the version causes the Service Worker to:
- Create a new cache with the new name
- Precache all listed assets
- Delete all old caches on activation
Forgetting to bump the cache version after breaking changes will cause users to see stale content until they manually clear their browser cache or the old Service Worker expires.
Deploy Everything
Deploy the Pages app, API worker, and auth worker in sequence:
scripts/deploy.sh all
Post-Deploy Verification
After deploying, verify the app is serving correctly:
# Check production
curl -s https://aiscouncil.com/ | head -5
# Check API health
curl -s https://api.aiscouncil.com/health
# Check auth health
curl -s https://auth.aiscouncil.com/health
Cloudflare Pages auto-invalidates its CDN cache on deploy, but propagation may take 1-2 minutes globally. If you see stale content, wait briefly and try again.
Domain Architecture
The app uses domain detection at runtime to support both production and staging:
| Domain | Constant | Production | Staging |
|---|---|---|---|
| App | AIS.DOMAIN | aiscouncil.com | aiscouncil.net |
| Marketing | AIS.WWW | www.aiscouncil.com | www.aiscouncil.net |
| API | API_BASE | https://api.aiscouncil.com/v1 | https://api.aiscouncil.net/v1 |
| Auth | AUTH_BASE | https://auth.aiscouncil.com/v1 | https://auth.aiscouncil.net/v1 |
| Docs | AIS.DOC_BASE | https://doc.aiscouncil.com | https://doc.aiscouncil.net |
| Store | AIS.STORE_URL | https://store.aiscouncil.com | https://store.aiscouncil.net |
API base URLs can also be overridden via localStorage for local development:
localStorage.setItem('ais-api-base', 'http://localhost:8787/v1');
localStorage.setItem('ais-auth-base', 'http://localhost:8788/v1');
Local Development
For local development without deploying:
- Build the app:
./build.sh - Serve
index.htmlwith any static file server (e.g.,python3 -m http.server 8080) - Run Workers locally with Wrangler:
cd worker && npx wrangler dev
cd worker-auth && npx wrangler dev --port 8788
- Override API base URLs in the browser console:
localStorage.setItem('ais-api-base', 'http://localhost:8787/v1');
localStorage.setItem('ais-auth-base', 'http://localhost:8788/v1');
location.reload();