Files
blackheart-website/CLAUDE.md
diana.dolgolyova b94ee69033 feat: add booking management, Open Day, unified signup modal
- 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>
2026-03-19 12:58:04 +03:00

9.2 KiB
Raw Permalink Blame History

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