Food Recommendations
A no-login food and dish recommendation board, built and load-hardened like a real product.
Next.js · TypeScript · Prisma · PostgreSQL · Redis · Sentry
Results
- 30
- Playwright cases — happy path, admin, validation, a11y, SEO/errors
- Redis
- rate limiting that actually holds across serverless instances
- Daily
- scheduled CI run, independent of whether anything changed that day
Problem
A recommendation board only works if anyone can post without friction, but "no accounts" creates real problems the moment it's live: who can edit a post, what stops one person from spamming submissions or likes, and what happens when something breaks with no user account to trace it back to.
Approach
- Ownership without accounts: each submission gets a secret edit token at creation time, so the original poster's browser can edit or delete it later with no login — moderation (reports, an admin panel to review and dismiss them) covers the rest.
- Rate limiting on submissions, likes, comments, and reports via Upstash Redis. It replaced an in-memory limiter that only worked per warm serverless instance — on Vercel that was close to no protection at all, since the next request can land on a different instance with no shared memory.
- Sentry wired into both the server and edge runtimes, so a failure in either surfaces with a real stack trace instead of a silent 500 a user just bounces off.
- Postgres via Prisma, with a trigram-search migration for the browse/search page, and a 30-case Playwright suite (happy path, submission validation, admin auth and delete, filtering/pagination, accessibility, SEO/error pages) run in CI on every push and on a daily schedule.
From the code
// Redis-backed so limits actually hold across Vercel's ephemeral serverless
// instances — the previous in-memory Map only limited requests hitting the
// same warm instance, which on serverless is close to no protection at all.
export async function isRateLimited(key: string, limit: number, windowMs: number): Promise<boolean> {
const { success } = await getLimiter(limit, windowMs).limit(key);
return !success;
}Outcome
A live, publicly usable app that handles the unglamorous parts of "no login required" honestly — abuse prevention and ownership — instead of skipping them because there's no user table to hang them off of.
Business Impact
The same instinct I bring to test strategy — what actually needs to hold up under real, unauthenticated traffic — applied to building the thing, not just testing it.