A simple, anonymous wishlist web application where owners can create wishlists and share them with guests. Guests can reserve items anonymously without creating an account.
- ✅ Create wishlist with unique admin and guest links
- ✅ Edit wishlist title and description
- ✅ Add, edit, and delete items
- ✅ View reservation status (see which items are reserved)
- ✅ Unreserve any item (override guest reservations)
- ✅ Copy guest link to share with others
- ✅ View wishlist items
- ✅ Reserve multiple items anonymously
- ✅ Cancel own reservations
- ✅ See reservation status:
- "You reserved this" for items they reserved
- "Reserved" for items reserved by others
- ✅ Dark mode support (system preference detection)
- ✅ Toast notifications for all actions
- ✅ Responsive design
- ✅ Security headers configured
- ✅ Comprehensive test coverage (57 unit tests + 18 E2E tests)
- Next.js - React framework with App Router
- React 19 - UI library
- TypeScript - Type safety
- TailwindCSS - Styling
- ShadCN/UI - Component library
- next-themes - Dark mode support
- react-hook-form - Form management
- Zod - Schema validation
- Sonner - Toast notifications
- Supabase - PostgreSQL database and backend
- Server Actions - Next.js server-side mutations
- Server Components - Next.js server-side data fetching
- Vitest - Unit testing
- Playwright - E2E testing
- Node.js 20+
- npm or yarn
- Supabase account (free tier works)
This project includes:
- Unit tests for business logic (Server Actions)
- Playwright E2E tests for critical user flows:
- Admin creates a wishlist
- Guest reserves an item
- Guest cancels their own reservation
- Testing prioritizes access control boundaries between admin and guest actions and correctness of reservation logic
Out of scope:
- Visual regression tests
- Load testing (MVP scale)
git clone <https://github.com/osanto/my-wishlist.git>
cd wishlistnpm install- Create a new project at supabase.com
- Go to SQL Editor and run the schema from
docs/schema.sql - Get your project URL and service role key from Settings → API
Create a .env.local file in the root directory:
SUPABASE_URL=your_supabase_project_url
SUPABASE_SERVICE_ROLE_KEY=your_service_role_keynpm run devOpen http://localhost:3000 in your browser.
npm run dev- Start development servernpm run build- Build for productionnpm run start- Start production servernpm run lint- Run ESLintnpm run format- Format code with Prettiernpm run format:check- Check code formattingnpm test- Run unit tests (Vitest)npm run test:ui- Run unit tests with UInpm run test:e2e- Run E2E tests (Playwright)
wishlist/
├── app/ # Next.js App Router
│ ├── actions/ # Server Actions
│ ├── admin/ # Admin pages
│ ├── guest/ # Guest pages
│ └── page.tsx # Homepage
├── components/ # React components
│ ├── ui/ # ShadCN UI components
│ └── ... # Feature components
├── lib/ # Utilities and helpers
│ ├── supabase.ts # Supabase client
│ ├── tokens.ts # Token generation
│ ├── token-storage.ts # localStorage utilities
│ └── wishlist.ts # Wishlist helpers
├── tests/ # Test files
│ ├── actions/ # Unit tests
│ └── e2e/ # E2E tests
└── docs/ # Documentation
├── PRD.md # Product requirements
├── Tech-Overview.md # Technical overview
└── schema.sql # Database schema
Run unit tests with Vitest:
npm testOr with UI:
npm run test:uiRun E2E tests with Playwright:
npm run test:e2eNote: E2E tests require the dev server to be running. Playwright will start it automatically.
- All Supabase calls happen server-side only
- Service role key never exposed to browser
- Tokens validated before every mutation
- Security headers configured (X-Frame-Options, HSTS, CSP, etc.)
- No personal data collected
- Anonymous reservations
- Wishlist Creation: User clicks "Create Wishlist" → System generates unique admin and guest tokens → Redirects to admin page
- Token Storage: Admin/guest tokens stored in URL (for routing) and localStorage (for persistence)
- Reservations: Guests get a unique reservation token stored in localStorage → Used to track which items they reserved
- Access Control: All mutations validate tokens server-side before executing
MIT License



