Files
blackheart-website/CLAUDE.md
diana.dolgolyova 6cbdba2197 feat: add CSRF protection for admin API routes
Double-submit cookie pattern: login sets bh-csrf-token cookie,
proxy.ts validates X-CSRF-Token header on POST/PUT/DELETE to /api/admin/*.
New adminFetch() helper in src/lib/csrf.ts auto-includes the header.
All admin pages migrated from fetch() to adminFetch().

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-17 17:53:02 +03:00

147 lines
7.6 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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 → 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 11 section cards
│ │ ├── login/ # Password auth
│ │ ├── layout.tsx # Sidebar nav shell
│ │ ├── _components/ # SectionEditor, FormField, ArrayEditor
│ │ ├── 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
│ │ ├── schedule/ # Schedule editor
│ │ ├── 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
│ │ └── validate-instagram/ # GET check username
│ └── master-class-register/ # POST public signup
├── 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
│ │ ├── 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
│ ├── MasterClassSignupModal.tsx # MC registration form → 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, migrations, CRUD
│ ├── auth.ts # Token signing (Node.js)
│ ├── auth-edge.ts # Token verification (Edge/Web Crypto)
│ └── content.ts # getContent() — DB with fallback
├── 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, trainer/style autocomplete from existing data
- 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)
## 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