Lightweight invoice template packed with essential functionality for TanStack, Cloudflare, and Effect
TanStack • Cloudflare • Effect • Better Auth • Stripe • Shadcn on Base UI
- TanStack: Start, Router, Query, Form
- Cloudflare: D1, DO, Agent, Workflow, Queue, KV, Cron, Rate Limiting, Web Analytics
- Effect: v4
- Better Auth: Magic Link, Admin, Organization, Stripe
- UI: Shadcn on Base UI
- Testing: Vitest, Cloudflare Vitest-Integration, Playwright
Invoices are a vehicle to exercise Cloudflare primitives, Effect v4, and fault-tolerant eventual consistency patterns under at-least-once delivery, partial failures, and crashes.
-
Cloudflare Services:
- D1 (SQLite) for Better Auth + app data with idempotent-write retry
- Durable Object Agents (
OrganizationAgent) per organization with DO-local SQLite,@callableRPC, and WebSocket broadcast - Workflows:
UserProvisioningWorkflow(Better Auth org/member reconciliation) andInvoiceExtractionWorkflow(AgentWorkflow: R2 load → LLM extract → DO save) - Queues for R2 event notifications and durable finalization safety nets
- R2 object storage with event notifications and retry on retryable codes (10001/10043/10054/10058)
- KV with exponential backoff + jitter
- Cron Trigger for expired-session cleanup
- Rate Limiting binding (IP-based) on magic-link endpoints
- Web Analytics
-
Fault-Tolerant Eventual Consistency:
- Idempotency-key dedupe in
onInvoiceUpload— three guards (staler2ActionTime, active workflow instance, terminal status) tolerate at-least-once R2 events - Schedule-first invoice delete —
this.schedule(0, ...)persists the R2 cleanup intent before the local row delete, so a crash converges on the next alarm tick (1s→30s, 3 retries) - Dual-path membership sync —
enqueue(FinalizeMembershipSync)before the Better Auth mutation (durable safety net) +stub.syncMembership()after (best-effort eager); both re-read D1 as authoritative UserProvisioningWorkflowreconciles all three states of Better Auth's non-transactional org creation (org + owner member are separate writes)- Workflow instance dedupe by idempotency key prevents double-extraction
- Idempotency-key dedupe in
-
Authentication & Organizations:
- Magic link authentication using Better Auth
- Multi-tenant organization management with automatic organization creation via workflow
- Role-based access control (user/admin/organization member roles)
- Organization invitations and membership management
- Agent WebSocket auth gated pre-upgrade (
onBeforeConnect) with per-RPC membership re-check
-
Payments & Subscriptions:
- Stripe integration with subscription processing
- Monthly and annual pricing plans with configurable trial periods
- Stripe Checkout and Customer Portal integration
- Webhook handling for subscription lifecycle events
- Subscription management (cancel, reactivate, billing portal access)
-
Effect v4 Architecture:
- Services via
ServiceMap.Servicewith explicitLayer.effectdefinitions - Traced functions with
Effect.fnfor observability - Type-safe error handling using
Schema.TaggedErrorClass - Layer composition via
Layer.mergefor dependency injection - Service dependencies resolved via
yield*for compile-time safety - Per-request
runEffectbuilt inworker.fetchand injected into TanStack Start'sServerContext; server functions pull it fromcontext: { runEffect }and execute Effect pipelines without importing@tanstack/react-start/server(which would drag Node builtins into the client build graph) - Separate runtime layer per execution surface — Worker
fetch,scheduled(Cron),queue,OrganizationAgentDO (DO-local SQLite via@effect/sql-sqlite-do), and each Workflow — so each entrypoint only materializes the services it needs runEffectusesrunPromiseExit+Cause.prettyto normalize failures intoErrorinstances with non-empty.message, preserving server context across TanStack'sShallowErrorPluginSSR dehydration, and re-throws TanStackredirect/notFounddefects so router control flow works from inside Effect pipelines
- Services via
-
Admin Panel:
- Admin interface for user management
- Session monitoring and administration
- Customer and subscription oversight
-
UI/UX Components:
- Shadcn with Base UI and TanStack Form integration
- Theme switching (light/dark/system) with persistence
-
Testing Infrastructure:
- Unit and integration tests using Vitest
- End-to-end testing with Playwright
-
Email Integration:
- Cloudflare transactional emails (coming)
- Demo mode support for development without external email services
-
Security & Performance:
- IP-based rate limiting for authentication endpoints
- Server-side route protection and authorization
- Secure session handling with database storage
- Install the Stripe CLI.
- Go to stripe and create a sandbox for testing named
tces-int- Remember secret key for
STRIPE_SECRET_KEYenvironment variable.
- Remember secret key for
- AI Gateway | Create Gateway
- Gateway ID: tces-ai-gateway-int
- Cache Responses: on
- Automatically purged cached requests after 1 Week
- Rate Limit Requests: only: on
- Limit requests when rate exceeds 25 requests over a 60 sliding period.
- Authenticated Gateway: on
- Create authentication token: tces-ai-gateway-token-int
- Remember for
AI_GATEWAY_TOKENenvironment variable.
- Workers AI | REST API | Create a Workers AI API Token: tces-workers-ai-api-token-int
- Remember for
WORKERS_AI_API_TOKENenvironment variable.
- Remember for
- aistudio.google.com | Get API Key | Create API key
- Remember for
GOOGLE_AI_STUDIO_API_KEYenvironment variable.
- Remember for
- Copy
.env.exampleto.env. - Edit the keys.
- Set
STRIPE_WEBHOOK_SECRETlater after you runpnpm stripe:listenbelow. - Edit account_id and CF_ACCOUNT_ID (local and production) in wrangler.jsonc
pnpm i
pnpm d1:reset
stripe login --project-name=tces-int
pnpm stripe:listen
# copy webhook signing secret to STRIPE_WEBHOOK_SECRET in .env
pnpm dev
# cron
curl "http://localhost:3000/cdn-cgi/handler/scheduled?cron=0%200%20*%20*%20*"
- Card Number:
4242 4242 4242 4242 - Expiration: Any future date
- CVC: Any 3-digit number
pnpm test
pnpm dev
pnpm stripe:listen
pnpm test:e2e
- Create stripe webhook
- Endpoint URL:
https://[DOMAIN]/api/auth/stripe/webhook - Events:
checkout.session.completed,customer.subscription.created,customer.subscription.updated,customer.subscription.deleted
- Endpoint URL:
- Cloudflare Web Analytics | Add a site
- Remember token from script for ANALYTICS_TOKEN secret below.
- pnpm exec wrangler queues create tces-q-production
- pnpm exec wrangler kv namespace create tces-kv-production
- Update wrangler.jsonc production kv_namespaces
- pnpm d1:reset:PRODUCTION
- pnpm deploy:PRODUCTION
- Storage & databases | R2 Object Storage | Overview | API Tokens Manage | Create User API token
- Token name: tces-r2-user-token-production
- Permissions: Object Read only
- Specify bucket(s) | Apply to specific buckets only: tces-r2-production
- Remember keys for R2_S3_ACCESS_KEY_ID and R2_S3_SECRET_ACCESS_KEY secrrets.
- pnpm exec wrangler r2 bucket notification create tces-r2-production --event-type object-create --queue tces-q-production
- AI Gateway | Create Gateway
- Gateway ID: tces-ai-gateway-production
- Cache Responses: on
- Automatically purged cached requests after 1 Week
- Rate Limit Requests: only: on
- Limit requests when rate exceeds 25 requests over a 60 sliding period.
- Authenticated Gateway: on
- Create authentication token: tces-ai-gateway-token-production
- Remember for
AI_GATEWAY_TOKENsecret.
- Workers AI | REST API | Create a Workers AI API Token: tces-workers-ai-api-token-production
- Remember for
WORKERS_AI_API_TOKENsecret.
- Remember for
- pnpm exec wrangler secret put SECRET --env production
- BETTER_AUTH_SECRET, STRIPE_SECRET_KEY, STRIPE_WEBHOOK_SECRET, ANALYTICS_TOKEN,R2_S3_ACCESS_KEY_ID, R2_S3_SECRET_ACCESS_KEY, AI_GATEWAY_TOKEN, WORKERS_AI_API_TOKEN GOOGLE_AI_STUDIO_API_KEY
- Workers & Pages Settings: tces
- Git repository: connect to git repo
- Build configuration
- Build command: CLOUDFLARE_ENV=production pnpm build
- Deploy command: pnpm exec wrangler deploy --env production
- Storage & databases: tces-d1-production: Settings
- Enable read replication
pnpm dlx shadcn@latest add --overwrite accordion alert-dialog alert aspect-ratio avatar badge breadcrumb button-group button calendar card carousel chart checkbox collapsible combobox command context-menu dialog drawer dropdown-menu empty field hover-card input-group input item label pagination popover progress radio-group scroll-area select separator sidebar sonner spinner switch tabs table textarea toggle tooltip
pnpm dlx shadcn@latest add https://ai-sdk.dev/elements/api/registry/all.jsonpnpm add -g @playwright/cli@latest
Homepage / Pricing design by dev-xo. See his remix-saas for a production-ready saas template for remix.
Licensed under the MIT License.