# AGENTS.md – HMS Licht & Ton Build & Test Guide

> **Projekt:** hms-licht-ton (ID 30)
> **Stack:** Nuxt 3 (Frontend) + FastAPI (Backend) + PostgreSQL + Redis
> **Deployment:** Coolify (Docker) auf coolify-01
>
> **DESIGN-RICHTLINIEN:** `docs/design-rules.md` – VERBINDLICH für alle Erweiterungen!
> Jeder KI-Agent MUSS diese Regeln vor der Implementierung lesen und einhalten.

---

## 1. Build & Test Commands

### 1.1 Frontend (Nuxt 3)

```bash
# Install dependencies
cd frontend && npm ci

# Development server (http://localhost:3000)
cd frontend && npm run dev

# Production build
cd frontend && npm run build

# Preview production build
cd frontend && npm run preview

# Generate static site (SSG pages)
cd frontend && npm run generate

# Unit tests (Vitest)
cd frontend && npx vitest run --reporter verbose

# Watch mode
cd frontend && npx vitest

# Coverage report
cd frontend && npx vitest run --coverage

# E2E tests (Playwright)
cd frontend && npx playwright test

# Specific E2E test
cd frontend && npx playwright test --grep 'Mietkatalog'

# Lint
cd frontend && npm run lint

# Type check
cd frontend && npm run typecheck
```

### 1.2 Backend (FastAPI)

```bash
# Install dependencies
cd backend && pip install -r requirements.txt

# Development server (http://localhost:8000)
cd backend && uvicorn app.main:app --reload --host 0.0.0.0 --port 8000

# Run all tests
cd backend && python -m pytest tests/ -v

# Run with coverage
cd backend && python -m pytest tests/ -v --cov=app --cov-report=term-missing

# Specific test file
cd backend && python -m pytest tests/test_equipment_router.py -v

# Specific test
cd backend && python -m pytest tests/test_rentman_import.py::test_paginated_import -v

# Database migrations
cd backend && alembic upgrade head
cd backend && alembic revision --autogenerate -m "description"

# Seed admin user
cd backend && python -m app.scripts.seed_admin
```

### 1.3 Docker / Full Stack

```bash
# Build all containers
docker compose build

# Start all services
docker compose up -d

# View logs
docker compose logs -f backend
docker compose logs -f frontend

# Health check
curl -s http://localhost:8000/api/health

# Stop all services
docker compose down

# Reset volumes (DESTRUCTIVE)
docker compose down -v
```

### 1.4 Integration Tests (Full Stack)

```bash
# Start backend + DB + Redis
docker compose up -d backend postgres redis

# Wait for health
curl -s http://localhost:8000/api/health | grep ok

# Run backend tests
cd backend && python -m pytest tests/ -v

# Start frontend
docker compose up -d frontend

# Run E2E tests
cd frontend && npx playwright test
```

---

## 2. Test Rules (MANDATORY)

### 2.1 TDD Principle

- **Write tests first, then implementation.** Tests define the contract.
- Tests MUST be written before or alongside the implementation code.
- Never commit code without corresponding tests.
- Coverage target: **>= 80%** for all modules.

### 2.2 Do NOT Modify Tests

- **Never modify existing tests to make them pass.**
- If a test fails, fix the implementation, not the test.
- Tests are the source of truth for expected behavior.
- If a test is genuinely wrong, flag it in a PR and explain why.
- Only the original test author or a reviewer may modify tests.

### 2.3 Test File Naming

**Frontend:**
- Unit tests: `frontend/tests/unit/*.test.ts`
- E2E tests: `frontend/tests/e2e/*.spec.ts`
- Fixtures: `frontend/tests/fixtures/*`
- Mocks: `frontend/tests/mocks/*`

**Backend:**
- Unit/Integration tests: `backend/tests/test_*.py`
- Fixtures: `backend/tests/conftest.py`
- Factories: `backend/tests/factories.py`
- Mocks: `backend/tests/mocks/`

