ein freies Lehrmittel auf der Basis von eduskript

Code Style

Patterns and conventions used in the codebase.

TypeScript

  • Strict mode enabled
  • ES2023 target
  • Prefer interface over type for objects
  • Use explicit return types on exported functions
// Good
export function calculateTotal(items: Item[]): number {
  return items.reduce((sum, item) => sum + item.price, 0)
}

// Avoid
export const calculateTotal = (items) => {
  return items.reduce((sum, item) => sum + item.price, 0)
}

React Components

// Function components with explicit props
interface ButtonProps {
  label: string
  onClick: () => void
  disabled?: boolean
}

export function Button({ label, onClick, disabled = false }: ButtonProps) {
  return (
    <button onClick={onClick} disabled={disabled}>
      {label}
    </button>
  )
}

API Routes

// Pattern: early returns, flat structure
export async function POST(request: NextRequest) {
  const session = await getServerSession(authOptions)
  if (!session?.user?.id) {
    return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })
  }

  const body = await request.json()
  if (!body.title) {
    return NextResponse.json({ error: 'Title required' }, { status: 400 })
  }

  const result = await prisma.page.create({ data: { ... } })
  return NextResponse.json(result, { status: 201 })
}

Comments

Write comments that explain why, not what:

// Good: explains the why
// Skip permission check for published content - anyone can view
if (page.isPublished) {
  return page
}

// Bad: just restates the code
// Check if page is published
if (page.isPublished) {
  return page
}

Document known limitations:

// WORKAROUND: React Query doesn't invalidate automatically here.
// Manually trigger refetch after mutation.
queryClient.invalidateQueries(['pages'])

// Note: O(n²) for small lists. Consider Set for >100 items.
const unique = items.filter((item, i) => items.indexOf(item) === i)

File Organization

// One component per file
// Name file same as component
Button.tsx → export function Button()

// Colocate tests
Button.tsx
Button.test.tsx

// Group by feature, not type
components/
  dashboard/
    PageEditor.tsx
    PageEditor.test.tsx
  public/
    MarkdownRenderer.tsx

Imports

// External packages first
import { useState, useEffect } from 'react'
import { NextResponse } from 'next/server'

// Then internal imports with @/ alias
import { prisma } from '@/lib/prisma'
import { Button } from '@/components/ui/button'

// Then relative imports
import { helperFunction } from './utils'

Naming

ThingConventionExample
ComponentsPascalCasePageEditor
FunctionscamelCasecalculateTotal
ConstantsSCREAMING_SNAKEMAX_FILE_SIZE
Fileskebab-casepage-editor.tsx
Database fieldscamelCaseisPublished
URL slugskebab-casemy-collection

Don't

  • Don't add features beyond what's asked
  • Don't refactor unrelated code
  • Don't add comments to unchanged code
  • Don't create abstractions for one-time use