Tech Stack
What I reach for, and why
A list of technologies says very little. What matters is why each one was chosen over the alternative, and what it cost.
Mobile client
- FlutterCross-platform app framework
- One codebase carrying two genuinely different products — the diner app and the owner app — behind a routing gate. The alternative was two native codebases for a team of one.
- ProviderState management
- Enough structure to keep state out of widgets without the ceremony of a heavier solution. For an app this size, more machinery would cost more than it returns.
API
- NestJSBackend framework
- Its module and provider system is why DealPlate's twenty-plus domains stayed navigable. Guards and parameter decorators let the auth boundary be declared rather than repeated.
- TypeScriptLanguage
- End to end — API, admin console and this site. With Prisma's generated types it means a schema change surfaces as a compile error rather than a runtime surprise.
- class-validatorRequest validation
- Applied as a global pipe with whitelist and transform, so unknown properties are stripped and params are typed before any handler runs.
Data
- PostgreSQLPrimary database
- Relational because the domain is relational — users, restaurants, promotions and coupons are nothing but relationships. Indexes on lat/long, zip and city make proximity a database concern.
- PrismaORM and migrations
- The migration workflow is the real value. Ten incremental migrations tell the story of how the product changed; a rewritten schema tells you nothing.
Identity
- Firebase AuthFederated identity
- Email/password and Google sign-in without owning credential storage. One identity across the mobile app and the admin console.
- JWT + PassportSelf-issued tokens
- The other approach, used in i-Bank — full control over token contents and lifetime, at the cost of owning the security surface yourself.
Web
- Next.js (App Router)Web framework
- Server Components keep content on the server and JavaScript off the client. Route groups let the admin console share a layout without sharing an auth posture.
- Tailwind CSSStyling
- Design tokens as CSS variables, consumed as utilities — which is what makes a single theme switch flip the whole site coherently.
- shadcn/uiComponent primitives
- Components copied into the repo rather than installed as a dependency. Accessible defaults that stay editable instead of fighting a library's opinions.
- MotionAnimation
- Scroll and transition animation that respects prefers-reduced-motion. Motion should confirm a change, not announce itself.
AI
- ClaudeStructured extraction
- Reads a photographed restaurant flyer into typed promotion fields against a fixed JSON schema. Constrained output, not free generation — and it fails closed when unconfigured.
- Groq / WhisperSpeech to text
- Called directly from the device on the user's own key, so audio never passes through infrastructure of mine.