GitHub - pouta-cms/form · GitHub
/" data-turbo-transient="true" />
Skip to content
Search or jump to...
Search code, repositories, users, issues, pull requests...
-->
Search
Clear
Search syntax tips
Provide feedback
--><br>We read every piece of feedback, and take your input very seriously.
Include my email address so I can be contacted
Cancel
Submit feedback
Saved searches
Use saved searches to filter your results more quickly
-->
Name
Query
To see all available qualifiers, see our documentation.
Cancel
Create saved search
Sign in
/;ref_cta:Sign up;ref_loc:header logged out"}"<br>Sign up
Appearance settings
Resetting focus
You signed in with another tab or window. Reload to refresh your session.<br>You signed out in another tab or window. Reload to refresh your session.<br>You switched accounts on another tab or window. Reload to refresh your session.
Dismiss alert
{{ message }}
pouta-cms
form
Public
Notifications<br>You must be signed in to change notification settings
Fork
Star
main
BranchesTags
Go to file
CodeOpen more actions menu
Folders and files<br>NameNameLast commit message<br>Last commit date<br>Latest commit
History<br>8 Commits<br>8 Commits
src
src
.gitignore
.gitignore
ARCHITECTURE.md
ARCHITECTURE.md
README.md
README.md
package-lock.json
package-lock.json
package.json
package.json
schema.sql
schema.sql
tsconfig.json
tsconfig.json
vitest.config.ts
vitest.config.ts
worker-configuration.d.ts
worker-configuration.d.ts
wrangler.json
wrangler.json
View all files
Repository files navigation
Pouta Forms
A dynamic, high-performance, open-source Typeform alternative running entirely on the Cloudflare Edge network. Built with pure Cloudflare Workers (ES modules syntax), KV, D1, and the Workers Analytics Engine.
Features
Dynamic Form Schemas : Fetched instantly from Cloudflare KV (FORM_SCHEMAS) on public GET requests with zero cold starts.
Single-Table Submission Upserts : Partial saves (checkpoints) and completed submissions reside in the exact same D1 SQL table (submissions), indexed on (form_id, status) to preserve query performance.
Submission Locking : Completed submissions are locked and cannot be overwritten or altered.
High-Volume Telemetry : Tracks form views (viewed) and initial engagements (started) via non-blocking, fire-and-forget Workers Analytics Engine data points.
Google OAuth Login : Secure admin auth flow issuing stateless, cryptographically signed JWT sessions via Web Crypto APIs (stored as HTTP-only cookies).
Spam Protection : Optional, configuration-backed verification hooks against Cloudflare Turnstile endpoints.
Getting Started
1. Installation
Install dependencies:
npm install
2. Database Migrations
Initialize the local D1 database schema:
npx wrangler d1 execute DB --local --file=schema.sql
3. Generate TypeScript Bindings
Generate TypeScript types for all KV, D1, and Analytics bindings:
npx wrangler types
4. Running Locally
Create a .dev.vars file in the root directory with the following variables:
GOOGLE_CLIENT_ID="your-google-client-id"<br>GOOGLE_CLIENT_SECRET="your-google-client-secret"<br>JWT_SECRET="your-jwt-signing-secret"<br>ALLOWED_ADMIN_EMAILS="admin@example.com,another@example.com"<br># Optional Turnstile site verification secret<br>TURNSTILE_SECRET_KEY="your-turnstile-secret-key"
Start the local Wrangler development server:
npm run dev
Google OAuth Client Configuration
To enable admin authentication, you must configure a Google OAuth 2.0 Client:
Go to the Google Cloud Console Credentials Page.
Create or select your Google Cloud project.
Click Create Credentials and select OAuth client ID .
Set the Application type to Web application .
Configure the OAuth origins and redirect URIs:
Authorized JavaScript origins :
http://localhost:8787 (for local development)
https://your-worker-name.your-subdomain.workers.dev (for production)
Authorized redirect URIs :
http://localhost:8787/admin/oauth/callback (for local development)
https://your-worker-name.your-subdomain.workers.dev/admin/oauth/callback (for production)
Click Create to obtain your Client ID and Client Secret.
Configure these secrets in your environments:
Locally : Place them in your .dev.vars file.
Production : Set them as encrypted secrets on Cloudflare using Wrangler:<br>npx wrangler secret put GOOGLE_CLIENT_ID<br>npx wrangler secret put GOOGLE_CLIENT_SECRET<br>npx wrangler secret put JWT_SECRET<br># For live Analytics Engine statistics:<br>npx wrangler secret put CLOUDFLARE_ACCOUNT_ID<br>npx wrangler secret put CLOUDFLARE_API_TOKEN
Note<br>To transition from mocked analytics to live analytics in the admin dashboard, you must define CLOUDFLARE_ACCOUNT_ID (your Cloudflare account identifier) and CLOUDFLARE_API_TOKEN (an API token with Account Analytics: Read permission) in your production secrets. Without these, the dashboard falls back to mocked view counts.
Directory Layout
src/index.ts: Application router, OAuth flow, telemetry, Turnstile validation, and D1 upsert...