Inspiration
Independent restaurants are being priced out of professional operations software. OpenTable charges $300–700/month plus per-cover fees. Yelp Guest Manager is $300+/month. For a 40-seat restaurant in Lagos, Nairobi, Houston, or Manila, these tools are simply unaffordable. The result: 12 million independent restaurants worldwide manage waitlists on paper, WhatsApp, or nothing at all.
I built TableTurn to change that.
What it does
TableTurn is a full-stack restaurant waitlist and table management system that gives independent restaurants a professional operations tool at $29/month.
For customers: Scan a QR code at the restaurant entrance, join the waitlist in seconds from your phone, see your live position in the queue, and get notified when your table is ready — no app download required.
For hosts: Open the dashboard on a tablet, see the live queue updating in real time, click a party name, select an available table sized for their party, and seat them in one click.
For restaurant owners: See all tables, manage multiple parties simultaneously, free tables when guests leave, and never worry about double bookings again.
The core technical innovation
The most critical requirement for any table management system is this: two hosts must never be able to seat two different parties at the same table simultaneously.
Most systems handle this in application code — checking if a table is available before updating it. This approach has a race condition: two requests arriving at the same millisecond can both pass the availability check before either has updated the table status.
TableTurn solves this at the database level using Amazon Aurora DSQL's serializable distributed transactions:
await sql.begin(async (tx) => {
// Check table availability inside the transaction
const table = await tx`
SELECT id, status FROM tables
WHERE id = ${table_id}
FOR UPDATE
`;
if (table[0].status !== "available") {
throw new Error("Table just taken by another host");
}
// Atomically seat the party and mark table occupied
await tx`UPDATE tables SET status = 'occupied' WHERE id = ${table_id}`;
await tx`UPDATE parties SET status = 'seated', table_id = ${table_id} WHERE id = ${id}`;
});
Aurora DSQL's serializable isolation level guarantees that these operations are ordered — one transaction completes before the other begins. The no-double-booking guarantee is mathematically enforced at the database level, not just practically unlikely at the application level.
Why Aurora DSQL specifically
I chose Aurora DSQL over standard Aurora PostgreSQL and DynamoDB for three reasons:
Serializable distributed consistency — Aurora DSQL provides serializable transaction isolation across distributed writes. DynamoDB's eventual consistency model cannot make the same guarantee for concurrent seating operations.
Serverless scaling — TableTurn's write patterns are bursty (many parties joining simultaneously at peak hours). Aurora DSQL scales automatically without capacity planning.
SQL expressiveness — The compliance reporting and queue analytics require complex JOIN queries and aggregations that DynamoDB cannot express efficiently.
How I built it
Week 1: Provisioned Aurora DSQL cluster, designed the schema with four tables (restaurants, tables, parties, reservations), implemented the seating transaction with serializable isolation.
Week 2: Built the host dashboard with live queue updates every 5 seconds, customer join page with position tracking, and all API routes.
Week 3: Landing page, QR code generation, architecture diagram, Vercel deployment with environment variables secured.
Week 4: Demo video, blog posts, Devpost submission.
Tech stack
- Frontend: Next.js 16 (App Router) deployed on Vercel
- Database: Amazon Aurora DSQL — us-east-1
- Language: TypeScript
- DB connector: Postgres.js with AWS IAM auth via DsqlSigner
- QR codes: node-qrcode
- Styling: Inline styles with system-ui font
Challenges
Aurora DSQL does not support foreign keys. I used TEXT type for IDs instead of UUID to avoid edge cases, and enforced referential integrity at the application layer.
Aurora DSQL requires CREATE INDEX ASYNC. Standard CREATE INDEX statements fail — indexes must be created asynchronously with a job ID returned.
IAM token expiry. Aurora DSQL IAM auth tokens expire every 15 minutes. I implemented token refresh logic in the database connection layer to handle this gracefully in production.
What I learned
Aurora DSQL's distributed serializable consistency is genuinely different from what most databases offer. Building TableTurn gave me a deep understanding of why serializable isolation matters for concurrent write workloads — and why choosing the right database primitive eliminates entire categories of application bugs.
What's next
- SMS notifications via Twilio when table is ready
- Reservation booking flow
- Multi-location analytics dashboard
- Mobile app for hosts
- White-label branding for restaurant groups
Built With
- amazon-aurora-dsql
- next.js
- node.js
- postgres.js
- qrcode
- typescript
- vercel
Log in or sign up for Devpost to join the conversation.