// case study
My Place Cigar Lounge
Private members-only cigar lounge with a custom marketing site, member portal, and admin dashboard
- Year
- 2026
- Role
- Solo developer — public marketing site, authenticated member area, and full admin panel.
- Status
- Live
www.my-place-lounge.com

// in plain english
A private, members-only cigar lounge in Rochester needed more than a brochure website. I built a public site that shows what membership offers, a signed-in area where members see their dashboard, find other members and RSVP to events, and an admin screen where the owners manage members, events, invites and announcements. I built all three parts myself.
// about this project
What it does and how I built it
A members-only experience for Rochester's cigar enthusiasts. The public marketing site showcases 24/7 access, personal humidor storage, and events. The authenticated members area powers dashboards, cigar profiles, a member directory, and RSVPs. The admin panel lets ownership manage members, events, invites, and announcements.
My role: Solo developer — public marketing site, authenticated member area, and full admin panel.
Built under ROC Web Tech, the web studio I founded.
// decisions
One Next.js app for marketing + member portal + admin
Could have shipped a separate static marketing site and a separate authenticated app. Instead one codebase serves public marketing routes, the auth-gated member dashboard, and the owner admin panel — shared components, shared design tokens, one deploy pipeline. Saves the ongoing tax of cross-app drift; trade-off is slightly larger first-load JS on public pages.
Supabase + Auth.js instead of rolling auth
Members-only feature was the riskiest scope. Supabase + Auth.js give me battle-tested auth, RBAC, and a Postgres I can query in 5 minutes, instead of a 2-week detour into JWT and session management. The cost is a $25/month line item; the saved week paid for years of that subscription.
Three-tier RBAC (owner / admin / member) enforced server-side
Easy approach: client-side role checks. Correct approach: middleware that gates every API route and page on role, with the client UI as a UX hint only. Worth the extra hour up front because the alternative — finding out a member can hit an admin endpoint — is a production incident.
Test discipline: Vitest, Playwright, and row-level-security checks
Vitest covers RBAC role resolution and the auth middleware helpers. Playwright runs an E2E pass on the public marketing site plus an authenticated flow for the member dashboard and admin actions. A Supabase integration suite spawns service-role and anonymous clients and checks that anonymous reads and writes are refused where the policies say they must be. Every PR must pass lint, typecheck, build and Vitest; the Playwright end-to-end suite runs on every push to master.
// highlights
- Public marketing site with dark elegant theme — black, gold, serif typography
- Authenticated member area — dashboard, cigar profile, directory, messaging
- Full admin panel — members, events, RSVPs, invites, announcements
- Role-based access control with owner / admin / member tiers
// what I’d do differently
I built the member/owner role model iteratively, layering access rules on as features landed, and wrote the row-level-security tests after the policies existed. Today I would write the full access matrix — who can read and write what, per role — before the first database migration, with count-based policy tests from day one. Authorization is the one layer where "add it as you go" quietly accumulates risk.
Stack
- Next.js 16
- TypeScript
- Tailwind CSS 4
- Supabase (auth + Postgres)
- Stripe
- Sanity
- Vercel
AI Tools
- Claude Code
Built with AI as a force multiplier — scaffolding, research, automation, and code review all flow through these tools in my daily loop.
// gallery
Screenshots
Toggle between desktop and mobile views.
Desktop · 1440 × 900
// let’s build
Want this on your team?
I design, build, and ship production AI and web systems end-to-end — and I’m looking for a full-time AI engineering role to do it on a team.