Full-stack event management application with public registration and admin CRUD.
- Frontend: Vite + React + TypeScript + Tailwind CSS + React Router v6
- Backend: Node.js / Express (TypeScript via tsx)
- Database: SQLite (
better-sqlite3) by default — see Postgres notes below
# 1. Install dependencies
bun install # or: npm install
# 2. Copy env config (optional — defaults work out of the box)
cp .env.example .env
# 3. Start development (frontend :5173 + API :3001)
bun run dev # or: npm run devOpen http://localhost:5173 — public events listing. Admin dashboard at http://localhost:5173/admin.
| Script | Description |
|---|---|
dev |
Vite dev server + Express API (concurrently) |
build |
Bundle frontend to dist/ + type-check server |
start |
Production: Express serves dist/ + API on PORT (default 3001) |
SQLite file auto-created at ./data/events.db on first start. No setup required.
- Add
pgpackage:bun add pg @types/pg - Replace
server/db.ts— swapbetter-sqlite3forpg.Poolwith async queries - Update SQL syntax (
$1placeholders instead of?,gen_random_uuid()for IDs) - Set
DATABASE_URL=postgresql://user:pass@host:5432/dbnamein.env
| Method | Path | Description |
|---|---|---|
| GET | /api/events |
Published events (public) |
| GET | /api/events/all |
All events including drafts (admin) |
| GET | /api/events/:id |
Single event with registration count |
| POST | /api/events |
Create event |
| PUT | /api/events/:id |
Update event |
| DELETE | /api/events/:id |
Delete event |
| POST | /api/events/:id/registrations |
Register for event |
| GET | /api/events/:id/registrations |
List registrations for event |
- Admin event CRUD: title, description, date/time, capacity, status (draft/published/cancelled)
- Public event listing (published events only)
- Public registration form with name + email
- Overbooking prevention enforced at the database level
- Duplicate registration prevention (unique constraint on event_id + email)
- Registration confirmation displayed in-browser
- Admin registration list per event
- Validation, loading, empty, and error states throughout
- Responsive layout (mobile-friendly)