Skip to content

Commit bcd989d

Browse files
feat: integrate push notifications and Firebase support
- Added Firebase Cloud Messaging (FCM) integration for push notifications. - Updated .gitignore to exclude Firebase service account keys. - Enhanced iOS and Android configurations to support push notifications. - Implemented push notification handling in the service worker for web. - Added API routes for managing push notification tokens. - Updated environment variables for Firebase messaging configuration. - Improved app initialization to register for remote notifications and handle foreground/background states.
1 parent 818d466 commit bcd989d

29 files changed

Lines changed: 1888 additions & 44 deletions

.githooks/pre-commit

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
#!/bin/sh
2+
#
3+
# Pre-commit hook: scan staged changes for secrets using Gitleaks.
4+
# Setup: git config core.hooksPath .githooks
5+
#
6+
7+
if ! command -v gitleaks >/dev/null 2>&1; then
8+
echo "⚠️ gitleaks not found — skipping secret scan"
9+
echo " Install: brew install gitleaks"
10+
echo " https://github.com/gitleaks/gitleaks#installing"
11+
exit 0
12+
fi
13+
14+
gitleaks git --pre-commit --staged --redact --verbose

.github/workflows/secret-scan.yml

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
name: Secret Scan
2+
3+
on:
4+
push:
5+
branches: [main]
6+
pull_request:
7+
8+
jobs:
9+
gitleaks:
10+
name: Gitleaks
11+
runs-on: ubuntu-latest
12+
steps:
13+
- uses: actions/checkout@v4
14+
with:
15+
fetch-depth: 0
16+
17+
- uses: gitleaks/gitleaks-action@v2
18+
env:
19+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,3 +47,6 @@ ios/DerivedData/
4747

4848
# Apple Sign in with Apple private keys
4949
*.p8
50+
51+
# Firebase service account keys
52+
*-firebase-adminsdk-*.json

.gitleaks.toml

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
# Gitleaks configuration for BotsChat
2+
# https://github.com/gitleaks/gitleaks
3+
4+
title = "BotsChat Secret Scanning"
5+
6+
[allowlist]
7+
description = "Known public client-side keys and build artifacts"
8+
paths = [
9+
'''package-lock\.json''',
10+
'''node_modules/''',
11+
'''\.wrangler/''',
12+
# Build output contains inlined client-side config — not secrets
13+
'''dist/''',
14+
]
15+
regexTarget = "line"
16+
regexes = [
17+
# Firebase client-side config (public by design — restricted by Firebase Security Rules and domain allowlists)
18+
'''VITE_FIREBASE_API_KEY''',
19+
'''VITE_FIREBASE_AUTH_DOMAIN''',
20+
'''VITE_FIREBASE_PROJECT_ID''',
21+
'''VITE_FIREBASE_MESSAGING_SENDER_ID''',
22+
'''VITE_FIREBASE_APP_ID''',
23+
'''VITE_FIREBASE_VAPID_KEY''',
24+
# Google OAuth client IDs (public — not secrets)
25+
'''VITE_GOOGLE_.*_CLIENT_ID''',
26+
# Google Analytics measurement ID (public)
27+
'''VITE_GA_MEASUREMENT_ID''',
28+
]

CLAUDE.md

