Getting Started
Local Development Guide
Everything you need to run FluxyChat locally — from fresh clone to sending your first message, testing agents, and debugging the dashboard onboarding flow.
Prerequisites
| Tool | Minimum | Notes |
|---|---|---|
| Node.js | 18.x (20+ recommended) | Required for all apps and scripts |
| pnpm | 8.x | Monorepo package manager (corepack enable && pnpm install -g pnpm) |
| Git | 2.x | |
| Cloudflare account (optional) | — | Only needed for remote D1/R2 binding or deployment |
| Clerk account (optional) | — | Only needed if you want auth UI; dashboard works without it |
Without a Cloudflare account,
wrangler devcreates local D1/KV/R2 bindings automatically via Miniflare. You only need real bindings for production deployment.
1. Clone & Install
git clone https://github.com/fluxychat/fluxychat.git
cd fluxychat
pnpm install2. Environment Setup
Run the automated setup script — it copies template files without overwriting existing ones:
pnpm run dev:setupThis creates:
apps/worker/.dev.vars← from.dev.vars.exampleapps/dashboard/.env.local← from.env.example
Worker: apps/worker/.dev.vars
For basic local dev, you only need these entries:
# Required for project provisioning
ALLOW_DEV_PROVISION=true
# Optional — enable hosted multi-tenant mode
HOSTED_MULTI_TENANT=true
FLUXY_PLATFORM_PROJECT_ID=<your-uuid-or-omit>
# Optional — AI/LLM provider keys (uncomment what you use)
# AI_API_KEY=sk-...
# ANTHROPIC_API_KEY=sk-ant-...
# OPENROUTER_API_KEY=sk-or-...
# GROQ_API_KEY=gsk_...
# DEEPSEEK_API_KEY=sk-...
# OLLAMA_BASE_URL=http://localhost:11434 # for local models
# Optional — feature flags
FEATURE_VOICE_MESSAGES=true
FEATURE_REPLY_SUGGESTIONS=trueThe full template (apps/worker/.dev.vars.example) documents 100+ variables covering Stripe, rate limits, SMS OTP, push notifications, quotas, and more. Most default to sensible values — only set what you need.
Dashboard: apps/dashboard/.env.local
# Point dashboard at your local worker
NEXT_PUBLIC_FLUXYCHAT_WORKER_URL=http://127.0.0.1\:8787
# Optional — Clerk auth (omit for manual quickstart mode)
# NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY=pk_test_...
# CLERK_SECRET_KEY=sk_test_...
# NEXT_PUBLIC_CLERK_SIGN_UP_FALLBACK_REDIRECT_URL=/onboarding
# Optional — console gate (skip for local dev)
# CONSOLE_GATE_SECRET=your-secret-hereWithout Clerk: The dashboard runs in manual mode — you'll use the
/onboardingflow to enter a Worker URL and API key directly. TheUserButtonand sign-in/sign-up buttons are hidden.
AI Agent: apps/ai-agent/.dev.vars
Only needed if you want the AI agent service running alongside the worker:
FLUXY_BASE_URL=http://127.0.0.1\:8787
JWT_SECRET=local-dev-secret
# OPENAI_API_KEY=sk-...Verify env readiness
pnpm run check:envThis runs scripts/check-env-readiness.mjs — a pre-flight checklist that catches missing or inconsistent values.
3. Start Dev Servers
All apps in parallel (recommended)
pnpm devThis uses Turbo to run dev across apps/* in parallel:
- Worker →
http://127.0.0.1:8787(Wrangler + Miniflare) - Dashboard →
http://localhost:3000 - AI Agent →
http://127.0.0.1:8788(Wrangler)
Individual apps
# Worker only
cd apps/worker && pnpm dev
# Dashboard only (needs worker running for API calls)
cd apps/dashboard && pnpm dev
# AI Agent only (needs worker running for webhooks)
cd apps/ai-agent && pnpm devBuild order
Turbo handles this automatically for pnpm build, but if you build manually:
@fluxy-chat/protocol → @fluxy-chat/sdk → @fluxy-chat/ui → @fluxy-chat/agent → apps/dashboardThe dashboard's build script in package.json chains these for you.
4. First Project & Message
Option A: Dashboard onboarding (GUI)
- Open
http://localhost:3000/onboarding - With Clerk: Sign up/in → the dashboard auto-connects
- Without Clerk: Enter your Worker URL (
http://127.0.0.1:8787) and click "Connect" - The onboarding wizard walks you through:
- Project creation (auto-provisioned via
ALLOW_DEV_PROVISION=true) - JWT minting (admin + member tokens)
- First room creation
- First message (celebrates with confetti when sent)
- Project creation (auto-provisioned via
Option B: Terminal quickstart (90 seconds)
pnpm run first-messageThis script:
- Starts a local Worker (inline Miniflare)
- Provisions a project
- Mints an admin JWT
- Creates a room
- Sends a message
- Prints the JWT and room ID for SDK use
Option C: Manual curl
# Mint a project-scoped JWT
curl -X POST "http://127.0.0.1\:8787/auth/token" \
-H "Content-Type: application/json" \
-H "X-Fluxy-Api-Key: fc_your_api_key" \
-d '{"userId":"alice","roles":["admin"],"ttlSeconds":3600}'
# Create a room
curl -X POST "http://127.0.0.1\:8787/rooms" \
-H "Authorization: Bearer <JWT>" \
-H "Content-Type: application/json" \
-d '{"name":"general","isPublic":true}'
# Send a message
curl -X POST "http://127.0.0.1\:8787/rooms/<roomId>/messages" \
-H "Authorization: Bearer <JWT>" \
-H "Content-Type: application/json" \
-d '{"content":"Hello from local dev!"}'5. Testing Realtime (WebSocket)
SDK hook
import { FluxyChatClient, useChat } from "@fluxy-chat/sdk";
const client = new FluxyChatClient({
baseUrl: "http://127.0.0.1\:8787",
userId: "alice",
token: "<your-member-jwt>",
});
function ChatRoom() {
const { messages, sendMessage } = useChat({ roomId: "general", client });
return (
<div>
{messages.map((m) => (
<div key={m.id}>{m.content}</div>
))}
<input
onKeyDown={(e) => {
if (e.key === "Enter") sendMessage(e.currentTarget.value);
}}
/>
</div>
);
}Raw WebSocket test
# Connect to a room's WebSocket
wscat -c "ws://127.0.0.1\:8787/rooms/general/ws?userId=alice&token=<JWT>"6. Testing Agents
Create an agent
curl -X POST "http://127.0.0.1\:8787/agents" \
-H "Authorization: Bearer <JWT>" \
-H "Content-Type: application/json" \
-d '{
"name": "Support Bot",
"handle": "support",
"provider": "openai",
"model": "gpt-4o-mini",
"capabilities": ["chat"],
"systemPrompt": "You are a helpful support assistant."
}'Invoke via curl
curl -X POST "http://127.0.0.1\:8787/agents/<agentId>/invoke" \
-H "Authorization: Bearer <JWT>" \
-H "Content-Type: application/json" \
-d '{"roomId":"general","content":"What is FluxyChat?"}'Via the dashboard
- Navigate to Agents in the sidebar
- Click Create agent → fill in provider, model, system prompt
- Open a room → type
@support <message>to trigger the agent
AI Agent Service: For webhook-triggered agents (mention-based), ensure
apps/ai-agentis running and its.dev.varshas the correctFLUXY_BASE_URLandJWT_SECRET.
7. Common Tasks
Run tests
# All packages
pnpm test
# Worker unit tests
cd apps/worker && pnpm test
# Dashboard unit tests
cd apps/dashboard && pnpm test
# Worker e2e tests (requires running worker)
cd apps/worker && pnpm test:e2e
# Dashboard e2e smoke tests (Playwright)
cd apps/dashboard && pnpm test:e2e:smokeLint
pnpm lintSmoke test the worker API
# Against a remote deployment
cd apps/worker && pnpm smoke:remote -- --base-url https://your-worker.your-subdomain.workers.dev --admin-jwt <JWT>
# Bundled end-to-end (auth → room → message → GDPR)
export TEST_API_KEY=fc_...
pnpm smoke:bundledProvisions / bootstrap
# Create platform project (for hosted multi-tenant mode)
pnpm run provision:bootstrap8. Clerk Setup (Optional)
If you want the full hosted experience with Clerk auth:
-
Create a Clerk application at clerk.com
-
Get your Publishable Key (
pk_test_...) from Clerk Dashboard → API Keys -
Get your Secret Key (
sk_test_...) from the same page (server-only) -
Add to
apps/dashboard/.env.local:NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY=pk_test_... CLERK_SECRET_KEY=sk_test_... NEXT_PUBLIC_CLERK_SIGN_UP_FALLBACK_REDIRECT_URL=/onboarding -
Restart the dashboard dev server
Clerk middleware in
apps/dashboard/middleware.tsautomatically activates when both keys are present. Without them, the middleware is a no-op and all routes are public.
Clerk webhook (for auto-provisioning)
To auto-create FluxyChat projects when users sign up:
-
In Clerk Dashboard → Webhooks → Add Endpoint
-
URL:
https://your-dashboard.com/api/webhooks/clerk -
Subscribe to
user.createdevents -
Copy the Signing Secret (
whsec_...) to:CLERK_WEBHOOK_SIGNING_SECRET=whsec_... DASHBOARD_PUBLIC_URL=https://your-dashboard.com
9. Troubleshooting
| Symptom | Cause | Fix |
|---|---|---|
| Worker 502 on startup | Miniflare D1 not initialized | cd apps/worker && npx wrangler d1 migrations apply fluxychat --local |
| Dashboard "No active project" | JWT not in session | Go through /onboarding or set JWT in localStorage |
| WebSocket connection refused | Worker not running | Ensure pnpm dev or cd apps/worker && pnpm dev is running |
| Clerk sign-in loop | Missing redirect URLs | Set NEXT_PUBLIC_CLERK_SIGN_UP_FALLBACK_REDIRECT_URL=/onboarding |
UserButton invisible | Clerk not configured | Add NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY — or use manual quickstart mode |
| Agent invoke timeout | No LLM API key in .dev.vars | Add AI_API_KEY or provider-specific key to apps/worker/.dev.vars |
Build error: @fluxy-chat/sdk not found | Packages not built | Run pnpm build from repo root (Turbo handles order) |
| Voice messages not working | Feature flag off | Set FEATURE_VOICE_MESSAGES=true in apps/worker/.dev.vars |
For more troubleshooting, see Troubleshooting.
10. Architecture Quick Reference
flowchart TB
subgraph dashboard["apps/dashboard — Next.js :3000"]
landing["/landing"]
onboarding["/onboarding"]
console["/rooms · /agents · /admin"]
landing --> onboarding
onboarding --> console
end
subgraph worker["apps/worker — Cloudflare Worker :8787"]
rest["REST API"]
ws["WebSocket"]
do["Durable Objects\n(Room, User, RateLimit)"]
d1["D1 · KV · R2"]
rest --> do
ws --> do
do --> d1
end
subgraph agent["apps/ai-agent — Worker :8788"]
llm["Mention webhooks → LLM → replies"]
end
console -->|"REST + WebSocket"| worker
worker -->|"webhooks"| agentKey ports
| Service | Port | Protocol |
|---|---|---|
| Dashboard | 3000 | HTTP (Next.js) |
| Worker | 8787 | HTTP + WebSocket (Wrangler) |
| AI Agent | 8788 | HTTP (Wrangler) |