# 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:** ```bash 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):** ```bash task dev:generate # Generate TypeScript types, schema exports, test helpers ``` **Testing & Quality:** ```bash 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:** ```bash task py:migrate -- "description" # Generate Alembic migration task py:postgres # Run backend with PostgreSQL config ``` **Docker:** ```bash 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`): ```bash 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:** ```python 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:** ```typescript 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 - [Documentation](https://docs.mealie.io/) - [Contributors Guide](https://nightly.mealie.io/contributors/developers-guide/code-contributions/) - [Discord](https://discord.gg/QuStdQGSGK)