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>
This commit is contained in:
109
CLAUDE.md
109
CLAUDE.md
@@ -7,8 +7,9 @@ Content language: Russian
|
||||
|
||||
## Tech Stack
|
||||
- **Next.js 16** (App Router, TypeScript, Turbopack)
|
||||
- **Tailwind CSS v4** (light + dark mode, class-based toggle)
|
||||
- **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)
|
||||
|
||||
@@ -16,66 +17,120 @@ Content language: Russian
|
||||
- Function declarations for components (not arrow functions)
|
||||
- PascalCase for component files, camelCase for utils
|
||||
- `@/` path alias for imports
|
||||
- Semantic CSS classes via `@apply`: `surface-base`, `surface-muted`, `heading-text`, `body-text`, `nav-link`, `card`, `contact-item`, `contact-icon`, `theme-border`
|
||||
- Only Header + ThemeToggle are client components (minimal JS shipped)
|
||||
- `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 → Team → About → Classes → Contact
|
||||
│ ├── 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
|
||||
│ ├── icon.png # Favicon
|
||||
│ └── apple-icon.png
|
||||
│ ├── 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, theme toggle ("use client")
|
||||
│ │ ├── Header.tsx # Sticky nav, mobile menu, booking modal ("use client")
|
||||
│ │ └── Footer.tsx
|
||||
│ ├── sections/
|
||||
│ │ ├── Hero.tsx
|
||||
│ │ ├── Team.tsx # "use client" — clickable cards + modal
|
||||
│ │ ├── About.tsx
|
||||
│ │ ├── Classes.tsx
|
||||
│ │ └── Contact.tsx
|
||||
│ │ ├── 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
|
||||
│ ├── SocialLinks.tsx
|
||||
│ ├── ThemeToggle.tsx
|
||||
│ ├── Reveal.tsx # Intersection Observer scroll reveal
|
||||
│ └── TeamMemberModal.tsx # "use client" — member popup
|
||||
│ ├── 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 # ALL Russian text, structured for future CMS
|
||||
│ └── content.ts # Fallback Russian text (DB takes priority)
|
||||
├── lib/
|
||||
│ └── constants.ts # BRAND constants, NAV_LINKS
|
||||
│ ├── 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, ContactInfo
|
||||
├── content.ts # SiteContent, TeamMember, ClassItem, MasterClassItem, etc.
|
||||
└── navigation.ts
|
||||
```
|
||||
|
||||
## Brand / Styling
|
||||
- **Accent**: rose/red (`#e11d48`)
|
||||
- **Dark mode**: bg `#0a0a0a`, surface `#171717`
|
||||
- **Light mode**: bg `#fafafa`, surface `#ffffff`
|
||||
- Logo: transparent PNG, uses `dark:invert` + `unoptimized`
|
||||
- **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
|
||||
- All text lives in `src/data/content.ts` (type-safe, one file to edit)
|
||||
- 13 team members with photos, Instagram links, and personal descriptions
|
||||
- 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
|
||||
- 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
|
||||
- Covers all 31 TS/TSX files + 4 CSS files
|
||||
- Update the index when adding/removing/renaming files or exports
|
||||
|
||||
## Database Migrations
|
||||
|
||||
Reference in New Issue
Block a user