500 lines
14 KiB
Markdown
500 lines
14 KiB
Markdown
# 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`) |