Files
mealie/.github/copilot-instructions.md
2025-12-05 13:00:45 -06:00

10 KiB

Mealie Development Guide for AI Agents

Project Overview

Mealie is a self-hosted recipe manager, meal planner, and shopping list application with a FastAPI backend (Python 3.12) and Nuxt 3 frontend (Vue 3 + TypeScript). It uses SQLAlchemy ORM with support for SQLite and PostgreSQL databases.

Development vs Production:

  • Development: Frontend (port 3000) and backend (port 9000) run as separate processes
  • Production: Frontend is statically generated and served via FastAPI's SPA module (mealie/routes/spa/) in a single container

Architecture & Key Patterns

Backend Architecture (mealie/)

Repository-Service-Controller Pattern:

  • Controllers (mealie/routes/**/controller_*.py): Inherit from BaseUserController or BaseAdminController, handle HTTP concerns, delegate to services
  • Services (mealie/services/): Business logic layer, inherit from BaseService, coordinate repos and external dependencies
  • Repositories (mealie/repos/): Data access layer using SQLAlchemy, accessed via AllRepositories factory
    • Get repos via dependency injection: repos: AllRepositories = Depends(get_repositories)
    • All repos scoped to group/household context automatically

Route Organization:

  • Routes in mealie/routes/ organized by domain (auth, recipe, groups, households, admin)
  • Use APIRouter with FastAPI dependency injection
  • Apply @router.get/post/put/delete decorators with Pydantic response models
  • Route controllers use HttpRepo mixin for common CRUD operations (see mealie/routes/_base/mixins.py)

Schemas & Type Generation:

  • Pydantic schemas in mealie/schema/ with strict separation: *In, *Out, *Create, *Update suffixes
  • Auto-exported from submodules via __init__.py files (generated by task dev:generate)
  • TypeScript types auto-generated from Pydantic schemas - never manually edit frontend/lib/api/types/

Database & Sessions:

  • Session management via Depends(generate_session) in FastAPI routes
  • Use session_context() context manager in services/scripts
  • SQLAlchemy models in mealie/db/models/, migrations in mealie/alembic/
  • Create migrations: task py:migrate -- "description"

Frontend Architecture (frontend/)

Component Organization (strict naming conventions):

  • Domain Components (components/Domain/): Feature-specific, prefix with domain (e.g., AdminDashboard)
  • Global Components (components/global/): Reusable primitives, prefix with Base (e.g., BaseButton)
  • Layout Components (components/Layout/): Layout-only, prefix with App if props or The if singleton
  • Page Components (components/ with page prefix): Last resort for breaking up complex pages

API Client Pattern:

  • API clients in frontend/lib/api/ extend BaseAPI, BaseCRUDAPI, or BaseCRUDAPIReadOnly
  • Types imported from auto-generated frontend/lib/api/types/ (DO NOT EDIT MANUALLY)
  • Composables in frontend/composables/ for shared state and API logic (e.g., use-mealie-auth.ts)
  • Use useAuthBackend() for authentication state, useMealieAuth() for user management

State Management:

  • Nuxt 3 composables for state (no Vuex)
  • Auth state via use-mealie-auth.ts composable
  • Prefer composables over global state stores

Essential Commands (via Task/Taskfile.yml)

Development workflow:

task setup              # Install all dependencies (Python + Node)
task dev:services       # Start Postgres & Mailpit containers
task py                 # Start FastAPI backend (port 9000)
task ui                 # Start Nuxt frontend (port 3000)
task docs               # Start MkDocs documentation server

Code generation (REQUIRED after schema changes):

task dev:generate       # Generate TypeScript types, schema exports, test helpers

Testing & Quality:

task py:test            # Run pytest (supports args: task py:test -- -k test_name)
task py:check           # Format + lint + type-check + test (full validation)
task py:format          # Ruff format
task py:lint            # Ruff check
task py:mypy            # Type checking
task ui:test            # Vitest frontend tests
task ui:check           # Frontend lint + test

Database:

task py:migrate -- "description"  # Generate Alembic migration
task py:postgres        # Run backend with PostgreSQL config

Docker:

task docker:prod        # Build and run production Docker compose

Critical Development Practices

Python Backend

  1. Always use uv for Python commands (not python or pip):

    uv run python mealie/app.py
    uv run pytest tests/
    
  2. Type hints are mandatory: Use mypy-compatible annotations, handle Optional types explicitly

  3. Dependency injection pattern:

    from fastapi import Depends
    from mealie.repos.all_repositories import get_repositories, AllRepositories
    
    def my_route(
        repos: AllRepositories = Depends(get_repositories),
        user: PrivateUser = Depends(get_current_user)
    ):
        recipe = repos.recipes.get_one(recipe_id)
    
  4. Settings & Configuration:

    • Get settings: settings = get_app_settings() (cached singleton)
    • Get directories: dirs = get_app_dirs()
    • Never instantiate AppSettings() directly
  5. Testing:

    • Fixtures in tests/fixtures/
    • Use api_client fixture for integration tests
    • Follow existing patterns in tests/integration_tests/ and tests/unit_tests/

