- MC registrations: notification toggles (confirm/remind) with urgency - Group bookings: save to DB from BookingModal, admin CRUD at /admin/bookings - Open Day: full event system with schedule grid (halls × time), per-class booking, discount pricing (30 BYN / 20 BYN from 3+), auto-cancel threshold - Unified SignupModal replaces 3 separate forms — consistent fields (name, phone, instagram, telegram), Instagram DM fallback on network error - Centralized /admin/bookings page with 3 tabs (classes, MC, Open Day), collapsible sections, notification toggles, filter chips - Unread booking badge on sidebar + dashboard widget with per-type breakdown - Pricing: contact hint (Instagram/Telegram/phone) on price & rental tabs, admin toggle to show/hide - DB migrations 5-7: group_bookings table, open_day tables, unified fields Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
165 lines
9.2 KiB
Markdown
165 lines
9.2 KiB
Markdown
# BLACK HEART DANCE HOUSE — Project Context
|
||
|
||
## About
|
||
Landing page for "BLACK HEART DANCE HOUSE" — a pole dance school in Minsk, Belarus.
|
||
Instagram: @blackheartdancehouse
|
||
Content language: Russian
|
||
|
||
## Tech Stack
|
||
- **Next.js 16** (App Router, TypeScript, Turbopack)
|
||
- **Tailwind CSS v4** (dark mode only, gold/black theme)
|
||
- **lucide-react** for icons
|
||
- **better-sqlite3** for SQLite database
|
||
- **Fonts**: Inter (body) + Oswald (headings) via `next/font`
|
||
- **Hosting**: Vercel (planned)
|
||
|
||
## Code Style
|
||
- Function declarations for components (not arrow functions)
|
||
- PascalCase for component files, camelCase for utils
|
||
- `@/` path alias for imports
|
||
- `next/image` with `unoptimized` for PNGs that need transparency preserved
|
||
- Header nav uses `lg:` breakpoint (1024px) for desktop/mobile switch (9 nav links + CTA need the space)
|
||
|
||
## Project Structure
|
||
```
|
||
src/
|
||
├── app/
|
||
│ ├── layout.tsx # Root layout, fonts, metadata
|
||
│ ├── page.tsx # Landing: Hero → [OpenDay] → About → Team → Classes → MasterClasses → Schedule → Pricing → News → FAQ → Contact
|
||
│ ├── globals.css # Tailwind imports
|
||
│ ├── styles/
|
||
│ │ ├── theme.css # Theme variables, semantic classes
|
||
│ │ └── animations.css # Keyframes, scroll reveal, modal animations
|
||
│ ├── admin/
|
||
│ │ ├── page.tsx # Dashboard with 13 section cards
|
||
│ │ ├── login/ # Password auth
|
||
│ │ ├── layout.tsx # Sidebar nav shell (14 items)
|
||
│ │ ├── _components/ # SectionEditor, FormField, ArrayEditor, NotifyToggle
|
||
│ │ ├── meta/ # SEO editor
|
||
│ │ ├── hero/ # Hero editor
|
||
│ │ ├── about/ # About editor
|
||
│ │ ├── team/ # Team list + [id] editor
|
||
│ │ ├── classes/ # Classes editor with icon picker
|
||
│ │ ├── master-classes/ # MC editor with registrations + notification toggles
|
||
│ │ ├── open-day/ # Open Day event editor (settings + grid + bookings)
|
||
│ │ ├── schedule/ # Schedule editor
|
||
│ │ ├── bookings/ # Group booking management with notification toggles
|
||
│ │ ├── pricing/ # Pricing editor
|
||
│ │ ├── faq/ # FAQ editor
|
||
│ │ ├── news/ # News editor
|
||
│ │ └── contact/ # Contact editor
|
||
│ └── api/
|
||
│ ├── auth/login/ # POST login
|
||
│ ├── logout/ # POST logout
|
||
│ ├── admin/
|
||
│ │ ├── sections/[key]/ # GET/PUT section data
|
||
│ │ ├── team/ # CRUD team members
|
||
│ │ ├── team/[id]/ # GET/PUT/DELETE single member
|
||
│ │ ├── team/reorder/ # PUT reorder
|
||
│ │ ├── upload/ # POST file upload (whitelisted folders)
|
||
│ │ ├── mc-registrations/ # CRUD registrations + notification toggle
|
||
│ │ ├── group-bookings/ # CRUD group bookings + notification toggle
|
||
│ │ ├── open-day/ # CRUD events
|
||
│ │ ├── open-day/classes/ # CRUD event classes
|
||
│ │ ├── open-day/bookings/ # CRUD event bookings + notification toggle
|
||
│ │ └── validate-instagram/ # GET check username
|
||
│ ├── master-class-register/ # POST public MC signup
|
||
│ ├── group-booking/ # POST public group booking
|
||
│ └── open-day-register/ # POST public Open Day booking
|
||
├── components/
|
||
│ ├── layout/
|
||
│ │ ├── Header.tsx # Sticky nav, mobile menu, booking modal ("use client")
|
||
│ │ └── Footer.tsx
|
||
│ ├── sections/
|
||
│ │ ├── Hero.tsx # Hero with animated logo, floating hearts
|
||
│ │ ├── About.tsx # About with stats (trainers, classes, locations)
|
||
│ │ ├── Team.tsx # Carousel + profile view
|
||
│ │ ├── Classes.tsx # Showcase layout with icon selector
|
||
│ │ ├── MasterClasses.tsx # Cards with signup modal
|
||
│ │ ├── OpenDay.tsx # Open Day schedule grid + booking (conditional)
|
||
│ │ ├── Schedule.tsx # Day/group views with filters
|
||
│ │ ├── Pricing.tsx # Tabs: prices, rental, rules
|
||
│ │ ├── News.tsx # Featured + compact articles
|
||
│ │ ├── FAQ.tsx # Accordion with show more
|
||
│ │ └── Contact.tsx # Info + Yandex Maps iframe
|
||
│ └── ui/
|
||
│ ├── Button.tsx
|
||
│ ├── SectionHeading.tsx
|
||
│ ├── BookingModal.tsx # Booking form → Instagram DM + DB save
|
||
│ ├── MasterClassSignupModal.tsx # MC registration form → API
|
||
│ ├── OpenDaySignupModal.tsx # Open Day class booking → API
|
||
│ ├── NewsModal.tsx # News detail popup
|
||
│ ├── Reveal.tsx # Intersection Observer scroll reveal
|
||
│ ├── BackToTop.tsx
|
||
│ └── ...
|
||
├── data/
|
||
│ └── content.ts # Fallback Russian text (DB takes priority)
|
||
├── lib/
|
||
│ ├── constants.ts # BRAND constants, NAV_LINKS
|
||
│ ├── config.ts # UI_CONFIG (thresholds, counts)
|
||
│ ├── db.ts # SQLite DB, 6 migrations, CRUD for all tables
|
||
│ ├── auth.ts # Token signing (Node.js)
|
||
│ ├── auth-edge.ts # Token verification (Edge/Web Crypto)
|
||
│ ├── content.ts # getContent() — DB with fallback
|
||
│ └── openDay.ts # getActiveOpenDay() — server-side Open Day loader
|
||
├── proxy.ts # Middleware: auth guard for /admin/*
|
||
└── types/
|
||
├── index.ts
|
||
├── content.ts # SiteContent, TeamMember, ClassItem, MasterClassItem, etc.
|
||
└── navigation.ts
|
||
```
|
||
|
||
## Brand / Styling
|
||
- **Accent**: gold (`#c9a96e` / `hsl(37, 42%, 61%)`)
|
||
- **Background**: `#050505` – `#0a0a0a` (dark only)
|
||
- **Surface**: `#171717` dark cards
|
||
- Logo: transparent PNG heart with gold glow, uses `unoptimized`
|
||
|
||
## Content Data
|
||
- Primary source: SQLite database (`db/blackheart.db`)
|
||
- Fallback: `src/data/content.ts` (auto-seeds DB on first access)
|
||
- Admin panel edits go to DB, site reads from DB via `getContent()`
|
||
- 12 team members with photos, Instagram links, bios, victories, education
|
||
- 6 class types (Exotic Pole Dance, Pole Dance, Body Plastic, etc.)
|
||
- Master classes with date/time slots and public registration
|
||
- 2 addresses in Minsk, Yandex Maps embed with markers
|
||
- Contact: phone, Instagram (no email)
|
||
|
||
## Admin Panel
|
||
- Password-based auth with HMAC-SHA256 signed JWT (24h TTL)
|
||
- Cookie: `bh-admin-token` (httpOnly, secure in prod)
|
||
- Auto-save with 800ms debounce on all section editors
|
||
- Team members: drag-reorder, photo upload, rich bio (experience, victories, education)
|
||
- Master classes: slots, registration viewer with notification tracking (confirm + reminder), trainer/style autocomplete
|
||
- Group bookings: saved to DB from BookingModal, admin page at `/admin/bookings` with notification toggles
|
||
- Open Day: event settings (date, pricing, discount rules, min bookings), schedule grid (halls × time slots), per-class booking with auto-cancel threshold, public section after Hero
|
||
- Shared `NotifyToggle` component (`src/app/admin/_components/NotifyToggle.tsx`) used across MC registrations, group bookings, and Open Day bookings
|
||
- File upload: whitelisted folders (`team`, `master-classes`, `news`, `classes`), max 5MB, image types only
|
||
|
||
## Security Notes
|
||
- **CSRF protection**: Double-submit cookie pattern. Login sets `bh-csrf-token` cookie (JS-readable). All admin fetch calls use `adminFetch()` from `src/lib/csrf.ts` which sends the token as `X-CSRF-Token` header. Middleware (`proxy.ts`) validates header matches cookie on POST/PUT/DELETE to `/api/admin/*`. **Always use `adminFetch()` instead of `fetch()` for admin API calls.**
|
||
- File upload validates: MIME type, file extension, whitelisted folder (no path traversal)
|
||
- API routes validate: input types, string lengths, numeric IDs
|
||
- Public MC registration: length-limited but **no rate limiting yet** (add before production)
|
||
|
||
## Upcoming Features
|
||
- **Rate limiting** on public endpoints (`/api/master-class-register`, `/api/group-booking`, `/api/open-day-register`)
|
||
- **DB backup mechanism** — automated/manual backup of `db/blackheart.db` with rotation
|
||
|
||
## AST Index
|
||
- **Always use the AST index** at `memory/ast-index.md` when searching for components, props, hooks, types, or styles
|
||
- Contains: component tree, all exports, props, hooks, client/server status, CSS classes, keyframes
|
||
- Update the index when adding/removing/renaming files or exports
|
||
|
||
## Database Migrations
|
||
- **Never drop/recreate the database** — admin data (photos, edits, registrations) lives there
|
||
- Schema changes go through versioned migrations in `src/lib/db.ts` (`migrations` array)
|
||
- Add a new entry with the next version number; never modify existing migrations
|
||
- Migrations run automatically on server start via `runMigrations()` and are tracked in the `_migrations` table
|
||
- Use `CREATE TABLE IF NOT EXISTS` and column-existence checks (`PRAGMA table_info`) for safety
|
||
|
||
## Git
|
||
- Remote: Gitea at `git.dolgolyov-family.by`
|
||
- User: diana.dolgolyova
|
||
- Branch: main
|