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
4 changes: 4 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,10 @@ TELEGRAM_BOT_TOKEN=your-telegram-bot-token
# OpenClaw version for container image (optional, default: latest)
# OPENCLAW_VERSION=latest

# Skip WebStack deployment (optional, default: deploy web)
# Set to "false" to deploy only Telegram bot stacks (no web build needed)
DEPLOY_WEB=false

# Predictive pre-warming (optional, disabled by default)
# Comma-separated cron expressions for EventBridge rules
# PREWARM_SCHEDULE=0 9 ? * MON-FRI *,0 14 ? * SAT-SUN *
Expand Down
1 change: 1 addition & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,7 @@ Table names use the `TABLE_NAMES` constant from `@serverless-openclaw/shared`.
- **Predictive Pre-Warming:** Optional EventBridge cron → prewarm Lambda → ECS RunTask with `USER_ID=system:prewarm`. Container claimed by first real user message (TaskState ownership transfer). Watchdog skips tasks where `now < prewarmUntil`. Configured via `PREWARM_SCHEDULE` (comma-separated crons) and `PREWARM_DURATION` (minutes, default 60) env vars. Disabled by default (no EventBridge rules created without schedule).
- **Telegram-Web Identity Linking:** OTP-based linking via Settings table. Web UI generates 6-digit OTP -> Telegram `/link {code}` verifies and creates bilateral link records -> resolveUserId maps telegram userId to cognitoId for container sharing. Unlinking is Web-only (IDOR prevention). REST API: POST /link/generate-otp, GET /link/status, POST /link/unlink (all JWT-authenticated)
- **HTTP API CORS:** `corsPreflight` required — Web (CloudFront) → API Gateway is cross-origin. `allowOrigins: ["*"]`, `allowHeaders: [Authorization, Content-Type]`
- **Telegram-only deployment:** `DEPLOY_WEB=false` skips WebStack and the web asset build. Use `make deploy-telegram`. MonitoringStack and ApiStack handle missing WebStack gracefully.

## Phase 1 Progress (10/10 — Complete)

Expand Down
5 changes: 4 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ USER_POOL := ap-northeast-2_r6wLZ95dd
CLIENT_ID := 1hgp8h9jico924p1atcr2c9ki9
CLUSTER := serverless-openclaw

.PHONY: help build test lint deploy-all deploy-web deploy-image deploy-image-soci \
.PHONY: help build test lint deploy-all deploy-telegram deploy-web deploy-image deploy-image-soci \
user-create user-password user-list user-delete \
task-list task-status task-stop task-stop-recent task-logs task-clean \
telegram-webhook telegram-status \
Expand Down Expand Up @@ -55,6 +55,9 @@ teardown: ## Destroy all CDK stacks (DANGEROUS)
@read -p "Type 'yes' to confirm: " confirm && [ "$$confirm" = "yes" ] || exit 1
cd packages/cdk && npx cdk destroy --all --profile $(AWS_PROFILE)

deploy-telegram: ## Deploy all stacks except WebStack (Telegram-only)
cd packages/cdk && DEPLOY_WEB=false npx cdk deploy --all --profile $(AWS_PROFILE) --require-approval never

## ─── Container Image ─────────────────────────────────────────────────────────

deploy-image: ## Build and push Docker image to ECR
Expand Down
22 changes: 22 additions & 0 deletions docs/deployment.md
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,17 @@ npx cdk deploy WebStack --profile $AWS_PROFILE
npx cdk deploy MonitoringStack --profile $AWS_PROFILE
```

### Telegram-only Deployment (no Web UI)

Set `DEPLOY_WEB=false` to skip WebStack and the web asset build entirely. Useful when only Telegram bot functionality is needed, saving build time and CloudFront costs.

```bash
make deploy-telegram
# equivalent to: DEPLOY_WEB=false npx cdk deploy --all ...
```

MonitoringStack and ApiStack handle a missing WebStack gracefully.

### Push Docker Image

To run the Fargate container, you need to push a Docker image to ECR.
Expand Down Expand Up @@ -267,6 +278,17 @@ VITE_COGNITO_USER_POOL_ID=<AuthStack.UserPoolId>
VITE_COGNITO_CLIENT_ID=<AuthStack.UserPoolClientId>
```

### Deploy-time Feature Flags

Set in `.env` or exported before running CDK commands.

| Variable | Default | Values | Purpose |
|----------|---------|--------|---------|
| `AGENT_RUNTIME` | `fargate` | `fargate` \| `lambda` \| `both` | Compute path selection |
| `AI_PROVIDER` | `anthropic` | `anthropic` \| `bedrock` | AI provider selection |
| `AI_MODEL` | _(provider default)_ | any model ID | Override default model |
| `DEPLOY_WEB` | `true` | `true` \| `false` | Include WebStack deployment |

---

## 7. Verification
Expand Down
15 changes: 9 additions & 6 deletions packages/cdk/bin/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import {
const app = new cdk.App();

const agentRuntime = process.env.AGENT_RUNTIME ?? "fargate"; // default: backward compatible
const deployWeb = process.env.DEPLOY_WEB !== "false"; // default: true (deploy web)

// Secrets (SSM SecureString parameters)
const secrets = new SecretsStack(app, "SecretsStack");
Expand Down Expand Up @@ -76,12 +77,14 @@ if (compute) {
api.addDependency(secrets);

// Step 1-8: Web UI (S3 + CloudFront)
new WebStack(app, "WebStack", {
webSocketUrl: `wss://${api.webSocketApi.apiId}.execute-api.${cdk.Aws.REGION}.amazonaws.com/prod`,
apiUrl: api.httpApi.apiEndpoint,
userPoolId: auth.userPool.userPoolId,
userPoolClientId: auth.userPoolClient.userPoolClientId,
});
if (deployWeb) {
new WebStack(app, "WebStack", {
webSocketUrl: `wss://${api.webSocketApi.apiId}.execute-api.${cdk.Aws.REGION}.amazonaws.com/prod`,
apiUrl: api.httpApi.apiEndpoint,
userPoolId: auth.userPool.userPoolId,
userPoolClientId: auth.userPoolClient.userPoolClientId,
});
}

// Monitoring Dashboard
new MonitoringStack(app, "MonitoringStack");
Expand Down