4.3 KiB
4.3 KiB
CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
Overview
Mangarr is a Symfony 7.0 manga management/reader application. It scrapes manga chapters from various sources, stores them as CBZ files, and provides a reader interface. It runs on FrankenPHP inside Docker.
Common Commands
All commands run via Docker through the Makefile. Use make help to see all available targets.
make start # Start Docker containers
make stop # Stop containers
make install # Build images, start containers, install deps (first-time setup)
make logs # Follow container logs
make sh # Shell into the PHP container
PHP / Symfony:
make sf c="about" # Run any Symfony console command
make cc # Clear cache
make vendor # Install Composer dependencies
make migration-migrate # Run pending migrations
make fixtures-load # Load fixtures (drops and recreates data)
Testing:
make test # Run all tests
make test f="ScrapeChapterHandlerTest" # Run a specific test by class name
make test c="--group e2e" # Pass phpunit options
Code Quality:
make phpcs # Fix code style (PSR-12 via php-cs-fixer)
make phpmd # Run PHP Mess Detector
make quality # Run both phpmd and phpcs
make phparkitect # Check architectural rules
Frontend:
make npm-run # Build assets once (dev)
make npm-watch # Watch and rebuild assets
make npm-add p=pkg # Add an npm dependency
Messenger workers (run in separate terminals):
make consume-commands # Process command.bus messages
make consume-events # Process domain events
make consume-schedule # Process scheduled tasks
Architecture
The project uses Domain-Driven Design with strict layer separation enforced by PHPArkitect (phparkitect.php).
Domain Structure
src/Domain/
{DomainName}/
Domain/ # Pure domain: Models, Contracts (interfaces), Events, Exceptions
Application/ # Use cases: Commands, Queries, CommandHandlers, QueryHandlers, Responses
Infrastructure/ # Framework: Persistence, API Platform State, Clients, Services
Shared/ # Cross-domain contracts and infrastructure (MangaPathManagerInterface, EventDispatcherInterface, etc.)
Business domains: Manga, Reader, Scraping, Conversion, Setting (+ Shared)
Architectural rules enforced:
Domainlayer has no outside dependencies (only std exceptions)Applicationlayer may depend on its own Domain +App\Domain\Shared\Domain\Contract+Symfony\Messenger+Ramsey\Uuid; never on InfrastructureShareddepends on nothing outside itself
Outside Domain (src/)
src/Entity/— Doctrine ORM entities (legacy, used by repositories)src/Controller/— Symfony HTTP controllerssrc/ApiResource/— API Platform resource definitions +OpenApiFactoryDecoratorsrc/Service/— Legacy services (being migrated into Domain)src/Message/+src/MessageHandler/— Legacy Messenger messages (outside DDD)
Frontend
assets/controllers/— Stimulus controllers (one per UI interaction)assets/vue/app/— Vue.js SPA mounted at/vue/*- Tailwind CSS via PostCSS, bundled with Webpack Encore
- Mercure for real-time updates (queue status, download progress)
Key Infrastructure
- Database: PostgreSQL 16 via Doctrine ORM; Adminer on port 8080
- Scraping:
scrapers.jsondefines per-site CSS selectors;HtmlScraperandJavascriptScraper(Panther) strategies - File storage: CBZ files stored at
MANGA_DATA_PATH(default~/Mangas); images atIMAGE_DATA_PATH - External API: MangaDex client for metadata (
MANGADEX_CLIENT_ID/SECRET/USERNAME/PASSWORDenv vars) - Messenger buses:
command.bus(sync commands),eventstransport,commandstransport,asynctransport (scheduler)
Adding a New Domain Feature
- Define contracts (interfaces) in
Domain/{Name}/Domain/Contract/ - Write Command/Query + Handler in
Domain/{Name}/Application/ - Implement interfaces in
Domain/{Name}/Infrastructure/ - Register infrastructure aliases in
config/services.yaml - Run
make phparkitectto validate layer boundaries