Frontend

  1. Run code generation after backend schema changes: task dev:generate

  2. TypeScript strict mode: All code must pass type checking

  3. Component naming: Follow strict conventions (see Architecture section above)

  4. API calls pattern:

    const api = useUserApi();
    const recipe = await api.recipes.getOne(recipeId);
    
  5. Composables for shared logic: Prefer composables in composables/ over inline code duplication

  6. Translations: Only modify en-US locale files when adding new translation strings - other locales are managed via Crowdin and must never be modified (PRs modifying non-English locales will be rejected)

Cross-Cutting Concerns

  1. Code generation is source of truth: After Pydantic schema changes, run task dev:generate to update:

    • TypeScript types (frontend/lib/api/types/)
    • Schema exports (mealie/schema/*/__init__.py)
    • Test data paths and routes
  2. Multi-tenancy: All data scoped to groups and households:

    • Groups contain multiple households
    • Households contain recipes, meal plans, shopping lists
    • Repositories automatically filter by group/household context
  3. Pre-commit hooks: Install via task setup:py, enforces Ruff formatting/linting

  4. Testing before PRs: Run task py:check and task ui:check before submitting PRs

Pull Request Best Practices

Before Submitting a PR

  1. Draft PRs are optional: Create a draft PR early if you want feedback while working, or open directly as ready when complete
  2. Verify code generation: If you modified Pydantic schemas, ensure task dev:generate was run
  3. Follow Conventional Commits: Title your PR according to the conventional commits format (see PR template)
  4. Add release notes: Include user-facing changes in the PR description

What to Review

Architecture & Patterns:

  • Does the code follow the repository-service-controller pattern?
  • Are controllers delegating business logic to services?
  • Are services coordinating repositories, not accessing the database directly?
  • Is dependency injection used properly (Depends(get_repositories), Depends(get_current_user))?

Data Scoping:

  • Are repositories correctly scoped to group/household context?
  • Do route handlers properly validate group/household ownership before operations?
  • Are multi-tenant boundaries enforced (users can't access other groups' data)?

Type Safety:

  • Are type hints present on all functions and methods?
  • Are Pydantic schemas using correct suffixes (*In, *Out, *Create, *Update)?
  • For frontend, does TypeScript code pass strict type checking?

Generated Files:

  • Verify frontend/lib/api/types/ files weren't manually edited (they're auto-generated)
  • Check that mealie/schema/*/__init__.py exports match actual schema files (auto-generated)
  • If schemas changed, confirm generated files were updated via task dev:generate

Code Quality:

  • Is the code readable and well-organized?
  • Are complex operations documented with clear comments?
  • Do component names follow the strict naming conventions (Domain/Global/Layout/Page prefixes)?
  • Are composables used for shared frontend logic instead of duplication?

Translations:

  • Were only en-US locale files modified for new translation strings?
  • Verify no other locale files (managed by Crowdin) were touched

Database Changes:

  • Are Alembic migrations included for schema changes?
  • Are migrations tested against both SQLite and PostgreSQL?

Review Etiquette

  • Be constructive and specific in feedback
  • Suggest code examples when proposing changes
  • Focus on architecture and logic - formatting/linting is handled by CI
  • Use "Approve" when ready to merge, "Request Changes" for blocking issues, "Comment" for non-blocking suggestions

Common Gotchas

  • Don't manually edit generated files: frontend/lib/api/types/, schema __init__.py files
  • Repository context: Repos are group/household-scoped - passing wrong IDs causes 404s
  • Session handling: Don't create sessions manually, use dependency injection or session_context()
  • Schema changes require codegen: After changing Pydantic models, run task dev:generate
  • Translation files: Only modify en-US locale files - all other locales are managed by Crowdin
  • Dev containers: This project uses VS Code dev containers - leverage the pre-configured environment
  • Task commands: Use task commands instead of direct tool invocation for consistency

Key Files to Reference

  • Taskfile.yml - All development commands and workflows
  • mealie/routes/_base/base_controllers.py - Controller base classes and patterns
  • mealie/repos/repository_factory.py - Repository factory and available repos
  • frontend/lib/api/base/base-clients.ts - API client base classes
  • tests/conftest.py - Test fixtures and setup
  • dev/code-generation/main.py - Code generation entry point

Additional Resources