Noosa
Next.js, Tech lead•2025 — present
Noosa is a bilingual event ticketing platform, so the site has to stay fast and open to anonymous visitors while taking payments and resisting bots — and a team of five had to keep shipping on top of it.
The web app was built end to end around a backend-for-frontend gateway that owns security, caching and auth, so features move quickly on a safe base.

Open to everyone, closed to bots.
Noosa started from a blank repository. Events had to be browsable by anyone without an account, checkout had to take real payments, and the whole product had to work in English and Indonesian — down to the error messages the backend returns. Session tokens and the backend secret could never reach browser JavaScript.
Organisers needed more than a form: multiple ticket types, custom registration questions, a gallery and a map per event. Sign-in and other key flows were already drawing automated traffic.
And the team was five people — two product, one designer, one backend developer and a tech lead — shipping two to four features a month. Every security rule had to stay in sync as routes changed, without a second copy of each path waiting to drift.


One gateway, one route table.
- ABackend-for-frontend gateway
The browser never calls the backend directly. A single Next.js route runs every request through rate limiting, captcha scoring, secret injection, a timeout, public caching, forced logout on 401, server-side error translation and redacted logging. Tokens stay in httpOnly cookies. The cost is one extra hop per call; the alternative was spreading those checks across services and hoping they agreed.
- BOne typed route table drives every policy
Each backend route is declared once. The same definitions build request URLs and feed the rate-limit tiers, captcha routes, cache allowlist and log redaction, and API types are generated from the backend's OpenAPI spec. Renaming a route is a one-line change, and every policy follows it.
- CRate limits keyed by user, not IP
Four Redis tiers, from 5 to 60 requests a minute. Signed-in users are keyed by a hash of their token, so people sharing one office or NAT address don't lock each other out. If Redis is down the limiter fails open and logs loudly — availability over strict enforcement, as a deliberate choice.
- DCheckout state lives in the URL
Multi-ticket, multi-attendee registration is held in the query string, so a checkout is shareable and survives a refresh without a client store. Hand-edited URLs are clamped to the same purchase limits the interface enforces.
- EHover prefetch and server hydration
Event cards prefetch on hover rather than on sight, and route layouts load data on the server and hydrate TanStack Query — so going from a list to an event opens with no loading state. Prefetching every visible card would have meant a server render per card.


The parts nobody notices until they break.
- Event builder. Cross-field validation — price only for paid tickets, capacity never below existing registrations — with backend errors mapped onto the exact field. Questions and their options drag-reorder at two nested levels, and the flow works from the keyboard.
- Type-safe translations. Every translation key is checked at compile time, around 1,300 lines per locale. A typo fails the build instead of showing a raw key to a customer.
- A lean rich-text editor. Stored content round-trips exactly, links are limited to http and https, and read-only views render without loading the editor at all.
- Hardened Google sign-in. A single-use state cookie and an open-redirect guard.
- Hosting migration. Moved from AWS EC2 with Docker Compose and Caddy to Vercel for the web app and Google Cloud Run for the backend.

Shipping monthly, on a base that holds.
Noosa now serves over 17,000 users, with more than 24,000 tickets sold across 800+ events. reCAPTCHA Enterprise has turned away around 2,000 malicious bot requests before they reached the backend.
The team ships two to four features a month, each one validated with questionnaires, user interviews and mockups before it is built. Because security and caching live in one gateway and one route table, new features inherit them without extra work. Adoption data steers the roadmap too: Sign in with Google is used by roughly 9% of users, which set the next priority for authentication.
- Year2025 — present
- IndustryEvent ticketing
- RoleTech lead · team of 5
- Scope of work/ Frontend / Platform / Infrastructure / CI/CD
- StackNext.js · TypeScript · TanStack Query · Tailwind CSS · Redis · reCAPTCHA · next-intl · Zod