### 2.4 Test Categories

| Category | Tool | Scope | When to Run |
|----------|------|-------|-------------|
| Unit | Vitest / Pytest | Functions, composables, stores, services | Every commit |
| Component | Vitest + Vue Test Utils | Vue components, props, emits | Every commit |
| Integration | Pytest + TestClient | API endpoints, DB operations | Every commit |
| E2E | Playwright | Full page flows, forms, navigation | Pre-merge, nightly |
| Smoke | curl scripts | API health, endpoints | Post-deploy |

### 2.5 Mocking Rules

- **Rentman API:** Always mock in tests. Never call live Rentman API.
  - Use `unittest.mock.patch` or `responses` library
  - Mock `GET /equipment` with paginated test data
  - Mock `POST /projectrequests` with fake response IDs
- **SMTP:** Always mock email sending in tests.
  - Mock `aiosmtplib.send` to capture sent emails
  - Verify email content, not actual delivery
- **Database:** Use SQLite in-memory or test PostgreSQL instance.
  - Never run tests against production database
  - Use separate test database: `DATABASE_URL=sqlite+aiosqlite:///test.db`

---

## 3. Coding Conventions

### 3.1 Frontend (Vue 3 + TypeScript)

```typescript
// Use Composition API with <script setup>
<script setup lang="ts">
import { ref, computed } from 'vue'

// Props with TypeScript types
const props = defineProps<{
  item: EquipmentItem
  showBadge?: boolean
}>()

// Emits with TypeScript types
const emit = defineEmits<{
  'add-to-cart': [item: EquipmentItem]
  'click': [id: number]
}>()

// Refs with types
const loading = ref(false)
const error = ref<string | null>(null)

// Computed
const totalPrice = computed(() => items.value.reduce((sum, i) => sum + i.price, 0))
</script>
```

**Rules:**
- Use `<script setup lang="ts">` always
- Use Composition API (not Options API)
- Use Pinia for global state
- Use `useFetch` / `useAsyncData` for SSR data fetching
- Use Tailwind utility classes (no custom CSS unless necessary)
- Use design tokens (CSS variables) for colors, spacing, radius
- Components: PascalCase filenames (`EquipmentCard.vue`)
- Pages: kebab-case filenames (`mietkatalog/[id].vue`)
- Composables: `use` prefix (`useEquipment.ts`)
- Stores: `stores/*.ts` with Pinia defineStore

### 3.2 Backend (Python + FastAPI)

```python
# Use async/await always
async def get_equipment_list(
    search: str | None = None,
    category: str | None = None,
    page: int = 1,
    page_size: int = 20,
    db: AsyncSession = Depends(get_db),
) -> PaginatedResponse[EquipmentItem]:
    ...

# Pydantic schemas for all input/output
class EquipmentItem(BaseModel):
    id: int
    name: str
    category: str | None = None
    rental_price: Decimal | None = None
    available: bool = True

# Type hints everywhere
def calculate_reference_number() -> str:
    year = datetime.now().year
    random_num = random.randint(1, 99999)
    return f"HMS-{year}-{random_num:05d}"
```

**Rules:**
- PEP 8 style (line length 100)
- async/await for all I/O operations (DB, Redis, API calls, SMTP)
- Pydantic v2 for all schemas (input validation, output serialization)
- Type hints on all functions and methods
- Routers in `routers/`, services in `services/`, models in `models/`
- Config via `pydantic-settings` (BaseSettings class)
- Database: SQLAlchemy async with `asyncpg` driver
- No raw SQL in routers (use SQLAlchemy ORM or service layer)
- Error handling: HTTPException with proper status codes

### 3.3 Naming Conventions

