e4c77d6buffcleb/teufli
Cross-platform gathering & event platform — hosts create events, invite guests by email, collect RSVPs, and (for paid events) coordinate P2P payments. Web, mobile, and an admin console over one typed API.
Origin
Single-replicabehind Cloudflare Tunnel
Round-trip
—ms
Why “Teufli”?
An accidental cross-cultural pun — a French party word wearing a cozy Swiss-German sweater.
fête flipped → teuf: a casual party, bash, or hangout. Widely used by younger French speakers.
the Müesli / Schoggi ending — it makes a word little, cute, and cozy.
Teufli
a cozy little gathering — endearing for reunions & close-knit crews
The full-stack surface area
Six workspaces — api, web, mobile, admin, marketing, and a shared editor — over one typed API. Here's what powers each layer.
Frontend
React 18 + Vite 5
Web app · app.teufli.com
Tailwind CSS 3
Utility-first design system
TanStack Query 5
Server-state & caching
React Router 6
Client routing (web + admin)
Expo 56 · RN 0.85
iOS + Android app
Astro 5
Marketing site · teufli.com
@teufli/site-editor
TipTap 3 event-site editor
Backend
Express 4 + TS 5.6
Versioned /v1 REST API
Prisma 5
Type-safe data access
Zod 3
Runtime request validation
JWT HS256
Passwordless magic links
In-process schedulers
Reminders · email · SMS · audit
Admin API (:3001)
Separate token & secret
Data & Storage
PostgreSQL 16
Primary relational store
Prisma Migrate
Versioned schema history
Signed media disk
Sharded local · HMAC URLs
Redis (ioredis)
Optional rate-limit store
AppConfig
Server-side feature flags
Multer · Sharp
Upload + image processing
Cloudflare & Ops
Cloudflare edge
DNS · TLS · WAF · DDoS · cache
Cloudflare Tunnel
cloudflared · outbound-only
Workers static assets
web + marketing hosting
Podman + Portainer
Containers on one host
Turnstile
CAPTCHA on auth + RSVP
Cloudflare Access
Gates admin.teufli.com
Clients
Web · iOS · Android · Admin
Cloudflare edge
TLS · WAF · cache · Turnstile
Cloudflare Tunnel
cloudflared · outbound-only
Express API
/v1 · Zod · Prisma · single-replica
PostgreSQL 16
Prisma · migrations
Clients
Web · iOS · Android · Admin
Cloudflare edge
TLS · WAF · cache · Turnstile
Cloudflare Tunnel
cloudflared · outbound-only
Express API
/v1 · Zod · Prisma · single-replica
PostgreSQL 16
Prisma · migrations
Signed media is edge-cached by Cloudflare; the tunnel keeps the origin off the public internet with no inbound ports. Mutations carry a double-submit CSRF token and terminate at the single-replica API, which owns the in-process reminder, email, SMS, and audit-retention schedulers.
Interactive API explorer
Browse the real 73-endpoint /v1 surface, grouped by area. Inspect payloads and copy a ready-to-run cURL for any endpoint.
It's Teufli's passwordless magic-link flow. The Bearer token is a 24-hour HS256 session JWT — the same one the mobile app stores. (Web clients use an httpOnly cookie instead, so this is the mobile / script / CI path.)
- 1
Request a magic link for your account's email.
bashcurl -X POST "https://api.teufli.com/v1/auth/magic-link" \ -H "Content-Type: application/json" \ -d '{"email":"you@teufli.com"}' - 2
Open the emailed link, copy its ?token= value, and exchange it for the JWT.
bashcurl "https://api.teufli.com/v1/auth/verify?token=$MAGIC_TOKEN" # => { "token": "<JWT>", "user": { ... } } - 3
Export the returned token — now every Bearer example works.
bashexport TEUFLI_TOKEN="<JWT from the response>"
The magic token is one-time and expires in a few minutes — exchange it promptly; the JWT it returns lasts ~24h. In local dev the link isn't emailed, so read the token from the MagicToken table (or the API server logs) and run step 2.
Endpoints
73/v1/eventsBearer JWTCreate an event — standalone or recurring. Enforces per-hour/day creation limits and the account event cap. The platform fee is copied onto the event server-side.
curl -X POST "https://api.teufli.com/v1/events" \
-H "Authorization: Bearer $TEUFLI_TOKEN" \
-H "Content-Type: application/json" \
-d '{"title":"Bordeleau Family Reunion","description":"Annual get-together at the lake house.","location":"Lake House","startsAt":"2026-08-14T18:00:00.000Z","timezone":"America/New_York","visibility":"INVITE_ONLY","allowPlusOnes":true,"maxPlusOnes":4,"isPaid":true,"ticketPrice":20,"pricingMode":"PER_GUEST","paymentHandles":[{"type":"VENMO","handle":"@chris-b"}]}'{
"title": "Bordeleau Family Reunion",
"description": "Annual get-together at the lake house.",
"location": "Lake House",
"startsAt": "2026-08-14T18:00:00.000Z",
"timezone": "America/New_York",
"visibility": "INVITE_ONLY",
"allowPlusOnes": true,
"maxPlusOnes": 4,
"isPaid": true,
"ticketPrice": 20,
"pricingMode": "PER_GUEST",
"paymentHandles": [
{
"type": "VENMO",
"handle": "@chris-b"
}
]
}{
"id": "evt_9f2a3c",
"publicId": "a1B2c3D4",
"slug": "bordeleau-family-reunion",
"title": "Bordeleau Family Reunion",
"status": "DRAFT",
"startsAt": "2026-08-14T18:00:00.000Z",
"visibility": "INVITE_ONLY",
"isPaid": true,
"ticketPrice": "20.00",
"pricingMode": "PER_GUEST",
"platformFeePct": "0.0300",
"seriesId": null
}Deployment topology
Not a multi-region edge fleet — one hardened origin. Cloudflare terminates and protects at the edge, a tunnel reaches in, and Podman runs the containers on a single host.
Web SPA
app.teufli.com
Mobile
iOS · Android
Marketing
teufli.com
Admin
admin.teufli.com
Workers assets
web + marketing static
Cloudflare Tunnel
cloudflared · outbound-only
Single-replica — owns in-process schedulers
Admin API · own JWT secret
Admin console (nginx static)
PostgreSQL 16 · internal only
Rate-limit store (optional)
Outbound-only tunnel connector
Transactional email · invites, magic links
SMS reminders (opt-in)
Mobile notifications · exp.host
The main API is deliberately single-replica — it owns the in-process reminder, email, SMS, and audit-retention schedulers, so a second copy would double-fire them. Media is served signed and edge-cached; the admin console sits behind Cloudflare Access.
- teufli_api:3000checking
Main API · /v1 · signed /media
- teufli_admin_api:3001
Admin API · own JWT secret
- teufli_admin:80
Admin console (nginx static)
- teufli_postgres:5432
PostgreSQL 16 · internal only
- teufli_redis:6379
Rate-limit store (optional)
- cloudflaredtunnel
Outbound-only tunnel connector
The teufli_api dot reflects a real /health poll; the rest show their static role.
Hardened at the edge, tested in depth
A defense-in-depth posture from Cloudflare's edge down to the API, backed by an all-green integration suite. Core Web Vitals is a tracked, not-yet-measured item.
492
Integration tests
vitest + supertest, real Postgres
6
Workspaces
api · web · mobile · admin · marketing · shared
50+
Prisma models
Single versioned schema
serial
Test runner
Single-fork · 2 retries · 20s timeout
Lighthouse & Core Web Vitalsplanned
Not yet measured — tracked as a feature request (Lighthouse CI). See docs/DASHBOARD-FEATURE-REQUESTS.md.
Secrets
Host .envInjected via Podman compose. JWT HS256 + separate admin secret + HMAC media signing — never in a client bundle.
DDoS
CloudflareAutomatic L3/L4/L7 mitigation, always on at the edge in front of the tunnel.
WAF + Rate limiting
ManagedCloudflare managed ruleset + express-rate-limit (auth capped at 20 / 15 min / IP).
TLS / SSL
Full (strict)Cloudflare Full strict · min TLS 1.2 · HSTS enabled · auto-renewed certs.
CSRF defense
Double-submithttpOnly teufli_session cookie + X-CSRF-Token header echo on every cookie-auth mutation.
Auth
PasswordlessMagic-link → 24h HS256 JWT. Per-guest inviteToken for RSVP; Turnstile on auth + RSVP.
{ error: { code, message, details } }