# AGENTS.md

Multi-tenant admin application built on MintyPHP. Manages tenants, users, departments, roles, permissions, address books, mail, CSV imports, scheduled jobs, and Microsoft Entra ID SSO.

## Tech Stack

- **Runtime:** PHP 8.5 (FPM) on MintyPHP framework (`mintyphp/core`)
- **Web server:** Nginx 1.25 (Alpine)
- **Database:** MariaDB 11.4
- **Cache:** Memcached 1.6
- **Frontend:** Vanilla JS (ES2022 modules), vanilla CSS with `@layer` system — no build step
- **Key PHP libs:** PHPMailer 7, Dompdf 3, endroid/qr-code 6, league/commonmark 2
- **Containerized:** Docker Compose (dev + prod variants)

## Quick Commands

```bash
# Start dev environment
docker compose up --build -d
# App: http://localhost:8080 | phpMyAdmin: http://localhost:8081

# Run PHPUnit tests (phpunit.xml configures bootstrap + testsuite)
docker compose exec php vendor/bin/phpunit

# Run PHPStan (level 5)
docker compose exec php vendor/bin/phpstan analyse -c phpstan.neon --no-progress

# Check unused Composer packages
docker compose exec php vendor/bin/composer-unused
```

## Project Structure

```
lib/                    # All backend PHP (namespace MintyPHP\)
  App/                  # DI container + bootstrap (AppContainer, Container/Registrars/)
  Repository/           # SQL queries, prepared statements, filters/paging
  Service/              # Business logic, validation, orchestration
  Http/                 # Auth guards, API auth, request helpers
    Input/              # Request input handling (RequestInput, FormErrors)
  Support/              # Crypto, flash, guard, search, helpers
pages/                  # Actions (controllers) — file-based routing
  pages/**/*.php        # Action files (read input, check permissions, call services)
  pages/**/*.phtml      # View files (rendering only, no DB calls)
templates/              # Layouts and partials
  partials/             # Reusable UI components
  emails/               # Email HTML templates
  pdfs/                 # PDF templates (Dompdf)
config/                 # App config (routes, assets, settings cache, themes)
web/                    # Document root (entry point, CSS, JS, static assets)
  js/core/              # DOM utilities, Grid.js factory
  js/components/        # Reusable UI components
  css/                  # Layered CSS (base → components → layout → pages)
storage/                # Uploaded files (branding/, imports/, tenants/, users/)
db/init/init.sql        # Full schema + seed data (no migration framework)
db/updates/             # Idempotent SQL update scripts for existing installs
tests/                  # PHPUnit tests (namespace MintyPHP\Tests\)
docs/                   # German-language documentation (Markdown)
i18n/                   # Translation files (de, en)
bin/                    # CLI scripts (scheduler, doctor.php health check)
tools/                  # Dev tooling scripts
docker/                 # Dockerfiles, Nginx configs, PHP configs
```

## Architecture Rules

### Strict Layering (enforce in all changes)

1. **App** (`lib/App/`): DI container bootstrap. Registers all service/repository factories. No business logic.
2. **Repository** (`lib/Repository/`): All SQL lives here. No HTTP, session, or rendering.
3. **Service** (`lib/Service/`): Business rules and validation. No HTML. Four internal sub-types:
   - **Service** (`*Service.php`): Business logic + orchestration. Coordinates repositories and gateways.
   - **Gateway** (`*Gateway.php`): Adapter for a single external dependency (repository, settings, HTTP API, scope). No orchestration flow.
   - **Factory** (`*Factory.php`): Only place inside `lib/Service/` that may call `new` on services/gateways/repositories. Registers via DI container.
   - **Policy** (`*Policy.php` in `lib/Service/Access/`): Authorization decisions per resource type. Returns `AuthorizationDecision`. No HTTP, no business logic.
4. **Action** (`pages/**/*.php`): Reads input, checks permissions + tenant scope, calls services, sets view vars.
5. **View** (`pages/**/*.phtml`): Pure rendering. **No DB calls.** HTML escaping via `e(...)`.
6. **Template** (`templates/`): Layouts and partials.

### Routing

- File-based: `pages/admin/users/edit($id).php` → URL parameter `id`
- `...(none).phtml` → no template layout
- `data().php` suffix → data/AJAX endpoints
- Named aliases in `config/routes.php` with `public` flag for auth guard

### PHP Conventions

- PSR-4 autoload: `MintyPHP\` → `lib/`, `MintyPHP\Tests\` → `tests/`
- All user-facing text uses `t('key')` translation helper
- Permissions + tenant scope enforced in actions/services, never just in UI
- Security/integration settings stay in DB, not in `config/settings.php` file cache

### Frontend Conventions

- Vanilla ES2022 modules, no bundler
- CSS classes prefixed with `app-`
- Defensive DOM checks (elements may not exist on every page)
- No business logic in frontend
- Assets served raw with `assetVersion()` cache-busting (filemtime-based)

### UI Patterns

- Edit pages: tabs → `Master data` | `Visibility` | optional `Danger zone`
- Titlebar partial for primary actions (Save, Save & close)
- Secondary actions in Aside block via `app-details-aside-actions.phtml`
- Lists use Grid.js
- All visible text wrapped in `t('...')`

## Database

- Schema defined in `db/init/init.sql` (applied once on container init)
- No migration framework — schema changes for existing installs are idempotent SQL scripts
- Settings stored in `settings` DB table (single source of truth); `config/settings.php` is a partial file cache for hot-path UI reads only

## Quality Gates

- **PHPStan level 5** — scans `config/`, `lib/`, `pages/`, `tests/`
- **PHPUnit 11** — bootstrap: `tests/bootstrap.php`
- **Frontend Smoke-Check** — browser console bleibt fehlerfrei in Kernflows
- **composer-unused** — periodic check for unused dependencies

## Environment

- Config via `.env` (gitignored) — copy from `.env.example` for dev, `.env.prod.example` for prod
- `config/config.php` (gitignored) — copy from `config/config.php.example`
- `APP_CRYPTO_KEY` (64-char hex) needed for AES-256-GCM encryption of SSO secrets