Lines changed: 192 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,192 @@
1+
# BotsChat
2+
3+
A full-stack messaging application built on Cloudflare Workers. Connects to self-hosted OpenClaw AI assistant instances via WebSocket, providing end-to-end encrypted AI chat and scheduled task management.
4+
5+
- Production: https://console.botschat.app
6+
- GitHub: https://github.com/botschat-app/botsChat
7+
8+
## Project Structure
9+
10+
```
11+
botsChat/
12+
├── packages/
13+
│ ├── api/ # Cloudflare Worker API (Hono + D1 + R2 + DO)
14+
│ ├── web/ # React SPA frontend (Vite)
15+
│ ├── plugin/ # OpenClaw plugin (WebSocket client)
16+
│ └── e2e-crypto/ # E2E encryption library (PBKDF2 + AES-GCM)
17+
├── migrations/ # D1 database migration files
18+
├── scripts/ # Dev scripts (dev.sh, mock-openclaw.mjs)
19+
├── tests/ # Test scripts
20+
├── ios/ # Capacitor iOS shell
21+
├── android/ # Capacitor Android shell
22+
└── wrangler.toml # Cloudflare Workers configuration
23+
```
24+
25+
## Cloudflare Resources
26+
27+
| Resource | Binding |
28+
|----------|---------|
29+
| D1 Database | `DB``botschat-db` |
30+
| R2 Bucket | `MEDIA``botschat-media` |
31+
| Durable Object | `CONNECTION_DO``ConnectionDO` |
32+
33+
## Architecture Principles
34+
35+
### Data Ownership
36+
37+
| Owner | Storage | Examples |
38+
|-------|---------|----------|
39+
| **BotsChat** | D1 | Task names, channel IDs, user info, message records |
40+
| **OpenClaw** | OpenClaw CronService | Schedule, instructions, model, job run status |
41+
42+
Key rules:
43+
- OpenClaw-owned data must be fetched in real time; never cache copies in D1 or DO Storage
44+
- D1 only stores BotsChat's own metadata (task↔channel associations, user info)
45+
- When OpenClaw data is needed, request it via DO → plugin WebSocket (`task.scan.request``task.scan.result`)
46+
47+
### Interacting with OpenClaw
48+
49+
All CronService mutations must go through the OpenClaw CLI (`openclaw cron add/edit/rm`). Never directly read/write `~/.openclaw/cron/jobs.json`.
50+
51+
Notes:
52+
- `openclaw cron edit` for isolated sessions requires the `--message` flag
53+
- `openclaw cron add` requires the `--name` flag
54+
- On macOS, all CLI commands need `/opt/homebrew/bin` in `env.PATH`
55+
56+
### ID Generation
57+
58+
- BotsChat entity IDs: prefixed (`tsk_xxx`, `ch_xxx`, `u_xxx`), generated by BotsChat
59+
- OpenClaw cron job IDs: UUID format, generated by OpenClaw, returned via `task.schedule.ack`
60+
61+
### ConnectionDO
62+
63+
`ConnectionDO` is the WebSocket relay hub (one instance per user):
64+
- Holds the OpenClaw plugin WebSocket (tag: `"openclaw"`)
65+
- Holds browser session WebSocket(s) (tag: `"browser:<sessionId>"`)
66+
- Relays messages bidirectionally (OpenClaw ↔ browser)
67+
- Persists messages to D1
68+
- Uses the Hibernation API for zero-cost idle connections
69+
70+
## Local Development
71+
72+
### Quick Start
73+
74+
```bash
75+
./scripts/dev.sh # Full dev env: build + migrate + server + mock AI + open browser
76+
./scripts/dev.sh reset # Wipe local DB → re-migrate → start full dev env
77+
./scripts/dev.sh server # Server only (no mock, no browser)
78+
./scripts/dev.sh mock # Start Mock OpenClaw standalone (foreground)
79+
./scripts/dev.sh migrate # Only run D1 migrations
80+
./scripts/dev.sh build # Only build web frontend
81+
```
82+
83+
No env vars needed — `dev.sh` auto-generates `DEV_AUTH_SECRET`, starts mock AI in background, and opens browser with auto-login + E2E.
84+
85+
### Manual Start
86+
87+
```bash
88+
npm run build -w packages/web
89+
npx wrangler dev --config wrangler.toml --ip 0.0.0.0 \
90+
--var ENVIRONMENT:development \
91+
--var DEV_AUTH_SECRET:any-secret-string
92+
```
93+
94+
### D1 Migrations
95+
96+
```bash
97+
npx wrangler d1 migrations apply botschat-db --local # Apply migrations
98+
rm -rf .wrangler/state && npx wrangler d1 migrations apply botschat-db --local # Full reset
99+
```
100+
101+
### Authentication
102+
103+
- **Production**: Google / GitHub OAuth only
104+
- **Local dev**: `ENVIRONMENT=development` enables email registration; `DEV_AUTH_SECRET` enables the `/api/dev-auth/login` endpoint
105+
106+
### Browser Auto-Login (Local Dev)
107+
108+
```
109+
http://localhost:8787/?dev_token=<DEV_AUTH_SECRET>&dev_user=<userId>&dev_e2e=<e2e_password>
110+
```
111+
112+
Parameters: `dev_token` (required), `dev_user` (optional, defaults to `dev-test-user`), `dev_e2e` (optional, auto-sets E2E password).
113+
114+
## Mock OpenClaw (Local Testing)
115+
116+
`scripts/mock-openclaw.mjs` is a zero-dependency Node.js WebSocket client that simulates the OpenClaw plugin protocol, enabling full BotsChat testing without deploying a real OpenClaw instance.
117+
118+
### Quick Start
119+
120+
```bash
121+
# Terminal 1: start the server
122+
./scripts/dev.sh
123+
124+
# Terminal 2: start mock (auto-creates a pairing token)
125+
./scripts/dev.sh mock
126+
```
127+
128+
### Manual Start
129+
130+
```bash
131+
node scripts/mock-openclaw.mjs --token <your_pairing_token>
132+
```
133+
134+
### Options
135+
136+
| Flag | Default | Description |
137+
|------|---------|-------------|
138+
| `--token <pat>` | (required) | Pairing token |
139+
| `--url <url>` | `http://localhost:8787` | Server URL |
140+
| `--agents <list>` | `main` | Comma-separated agent IDs |
141+
| `--delay <ms>` | `300` | Reply delay (simulates thinking) |
142+
| `--stream` | `false` | Enable streaming replies (chunk by chunk) |
143+
| `--model <name>` | `mock/echo-1.0` | Default model name |
144+
145+
### Mock Behavior
146+
147+
| Incoming Message | Response |
148+
|-----------------|----------|
149+
| `user.message` | Echoes back as `agent.text`: "Mock reply: {text}" |
150+
| `user.media` | Acknowledges media receipt |
151+
| `user.command` | Acknowledges command |
152+
| `user.action` | Acknowledges A2UI interaction |
153+
| `task.scan.request` | Returns empty task list |
154+
| `models.request` | Returns 4 mock models |
155+
| `task.schedule` | `task.schedule.ack` confirmation |
156+
| `task.run` | Simulates 2-second execution + `job.update` |
157+
| `settings.defaultModel` | `defaultModel.updated` confirmation |
158+
| `ping` | `pong` |
159+
160+
## Testing
161+
162+
```bash
163+
./tests/media-api-test.sh # 17 API tests
164+
node tests/media-ws-test.mjs # 9 WebSocket tests
165+
node tests/media-browser-test.mjs # Browser test data prep
166+
npm test -w packages/e2e-crypto # E2E crypto unit tests
167+
```
168+
169+
## Deployment
170+
171+
```bash
172+
npm run build -w packages/web
173+
npx wrangler deploy --config wrangler.toml
174+
npx wrangler d1 migrations apply botschat-db --remote
175+
```
176+
177+
Production uses `ENVIRONMENT=production` (OAuth only). Secrets are set via `wrangler secret put`.
178+
179+
## Debugging Tips
180+
181+
- **Port conflict**: `lsof -ti:8787 | xargs kill -9`
182+
- **D1 schema error**: `rm -rf .wrangler/state` → re-migrate
183+
- **Plugin WS URL**: `cloudUrl` must be `http://...`; the plugin auto-converts to `ws://`
184+
- **Blank screen after login**: Hard refresh (`Cmd+Shift+R`) or clear localStorage
185+
186+
## UI Design
187+
188+
See `.cursor/rules/design-guideline.md` for the full specification. Key principles:
189+
- Three-column layout (Icon Rail + Sidebar + Main Content + optional Detail Panel)
190+
- Dark/light dual themes via CSS variables
191+
- Flat message rows (not bubbles) for information density
192+
- Sidebar always uses dark/brand background; only Main Content follows theme

0 commit comments

Comments
 (0)