Skip to content

Latest commit

 

History

History
432 lines (316 loc) · 16.7 KB

File metadata and controls

432 lines (316 loc) · 16.7 KB

CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

Project Overview

MUNify DELEGATOR is a SvelteKit-based application for managing Model United Nations conference registration, delegation assignment, and organizational matters. Built with Svelte 5, TypeScript, Prisma ORM, and GraphQL (via Pothos & Yoga), it's designed for DMUN e.V. but can be adapted for other MUN conferences.

Tech Stack Core

  • Frontend: SvelteKit with Svelte 5 (runes mode), TailwindCSS 4, DaisyUI
  • Backend: Node.js with SvelteKit server routes
  • Database: PostgreSQL via Prisma ORM
  • GraphQL: Pothos schema builder with graphql-yoga server, Houdini client
  • Auth: OpenID Connect (OIDC) - recommended provider: Logto
  • i18n: Paraglide-JS for internationalization (default locale: German)
  • Runtime: Bun (package manager and development runtime)
  • Observability: OpenTelemetry tracing support

Development Commands

Setup & Running

# Install dependencies
bun install

# Start development (Docker + dev server)
bun run dev

# Separate commands
bun run dev:docker    # Start Docker containers (PostgreSQL, etc.)
bun run dev:server    # Start Vite dev server only

# Install git hooks (lefthook)
bunx lefthook install

Database Operations

# Generate Prisma client
bunx prisma generate

# Create and apply migrations
bunx prisma migrate dev

# Reset database (WARNING: deletes all data)
bunx prisma migrate reset

# Seed database with development data
bun prisma/seed/dev/seed.ts

# Open Prisma Studio (database GUI)
bun run studio

Code Quality

# Format code
bun run format

# Type checking (PREFERRED for development - fast feedback)
bun run check          # Single run - use this to verify changes
bun run check:watch    # Watch mode
bun run typecheck      # TypeScript only

# Lint (slow - runs automatically on git push via lefthook)
bun run lint           # Only run manually when specifically needed

# Testing
bun test               # Run tests once
bun run test:watch     # Watch mode
bun run coverage       # With coverage report

Note: Prefer bun run check over bun run lint during development. Linting is slow (~2 min) and runs automatically on push via lefthook pre-push hooks. Use bun run check for quick type-checking feedback.

i18n (Internationalization)

# Check for missing/unused translations
bun run i18n:check

# Validate translation project
bun run i18n:validate

# Auto-translate missing keys
bun run i18n:translate

# Add new translation key interactively
bun run add-translation

Building

# Production build
bun run build

# Preview production build
bun run preview

Architecture

Directory Structure

  • src/routes/ - SvelteKit routes (filesystem-based routing)

    • (authenticated)/ - Protected routes requiring authentication
      • dashboard/ - Conference dashboards
      • management/ - Admin interfaces for conference/delegation management
      • registration/ - User registration flows
      • assignment-assistant/ - Delegation assignment tools
    • api/graphql/ - GraphQL API endpoint
    • auth/ - OIDC authentication callbacks
    • seats/, vc/, validateCertificate/ - Public-facing pages
  • src/api/ - Backend GraphQL API layer

    • resolvers/ - GraphQL resolvers organized by module
      • modules/ - Domain-specific resolvers (conference, delegation, committee, etc.)
      • api.ts - Main GraphQL Yoga server configuration
      • builder.ts - Pothos schema builder setup with plugins
    • abilities/ - CASL-based authorization rules per entity
    • services/ - Backend business logic services
  • src/lib/ - Shared frontend code

    • components/ - Reusable Svelte components
    • queries/ - Houdini GraphQL queries/mutations
    • services/ - Frontend utility functions
    • schemata/ - Zod validation schemas
    • paraglide/ - Generated i18n code
  • src/config/ - Environment configuration

    • public.ts - Client-side config (PUBLIC_* env vars)
    • private.ts - Server-side config (secrets, DB URLs)
  • src/tasks/ - Background scheduled tasks (node-schedule)

    • conferenceStatus.ts - Auto-update conference states
    • mailSync.ts - Email synchronization with external systems
  • prisma/ - Database layer

    • schema.prisma - Prisma schema definition
    • migrations/ - Database migration history
    • seed/ - Database seeding scripts
    • pothos/ - Generated Pothos types from Prisma

Key Architectural Patterns

1. GraphQL API Layer (Pothos + Yoga)

  • Schema-first approach using Pothos code-first schema builder
  • All resolvers in src/api/resolvers/modules/ are auto-imported in api.ts
  • Plugin stack: Prisma integration, complexity limiting, OpenTelemetry tracing, utilities
  • Authorization: CASL ability checks per entity type in src/api/abilities/entities/
  • Context includes: Prisma client, OIDC user info, request metadata

2. Frontend Data Fetching (Houdini)

  • Houdini manages GraphQL client-side operations

  • Type-safe generated queries in .houdini/ directory

  • Queries/mutations in src/lib/queries/ trigger codegen

  • Config in houdini.config.js - runes mode enabled

  • Cache Invalidation: After mutations that modify data, you must invalidate Houdini's cache to update the UI:

    import { cache } from '$houdini';
    import { invalidateAll } from '$app/navigation';
    
    // After a mutation:
    cache.markStale();
    await invalidateAll();

