This file provides context for AI assistants working with the programmier.bar website codebase.
A podcast/conference/meetup platform for the German developer community. Built with Nuxt 3 (Vue 3) frontend and Directus 11 headless CMS.
- Frontend: Nuxt 3, Vue 3, TypeScript, Tailwind CSS, Pinia
- CMS: Directus 11 (headless CMS)
- Server: Nitro (Nuxt's server engine)
- Search: Algolia
- AI: Google Gemini (spam filtering)
- Node: v19+ (v22 in CI)
website/
├── nuxt-app/ # Main Nuxt 3 frontend
│ ├── components/ # 77 Vue components
│ ├── composables/ # 24 Vue composables
│ ├── helpers/ # Utility functions
│ ├── types/ # TypeScript definitions
│ ├── pages/ # File-based routing
│ ├── server/ # Nitro API routes
│ └── config.ts # Feature flags & constants
├── directus-cms/ # Directus CMS instance
│ └── extensions/ # Custom Directus extensions
└── shared-code/ # Shared TypeScript code
npm run dev # Development server
npm run build # Production build
npm run generate # Static site generation
npm run eslint # Lint with auto-fix
npm run prettier # Format codenpm run start # Start Directus server
npm run build # Build extensions
npm run migrate:db # Database migrations# In directus-cms/extensions/directus-extension-programmierbar-bundle/
npm test # Run Jest tests- Never duplicate logic across modules. If a pattern (API access, LLM calls, template handling, schema definitions) is used in more than one place, extract it into a shared abstraction with a clear, generic name.
- Tokens, API keys, and credentials should be managed in one place — not scattered across features.
- Types and schemas belong in established, canonical locations. Don't create new files when existing ones cover the same domain.
No Hidden Behavior
- No fallback values for critical configuration. Fail explicitly if config is missing — silent fallbacks cause data loss or broken state in production.
- No hardcoded defaults buried in business logic (prompts, URLs, feature flags). If it affects behavior, it must be visible and configurable.
- Treat missing or empty data as a failure worth surfacing, not a reason to silently exit.
- If a failure requires human intervention, notify through the team's established channel (e.g. Slack). Log-only visibility is insufficient for anything that blocks a workflow.
- Prefer loud failures over silent degradation.
Additional hints can be found in:
- .claude/rules/directus-conventions.md
- .claude/rules/nuxt-conventions.md
- Prettier: 120 char width, 4 spaces, no semicolons, trailing commas
- ESLint: Nuxt recommended config with TypeScript
- Imports: Auto-sorted, use
typekeyword for type-only imports - Components: PascalCase, single-word names allowed
Directus types follow a preparation pattern:
DirectusPodcastItem- Raw CMS type with ID referencesPodcastItem- Prepared type with hydrated relationships
Main composables in nuxt-app/composables/:
useDirectus()- CMS data fetching (most important, 884 lines)usePodcastPlayer()- Podcast playback stateuseProfileCreationStore()- User profile state
Feature flags and constants in nuxt-app/config.ts:
FLAG_SHOW_LOGIN- Toggle login UIDEVTOOLS- Enable Nuxt DevTools- Event tracking IDs (80+ constants)
Email endpoint at /api/email (POST):
- Zod schema validation
- Gemini AI spam filtering
- Honeypot protection
Key variables (see .env.example if exists):
DIRECTUS_CMS_URL- Directus instance URLWEBSITE_URL- Public website URLNUXT_ENV- 'development' or 'production'ALGOLIA_INDEX- Search index name
Main Directus collections:
- Podcasts (deep_dive, cto_special, news, other)
- Meetups & Conferences
- Speakers (Hall of Fame)
- Pick of the Day
nuxt-app/nuxt.config.ts- Nuxt configurationnuxt-app/config.ts- App constants & feature flagsnuxt-app/composables/useDirectus.ts- CMS integrationnuxt-app/tailwind.config.js- Tailwind customizationsnuxt-app/types/directus.ts- CMS type definitions
Custom colors: black, white, blue, lime, pink, gray Breakpoints: xs(520), sm(640), md(768), lg(1024), xl(1280), 2xl(1536), 3xl(2000)