EWSTUDIOS / the platform
Five different AI products. One $7 server.
The shared work is deciding what the browser is allowed to ask for.
Heroku Basic only. Cloudflare Workers, Supabase and Gemini use free tiers. Five apps share the API.

- Role
- Product, design direction and engineering lead, built with Claude Code
- Timeline
- Shared platform · October 2026
- Stack
- Hono · TypeScript · Heroku · Supabase · Gemini
Heroku Basic only. Cloudflare Workers, Supabase and Gemini use free tiers. Five apps share the API.
The five featured products
Shared infrastructure.
Independent experiences.
02 / Pixe
A light table for creative direction.
Built around a board rather than another wall of search results.
03 / Translate+
Say it like you mean it.
Translate on the device first. Keep the words you care about, and the Hindi you actually speak.
04 / Willify
A vibe is only the beginning.
An AI DJ that has to prove the song exists before it reaches your playlist.
05 / Natour
A plan with its feet on the ground.
The AI writes the itinerary. OpenStreetMap checks the places. Unchecked stays visibly unchecked.
Three engineering decisions
The constraint shapes
the implementation.
Keep the trust boundary on the server
Constraint. A shared model key must not become a general chatbot
Decision. clients send typed, capped data to server-owned templates, with validation, identity and quota guards
Result. the quota increment and return happen in one atomic SQL statement, avoiding parallel calls slipping through. The region gate uses the last X-Forwarded-For entry because earlier entries can be forged.
Source and evidence limits
ew-apps-api/README.md, “Decisions worth explaining” → “Templates live on the server”, “The quota is one atomic SQL statement”, “The region block is on the server”. Referenced implementation: src/app.ts, src/apps/, supabase/migrations/. No claim that prompt injection is universally solved.
Read the pinned README ↗Stream within the host's deadline
Constraint. Heroku drops a silent request after 30s
Decision. begin streaming, send a blank-line keep-alive every 10 seconds while waiting, and abort the model at 25s
Result. clients receive partial output and an explicit upper bound, rather than waiting for a silent router failure. Keep-alives stop at the first model chunk so a translation's line breaks remain intact.
Source and evidence limits
ew-apps-api/README.md, “Streaming, with a 25s stop”, “Keep-alives stop at the first chunk”, “JSON Lines output”. These are configured behaviors, not latency percentiles.
Read the pinned README ↗Share infrastructure, keep app data local
Constraint. Five featured products need shared AI identity and budgets
Decision. static Workers frontends, shared Supabase identity/quota and one $7 Heroku dyno; a 6-digit email code is the fallback
Result. product data remains local while free-server AI has shared identity.
Source and evidence limits
ew-apps-api/README.md → “The idea”, “The IP limit is in memory”; taskpilot/README.md and pixe/README.md → “One sign-in for every EWSTUDIOS app”. The API README now documents workers.dev as a public suffix: ewstudios.workers.dev is the shared registrable passkey domain. Four apps offer passkeys; Natour uses email code only. Shared identity does not mean shared task, board or library storage.
Read the pinned README ↗Architecture
Follow one request.
Supabase supplies identity beside the guards and the atomic quota. Source-CDN media goes straight to the browser. Queues and caches remain in one process.
Passkey domain: ewstudios.workers.dev. Because workers.dev is a public suffix, its child is registrable and can be the shared RP ID. Supabase origin limits mean four apps offer passkeys; Natour uses the emailed 6-digit code only. API README, “One passkey for every app, because workers.dev is a public suffix” · aafe065 ↗
Quality proof / evidence, with scope
Show what was checked.
App evidence
README documents route tests with fake dependencies; npm test, npm run lint and npm run typecheck. No current run or test total is claimed.
Repository report, read 26 October 2026. These app scores were not rerun for this portfolio.
Commands and evidence in the README ↗This portfolio page
Static HTML, deferred decorative Stage, explicit media intent and complete reduced-motion content.
- performance
- 99/100
- accessibility
- 100/100
- best practices
- 100/100
- seo
- 100/100
Lighthouse mobile, light theme, cold cache, simulated throttling. Measured 2026-10-26. Gzip static export on localhost.
Eight page cases across Chromium/WebKit, phone/desktop and both themes; two axe audits with zero violations. WebKit playback and real Safari hardware remain unverified.
Read the dated portfolio check results ↗The honest next step
What remains.
The IP limiter is in memory. Move it to Postgres before scaling beyond one dyno.