3. Authentication & Authorization

  • OIDC flow via openid-client library
  • Login callbacks in src/routes/auth/
  • User context injected into GraphQL context via src/api/context/
  • CASL abilities define fine-grained permissions per entity:
    • Actions: list, read, update, delete, impersonate
    • Each entity type has dedicated ability definitions
  • Team member roles: Admin, PROJECT_MANAGEMENT, PARTICIPANT_CARE, etc.

4. Internationalization

  • Paraglide-JS with url and baseLocale strategy
  • Source translations in messages/ directory
  • Use $t() function in components for translated strings
  • Generate translations via Inlang CLI
  • German gender-inclusive language: Use gender-neutral forms when possible (e.g., "Teilnehmende" instead of "Teilnehmer"). When neutral forms aren't available, use the gender-asterisk format (e.g., "der/die Teilnehmer*in", "Delegationsleiter*in").

5. Database Patterns

  • Prisma ORM with PostgreSQL
  • Models: Conference, Delegation, Committee, DelegationMember, SingleParticipant, etc.
  • Conference state machine: PREPARTICIPANT_REGISTRATIONPREPARATIONACTIVEPOST
  • Payment tracking via PaymentTransaction model
  • Paper submission system with versioning and reviews

6. Background Tasks

  • node-schedule for cron jobs
  • Tasks registered in src/tasks/index.ts
  • Conference state auto-transitions, email list synchronization
  • Task output written to tasksOut/ directory (configured in build)

Path Aliases (svelte.config.js)

$api → src/api
$assets → src/assets
$db → prisma
$config → src/config
$houdini → .houdini

Important Integrations

  • PDF Generation: pdf-lib with custom fonts for certificates
  • Barcode/QR: @bwip-js/browser, @svelte-put/qr, barcode-detector
  • Rich Text Editor: TipTap for committee agenda items
  • Maps: Leaflet via sveaflet for delegation locations
  • External APIs: Listmonk email service integration in src/tasks/apis/

UI Component Patterns

See CLAUDE-UI.md for comprehensive UI design documentation including:

  • Form components and FormFieldset grouping patterns
  • Modal and Drawer usage
  • Dashboard section layouts
  • DataTable configuration
  • Navigation components (Tabs, NavMenu)
  • Status indicators and badges
  • Color theming and icons
  • Code examples for common patterns

Quick reference:

  • Forms: Always wrap related inputs with FormFieldset for visual grouping
  • Modals: Use Modal component with action snippet for footer buttons
  • Layout: Use DaisyUI classes; prefer bg-base-* and semantic colors
  • Icons: Use FontAwesome Duotone (fa-duotone fa-icon-name)
  • URL State: Use sveltekit-search-params for URL-persisted state

Maintenance: When creating new UI components, significantly modifying existing ones (props, usage patterns), or deprecating components, update CLAUDE-UI.md accordingly. Keep documentation in sync with the actual component implementations.

Commit Conventions

Follow Conventional Commits:

  • feat: - New feature
  • fix: - Bug fix
  • style: - UI/styling changes
  • refactor: - Code restructuring without behavior change
  • perf: - Performance improvements
  • docs: - Documentation updates
  • test: - Test updates
  • chore: - Maintenance tasks
  • build: - Build system changes
  • ci: - CI/CD changes

Format: <type> (<scope>): <description> (e.g., feat (Frontend): implement login modal)

Testing Strategy

  • Vitest with jsdom environment
  • Test files: src/tests/ directory
  • Coverage provider: v8
  • Run tests before pushing (enforced by lefthook pre-push hook)

Environment Variables

Required variables (see .env.example):

  • DATABASE_URL - PostgreSQL connection string
  • SECRET - Session encryption secret
  • NODE_ENV - Environment (development/production/test)
  • PUBLIC_OIDC_AUTHORITY - OIDC provider URL
  • PUBLIC_OIDC_CLIENT_ID - OAuth client ID
  • OIDC_SCOPES - OAuth scopes (must include openid)
  • OIDC_ROLE_CLAIM - JWT claim for roles
  • CERTIFICATE_SECRET - Secret for signing participation certificates
  • OpenTelemetry vars (optional): OTEL_ENDPOINT_URL, OTEL_SERVICE_NAME

Common Workflows

Adding a New GraphQL Resolver

  1. Create resolver module in src/api/resolvers/modules/
  2. Import in src/api/resolvers/api.ts
  3. Define CASL abilities in src/api/abilities/entities/ if new entity
  4. Restart dev server to regenerate schema

Adding a Frontend Feature

  1. Create/modify components in src/lib/components/
  2. Add GraphQL queries in src/lib/queries/
  3. Houdini auto-generates types on save
  4. Use generated stores in Svelte components
  5. Add translations to messages/ directory

