This file provides context for AI assistants working with the programmier.bar website codebase.
Do not automatically commit code changes, unless you were tasked with doing so. Do not automatically push code changes, unless you were tasked with doing so.
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: 24 for
nuxt-app— seenuxt-app/.nvmrc, which CI reads too. The Directus extension still builds on 22.
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 eslint # Lint with auto-fix
npm run prettier # Format codeThere is deliberately no static-generation script. See
the upgrade plan for why: a static build has to prerender every
<nuxt-img> variant, which is ~6200 downloads and resizes against the CMS, and it does not finish.
Nothing deployed used it — Vercel runs nuxt build and serves images through _vercel/image.
npm 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.
Significant, cross-cutting technical decisions are documented as ADRs in the
_ADRs/ folder (numbered Markdown files, e.g. 0001-...md). Each ADR captures
the context, the decision, its consequences, and any deferred follow-up. Before
changing build/test tooling, module setup, or other foundational concerns,
check _ADRs/ first — the rationale and known trade-offs are likely already
recorded there. Add a new ADR when you make a decision future contributors would
otherwise have to reverse-engineer.
Additional hints can be found in:
- _ADRs/ — architectural decision records (see above)
- .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
CI runs npm run prettier:check in nuxt-app, so unformatted code fails the build. Nobody should be
expected to remember the formatter — turn on format on save and it never comes up:
- WebStorm: Settings → Languages & Frameworks → JavaScript → Prettier → On save
- VS Code: the Prettier extension, plus
"editor.formatOnSave": true
Both read nuxt-app/.prettierrc on their own, and nuxt-app/.editorconfig covers indentation and line
endings before that is set up. Keep those two in step — they overlap, and an editor that indents to a
different width than Prettier produces a diff on every save. If a PR fails the check, npm run prettier
fixes it — never hand-edit to satisfy it.
Note that npm run lint (ESLint) needs nuxt prepare to have run first, since eslint.config.mjs
extends the generated .nuxt/eslint.config.mjs. npm ci does this via postinstall.
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)