| Type | Frontend | Backend |
|------|----------|--------|
| Files | kebab-case (`mietkatalog.vue`) | snake_case (`rentman_import.py`) |
| Components | PascalCase (`EquipmentCard`) | – |
| Functions | camelCase (`getEquipmentList`) | snake_case (`get_equipment_list`) |
| Variables | camelCase (`equipmentList`) | snake_case (`equipment_list`) |
| Constants | UPPER_SNAKE (`API_BASE_URL`) | UPPER_SNAKE (`RENTMAN_API_TOKEN`) |
| Classes | PascalCase (`EquipmentItem`) | PascalCase (`EquipmentItem`) |
| CSS | kebab-case (`.equipment-card`) | – |
| DB Tables | – | snake_case (`equipment_cache`) |
| API Routes | kebab-case (`/api/rental-requests`) | kebab-case (`/api/rental-requests`) |

### 3.4 Git Conventions

- Branch naming: `feature/T01-frontend-foundation`, `fix/equipment-search`
- Commit messages: Conventional Commits
  - `feat: add equipment search filter`
  - `fix: correct date validation in rental request`
  - `test: add equipment router tests`
  - `docs: update architecture.md`
  - `refactor: extract email service`
  - `chore: update dependencies`
- PR: Squash merge, one PR per task
- Never commit secrets (.env, credentials)

---

## 4. Environment Variables

### 4.1 Required (.env)

```bash
# Rentman
RENTMAN_API_TOKEN=your_token_here

# Auth
JWT_SECRET=your_jwt_secret_here

# Database
DATABASE_URL=postgresql+asyncpg://hms:password@localhost:5432/hms

# Redis
REDIS_URL=redis://localhost:6379/0

# SMTP
SMTP_HOST=smtp.example.com
SMTP_PORT=587
SMTP_USER=user@example.com
SMTP_PASSWORD=your_password
SMTP_FROM=info@hms-licht-ton.de

# Frontend
NUXT_PUBLIC_API_BASE=http://localhost:8000/api
```

### 4.2 Optional

```bash
# Admin seeding
ADMIN_USERNAME=admin
ADMIN_PASSWORD=change_me_in_production

# CORS
CORS_ORIGINS=https://hms.media-on.de
```

---

## 5. Task Dependencies

```
T01 (Frontend Foundation) ─────┬──> T02 (Static Pages)
                                ├──> T06 (Mietkatalog Frontend) ──> T07 (Cart/Mietanfrage)
                                │
T03 (Backend Core) ────────────┼──> T04 (Rentman Integration)
                                ├──> T05 (Email/Contact/Rental Backend)
                                ├──> T06 (Mietkatalog Frontend)
                                │
T08 (Docker/CI/CD) ── depends on ALL ──>
```

**Parallel execution:**
- T01 and T03 can start simultaneously (no shared dependencies)
- T02 starts after T01
- T04 starts after T03
- T06 starts after T01 AND T03
- T05 starts after T03 AND T04
- T07 starts after T01 AND T06
- T08 starts after ALL other tasks

---

## 6. Quality Gates

### 6.1 Per-Task Gate

Before a task is marked complete:
- [ ] All test_spec.commands pass
- [ ] Coverage >= target (80%)
- [ ] All acceptance_criteria verified
- [ ] Build succeeds (npm run build / pip install)
- [ ] No linting errors
- [ ] No type errors

### 6.2 Pre-Merge Gate

- [ ] All task tests pass
- [ ] E2E tests pass
- [ ] Docker build succeeds
- [ ] No secrets in code
- [ ] Code review approved

### 6.3 Pre-Deploy Gate

- [ ] All E2E tests pass
- [ ] Health check returns 200
- [ ] Environment variables set in Coolify
- [ ] Domain DNS configured
- [ ] TLS certificate active

---

## 7. Forbidden Patterns

### 7.1 Frontend
- ❌ Options API (`export default { data() { ... } }`)
- ❌ Hardcoded colors (use CSS variables / Tailwind config)
- ❌ Inline styles (use Tailwind classes)
- ❌ `localStorage` direct access in components (use Pinia store with persist plugin)
- ❌ Fetching in `mounted()` (use `useAsyncData` / `useFetch` for SSR)
- ❌ `any` type (use proper TypeScript types)
- ❌ Console.log in production code
- ❌ Large inline SVG (use separate component files)