Database Schema Changes

  1. Edit prisma/schema.prisma
  2. Run bunx prisma migrate dev --name <descriptive-name>
  3. Prisma auto-generates client and Pothos types
  4. Update seed scripts if needed
  5. Test migrations against seed data

Adding Background Task

  1. Create task file in src/tasks/
  2. Use node-schedule to define cron schedule
  3. Import task in src/tasks/index.ts
  4. Ensure task output directory exists

Git Hooks (Lefthook)

Pre-commit: Auto-format staged files with Prettier Pre-push: Run tests and lint staged files

Performance Notes

  • Svelte 5 runes mode enabled - use $state, $derived, $effect instead of legacy stores
  • Houdini query deduplication and caching
  • GraphQL query complexity limiting via Pothos plugin
  • OpenTelemetry tracing for performance monitoring
  • Image optimization: Use WebP format, lazy load images
  • Install dependencies always into the devDependencies section as is best practice for sveltekit projects if not explicitly required at runtime.

Security Considerations

  • OIDC authentication required for all routes in (authenticated)/
  • CASL authorization checks on all GraphQL mutations
  • Certificate signatures use HMAC-SHA256
  • Environment secrets must never be committed
  • Prisma parameterized queries prevent SQL injection
  • GraphQL complexity limits prevent DoS attacks

Type Safety (CRITICAL)

This codebase supports 100% end-to-end type safety from database to frontend. The type system is your primary defense against bugs—use it properly.

Rules

  1. NEVER use any - The any type defeats the purpose of TypeScript. Only use it when absolutely unavoidable (e.g., third-party library limitations), and always add a comment explaining why.

  2. NEVER use type casting (as Type) - Type assertions bypass the compiler's checks. If you feel the need to cast, it indicates a type definition problem that should be fixed at the source.

  3. Trust the generated types - Prisma, Pothos, and Houdini generate accurate types. If types don't match your expectations, investigate why rather than casting.

  4. Fix type errors at the source - When encountering type mismatches:

    • Check if the GraphQL query/mutation needs updating
    • Verify the Prisma schema is correct
    • Ensure Houdini codegen has run (bun run dev triggers this)
    • Never silence errors with as any or @ts-ignore
  5. Use type narrowing - Prefer type guards, discriminated unions, and proper null checks over assertions.

Why This Matters

  • Prisma generates types from schema.prisma
  • Pothos generates GraphQL schema types from Prisma
  • Houdini generates frontend types from GraphQL operations
  • This chain provides compile-time guarantees that data flows correctly through the entire stack

Exceptions (Rare)

If any or casting is truly unavoidable, you MUST:

  1. Add a // TYPE-SAFETY-EXCEPTION: comment explaining why
  2. Keep the scope as narrow as possible
  3. Consider opening an issue to fix it properly later

MCP Servers

This project uses Model Context Protocol (MCP) servers to enhance AI-assisted development. Configuration is in .mcp.json.

Configured Servers

Server Package/URL Purpose
svelte @sveltejs/mcp Official Svelte 5 documentation, code validation and fixes
daisyui-github gitmcp.io/saadeghi/daisyui DaisyUI component library documentation
tailwind-github gitmcp.io/tailwindlabs/tailwindcss TailwindCSS documentation
github @anthropic-ai/github-mcp-server GitHub PRs, issues, code search, workflow management
prisma prisma mcp Database migrations, schema introspection, Prisma Studio
vitest @djankies/vitest-mcp Test running with structured output, coverage analysis
context7 @upstash/context7-mcp Up-to-date documentation for any library
memory @modelcontextprotocol/server-memory Persistent knowledge graph across sessions
sequential-thinking @modelcontextprotocol/server-sequential-thinking Complex problem-solving through structured thinking
houdini-github gitmcp.io/HoudiniGraphql/houdini Houdini GraphQL client documentation
pothos-github gitmcp.io/hayes/pothos Pothos GraphQL schema builder documentation

Setup Requirements

GitHub MCP Server: Requires a GitHub Personal Access Token. Replace <YOUR_TOKEN> in .mcp.json with your token, or set the GITHUB_PERSONAL_ACCESS_TOKEN environment variable.

Context7: Optionally get a free API key at context7.com/dashboard for higher rate limits.

Usage Tips

  • Use use context7 in prompts to fetch current documentation for any library
  • The Svelte MCP server validates Svelte 5 code and suggests fixes
  • Prisma MCP can run migrations and open Prisma Studio directly
  • Vitest MCP provides structured test output optimized for AI analysis
  • Memory MCP remembers context across conversation sessions

Development Workflow

  • Never use the git commit command after a task is finished.

PR Labels

When creating pull requests, always apply the appropriate PR: * label based on the conventional commit type in the PR title:

Commit prefix Label
feat (new functionality) PR: Feature
feat (improve existing) PR: Enhancement
fix PR: Bug
perf PR: Performance
refactor, style PR: Refactor
docs documentation
ci, build, chore PR: Infrastructure
deps, dependencies dependencies
test PR: Tests

Every PR must have at least one of these labels before merging. This powers the auto-generated release notes.