French chunking practice app based on the method by Français avec Pierre. Practice selecting chunks, drilling pronunciation, writing sentences (with optional grammar check), and a timed mini-monologue. Includes a chunk library (add/edit/delete custom chunks) and practice history.
- Install dependencies:
npm install - Set up Cloudflare Worker secrets for local development:
Generate a secret and add it to
cp .dev.vars.example .dev.vars
.dev.vars:openssl rand -base64 32
API_KEY_COOKIE_SECRET=<your-generated-secret> - For deployed environments, set
API_KEY_COOKIE_SECRETas a Worker secret (see Production deployment).
The app uses a Cloudflare Worker BFF to store API keys in an encrypted HttpOnly cookie. Run both processes:
# Terminal 1 — build static assets + serve API routes
npm run build && npm run dev:worker
# Terminal 2 — Vite dev server (proxies /api to the worker)
npm run devOpen http://localhost:5173. Enter your Gemini API key in Settings — it is sent once to /api/session and stored in an HttpOnly cookie, not in localStorage.
Get a Gemini key at Google AI Studio.
Fluide deploys as a Cloudflare Worker with static assets (not Cloudflare Pages). The Worker serves the Vite-built SPA from dist/ and handles /api/* BFF routes.
npm run deployThis runs npm run build then wrangler deploy, uploading both the Worker and dist/ assets in one step.
The fluide Worker is connected to GitHub. Configure in Workers & Pages → fluide → Settings → Build:
| Setting | Value |
|---|---|
| Build command | npm run build |
| Deploy command (production branch) | npm run deploy or npx wrangler deploy |
| Non-production branch deploy command | npm run deploy:preview or npx wrangler versions upload |
| Production branch | main |
Enable Builds for non-production branches under Settings → Build → Branch control so PRs get preview URLs.
Set these in Workers & Pages → fluide → Settings → Variables & Secrets:
| Name | Type | Required | Description |
|---|---|---|---|
API_KEY_COOKIE_SECRET |
Secret | Yes | 32+ byte random string used to seal user Gemini API keys in the HttpOnly cookie. Generate with openssl rand -base64 32. |
API_KEY_COOKIE_SECRET_PREVIOUS |
Secret | No | Previous secret for zero-downtime rotation. The worker accepts cookies sealed with either secret. |
Preview branches: Worker secrets are shared across all versions of the fluide worker (production and preview). Set API_KEY_COOKIE_SECRET once on the worker — preview deployments from PR branches will use the same secret. Use a dedicated preview secret only if you create a separate Wrangler environment/worker for previews.
Do not commit .dev.vars, .env.local, or real secret values to git.
| Method | Path | Purpose |
|---|---|---|
POST |
/api/session |
Store encrypted Gemini API key in HttpOnly cookie |
POST |
/api/revoke |
Clear the session cookie |
GET |
/api/session/status |
Check whether a valid session exists |
POST |
/api/grammar-check |
Proxy grammar check to Gemini |
POST |
/api/extract-phrases |
Proxy phrase extraction to Gemini |
- Frontend: Vite + React + TypeScript + Tailwind CSS
- BFF: Cloudflare Worker (
worker/) proxies grammar check and phrase extraction to Gemini - Auth: User-provided Gemini API keys are sealed with AES-256-GCM and stored in a
__Host-fluide_user_api_keyHttpOnly cookie