This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
pnpm install # Install dependencies
pnpm prepare # Setup git hooks (husky + lint-staged)
cp .env.example .env # Copy environment variablespnpm dev # Start Next.js development server with Turbopack (default)
pnpm dev:webpack # Start with webpack instead of Turbopackpnpm build # Production build with Turbopack (default)
pnpm build:webpack # Production build with webpack
pnpm start # Start production serverpnpm lint # Run ESLint
pnpm lint:fix # Fix ESLint issues automatically
pnpm prettier # Format all files with Prettier
pnpm typegen # Generate Next.js typed routes and run TypeScript compilerpnpm test # Run Vitest tests once
pnpm test:watch # Run Vitest in watch modepnpm tolgee:pull # Pull translations from Tolgee
pnpm tolgee:push # Push translations to Tolgee
pnpm tolgee:sync # Sync translations bidirectionally- Next.js 15 (App Router) with Turbopack
- React 19 with React Compiler RC
- TypeScript with strict configuration
- Tailwind CSS for styling
- Tolgee for i18n (English & Polish)
- Vitest for testing
- Zod for runtime validation
src/
├── app/ # Next.js App Router pages
│ ├── (pages)/ # Route group for main pages
│ ├── (cities)/ # Route group for city-specific pages
│ ├── layout.tsx # Root layout with Tolgee provider
│ └── page.tsx # Homepage
├── components/ # React components
│ ├── Navigation/ # Navigation components
│ └── ui/ # shadcn/ui components
├── content/ # Content configuration files
│ ├── cities.tsx # City definitions and map positions
│ ├── events-discounts.ts # Conference/event discount data
│ ├── software-discounts.ts # Software tool discount data
│ ├── learning-discounts.ts # Learning platform discount data
│ ├── communityParticipation.ts # Community surveys/initiatives
│ ├── additionalEvents.ts # Static event data
│ └── partners.tsx # Partner/sponsor data
├── tolgee/ # Tolgee i18n configuration
│ ├── shared.ts # Base Tolgee config
│ ├── server.tsx # Server-side instance
│ ├── client.tsx # Client-side provider
│ └── language.ts # Language management
├── types/ # TypeScript type definitions
├── utils/ # Utility functions
├── hooks/ # Custom React hooks
└── env.ts # Environment variable validation (T3 Env)
messages/
├── en.json # English translations
└── pl.json # Polish translations
- Route Groups:
(pages)and(cities)group routes without affecting URLs - Server Components by default: Most components are Server Components for better performance
- Client Components: Marked with
'use client'directive (e.g., interactive forms, animations) - Typed Routes: Enabled via
typedRoutes: truein next.config.ts
- Server Components: Use
await getTranslate()from@/tolgee/server - Client Components: Use
useTranslate()hook from@tolgee/react - Translation keys: Organized by section (e.g.,
navigation.home,hero.title) - Static data fallback: Translation files in
messages/for development without API key - In-context editing: Hold Alt + click on text to edit translations
All promotional content, discounts, and community initiatives are configured via TypeScript files in src/content/:
- Discount banners automatically hide after expiry date
- Type-safe with Zod schemas
- Support for gradients, icons, and metadata
- Events fetched from external API (configured via
EVENTS_API_URL) - Validated with Zod schema (
EventsSchema) - Cached for 1 hour (
revalidate: 3600) - Merged with static additional events
- Rendered in
EventCardcomponents
- Validated using
@t3-oss/env-nextjsinsrc/env.ts - Runtime validation with Zod schemas
- Server-only variables:
EVENTS_API_URL,SITE_URL,DISCORD_SERVER_ID - Public variables:
NEXT_PUBLIC_TOLGEE_API_KEY,NEXT_PUBLIC_TOLGEE_API_URL
- Tailwind CSS with custom configuration
- shadcn/ui components in
src/components/ui/ - Utility function
cn()for conditional class merging (clsx+tailwind-merge) - Safelist for dynamic gradient classes (see
tailwind.config.ts)
- Husky runs lint-staged on commit
- Prettier formats staged files automatically
- Configured in
.lintstagedrc
- Lifecycle scripts disabled in
.npmrc preinstall-always-failpackage prevents accidental script execution- Socket.dev warnings enabled on PRs
- Enabled in "annotation" mode (
reactCompiler.compilationMode: 'annotation') - Only compiles functions/components with
"use memo"or"use forget"directives
- Minimum: Node 22+, npm 10.8+, pnpm 9.4+
- Managed via
.tool-versions(asdf) and.nvmrc
Edit the appropriate content file and add an object to the exported array:
src/content/events-discounts.ts- Conferences/eventssrc/content/software-discounts.ts- Software toolssrc/content/learning-discounts.ts- Learning platforms
Required fields: id, message, cta, ticketLink, expiresAt
Optional: gradient, icon, emojiRight, discountCode
Edit src/content/communityParticipation.ts and add to COMMUNITY_PARTICIPATION array.
Set status: 'active' and featured: true to display on homepage.
Promo materials (copy + graphics) live in docs/social-media/<campaign-name>/.
See docs/social-media/cyberfolks-meetjs/ as the reference implementation.
To generate graphics, write a Node script using @vercel/og (satori) bundled with Next.js —
do NOT hand-position elements in raw SVG:
const { ImageResponse } = await import(
'next/dist/compiled/@vercel/og/index.node.js'
);Key conventions:
- Layout: flexbox via satori element trees (plain objects
{ type, props: { style, children } }, no JSX needed) - Fonts: Montserrat (brand font, weights 500/800) + JetBrains Mono for discount codes; fetch from Google Fonts and cache in
.fonts/(gitignored) - Brand colors: purple
#2b1932, green#bcd25f, blue#239eab, card#241329 - Brand style: reuse the "ticket" motif from
src/app/(pages)/discounts/opengraph-image.tsx(rotated card, gradient border, dashed perforation, code pill). Avoid fake cut-out notches — satori has no masking, they clash with gradient backgrounds - Formats: LinkedIn/Facebook 1200×630, IG feed 1080×1080, IG story 1080×1920 (keep content within ~250px top / 280px bottom safe zone)
- Assets: inline images as base64 data URIs (satori fetches remote
<img>at render time) - Run:
node docs/social-media/<campaign>/generate-graphics.mjs, output PNGs tographics/
Edit src/content/cities.tsx:
- Add city object to
CITIESarray with map coordinates - Create corresponding route folder in
src/app/(cities)/city-name/ - Set status:
'active','paused','coming-soon', or'new'
- Always add translation keys to both
messages/en.jsonandmessages/pl.json - Use descriptive, namespaced keys (e.g.,
hero.title, not justtitle) - Server components:
const t = await getTranslate(); t('key') - Client components:
const { t } = useTranslate(); t('key')
- Tests use Vitest with React Testing Library
- Configuration in
vitest.config.ts - Setup file:
src/setupTests.tsfor jest-dom matchers - Path alias
@/resolves tosrc/
When using external images, add the domain to next.config.ts under images.remotePatterns.