### 7.2 Backend
- ❌ Sync I/O in async context (no `requests.get`, use `httpx.AsyncClient`)
- ❌ Raw SQL in routers (use service layer + SQLAlchemy ORM)
- ❌ Hardcoded secrets (use env vars / pydantic-settings)
- ❌ `print()` in production code (use `logging`)
- ❌ Missing type hints
- ❌ Missing Pydantic validation (all inputs must be validated)
- ❌ Direct Rentman API calls without going through service layer
- ❌ Missing error handling (no bare `except:`)
- ❌ Synchronous database operations (use async SQLAlchemy)

---

## 8. Project Structure Summary

```
hms-licht-ton/
├── frontend/           (Nuxt 3 + Tailwind CSS)
│   ├── components/    (Vue 3 SFCs)
│   ├── pages/          (File-based routing)
│   ├── stores/         (Pinia stores)
│   ├── composables/    (useXxx composables)
│   ├── layouts/        (Nuxt layouts)
│   ├── assets/         (CSS, images, SVG)
│   ├── tests/          (Vitest + Playwright)
│   └── nuxt.config.ts
├── backend/            (FastAPI + SQLAlchemy + Redis)
│   ├── app/
│   │   ├── main.py
│   │   ├── config.py
│   │   ├── database.py
│   │   ├── models/     (SQLAlchemy models)
│   │   ├── schemas/    (Pydantic schemas)
│   │   ├── routers/    (API endpoints)
│   │   ├── services/   (Business logic)
│   │   └── cache.py     (Redis client)
│   ├── tests/          (Pytest)
│   ├── alembic/        (Migrations)
│   └── Dockerfile
├── docs/               (Architecture, requirements, UI design)
├── docker-compose.yml  (4 services)
├── .env.example
├── .forgejo/           (CI/CD workflows)
├── AGENTS.md           (This file)
└── README.md
```

---

## 9. Key References

- **Architecture:** `docs/architecture.md`
- **Task Graph:** `docs/task_graph.json`
- **Requirements:** `docs/requirements.md`
- **UI Design:** `docs/ui_design.md`
- **Component Inventory:** `docs/component_inventory.md`
- **Rentman API Skills:** `rentman-api-operations` + `rentman-domain-basics` (load before API calls)
- **Rentman Python Client:** `from usr.plugins.rentman.helpers.rentman import RentmanAPI`

---

## 10. Emergency Procedures

### 10.1 Backend Down
1. Check `docker compose logs backend`
2. Check `docker compose ps` (is it running?)
3. Check `curl http://localhost:8000/api/health`
4. If DB issue: `docker compose restart postgres`
5. If Redis issue: `docker compose restart redis`
6. If app crash: `docker compose restart backend`

### 10.2 Frontend Down
1. Check `docker compose logs frontend`
2. Check `docker compose ps`
3. `docker compose restart frontend`
4. If build issue: `cd frontend && npm run build` (check errors)

### 10.3 Rentman API Unreachable
1. Check `RENTMAN_API_TOKEN` in env vars
2. Test token: `curl -H "Authorization: Bearer $TOKEN" https://api.rentman.net/equipment`
3. If expired: Generate new token in Rentman UI
4. Cached equipment still serves from PostgreSQL + Redis

### 10.4 Database Reset (DESTRUCTIVE)
```bash
docker compose down -v
docker compose up -d
cd backend && alembic upgrade head
python -m app.scripts.seed_admin
```

---

## 11. Handoff

- **AGENTS.md status:** COMPLETE
- **All build commands documented:** YES
- **Test rules documented:** YES
- **Conventions documented:** YES
- **Quality gates defined:** YES
- **Ready for implementation:** YES (after Plan Mode transition to `implementation_allowed`)