13 KiB
Runtime Report — ERP Nutzfahrzeuge
Date: 2026-07-17
Phase: 5 — Runtime Verification
Runtime: /opt/venv/bin/python (execution environment)
Summary
| Check | Status |
|---|---|
| Backend startup | ✅ PASS |
| Health endpoint | ✅ PASS (200, {"status":"ok"}) |
| Root endpoint | ✅ PASS (200, app metadata) |
| Auth login (GET) | ✅ PASS (405 Method Not Allowed — POST-only) |
| OpenAPI/Swagger | ✅ PASS (200, full schema) |
| Frontend build artifacts | ✅ PASS (.next/ with BUILD_ID, server/, static/) |
| Runtime errors | ✅ NONE (clean logs, no tracebacks) |
| PostgreSQL | ✅ Running (localhost:5432, accepting connections) |
| Redis | ⚠️ NOT installed (JWT-based refresh tokens, no Redis storage needed) |
Overall verdict: Backend starts and runs cleanly. All public endpoints respond as expected. No runtime errors detected.
1. Startup Verification
Start command:
cd backend && /opt/venv/bin/python -m uvicorn app.main:app --host 0.0.0.0 --port 8000
Result: Server started successfully (PID 3383733).
Startup log:
INFO: Started server process [3383733]
INFO: Waiting for application startup.
INFO: Application startup complete.
INFO: Uvicorn running on http://0.0.0.0:8000 (Press CTRL+C to quit)
Import check: from app.main import app — OK (no ImportError)
Core dependencies verified:
uvicorn✅fastapi✅sqlalchemy✅asyncpg✅
2. Health Check
Endpoint: GET http://localhost:8000/api/v1/health
Response:
- HTTP Status:
200 OK - Body:
{"status":"ok"}
Verdict: ✅ Health endpoint reachable and returning expected payload.
3. Endpoint Verification
3.1 Root Endpoint
- URL:
GET http://localhost:8000/ - HTTP Status:
200 OK - Body:
{"name":"ERP Nutzfahrzeuge","version":"1.0.0","docs":"/docs"}
3.2 Auth Login (GET — should fail)
- URL:
GET http://localhost:8000/api/v1/auth/login - HTTP Status:
405 Method Not Allowed - Body:
{"detail":"Method Not Allowed"} - Expected behavior: Login is POST-only; GET correctly rejected.
3.3 OpenAPI Schema
- URL:
GET http://localhost:8000/openapi.json - HTTP Status:
200 OK - Schema version: OpenAPI 3.1.0
- Title: ERP Nutzfahrzeuge Backend API
- Version: 1.0.0
4. Available API Endpoints (from OpenAPI)
Auth (/api/v1/auth)
| Method | Path | Description | Auth |
|---|---|---|---|
| POST | /api/v1/auth/login |
Login with email+password → JWT tokens | No |
| POST | /api/v1/auth/refresh |
Exchange refresh token for new token pair | No |
| GET | /api/v1/auth/me |
Get current user profile | Bearer |
Users (/api/v1/users)
| Method | Path | Description | Auth |
|---|---|---|---|
| GET | /api/v1/users/ |
List users (paginated, admin only) | Bearer |
| POST | /api/v1/users/ |
Create user (admin only) | Bearer |
| PUT | /api/v1/users/{user_id} |
Update user (admin only) | Bearer |
| DELETE | /api/v1/users/{user_id} |
Soft-delete user (admin only) | Bearer |
Vehicles (/api/v1/vehicles)
| Method | Path | Description | Auth |
|---|---|---|---|
| GET | /api/v1/vehicles/ |
List vehicles (filter, sort, paginate) | Bearer |
| POST | /api/v1/vehicles/ |
Create vehicle | Bearer |
| GET | /api/v1/vehicles/{vehicle_id} |
Get single vehicle | Bearer |
| PUT | /api/v1/vehicles/{vehicle_id} |
Update vehicle | Bearer |
| DELETE | /api/v1/vehicles/{vehicle_id} |
Soft-delete vehicle | Bearer |
| POST | /api/v1/vehicles/{vehicle_id}/mobile-de/push |
Push to mobile.de (async, 202) | Bearer |
| GET | /api/v1/vehicles/{vehicle_id}/mobile-de/status |
Get mobile.de sync status | Bearer |
Contacts (/api/v1/contacts)
| Method | Path | Description | Auth |
|---|---|---|---|
| GET | /api/v1/contacts/ |
List contacts (filter, sort, paginate) | Bearer |
| POST | /api/v1/contacts/ |
Create contact (admin/verkaeufer) | Bearer |
| GET | /api/v1/contacts/{contact_id} |
Get contact with persons | Bearer |
| PUT | /api/v1/contacts/{contact_id} |
Update contact | Bearer |
| DELETE | /api/v1/contacts/{contact_id} |
Soft-delete contact | Bearer |
| POST | /api/v1/contacts/{contact_id}/persons |
Add contact person | Bearer |
| DELETE | /api/v1/contacts/{contact_id}/persons/{person_id} |
Remove contact person | Bearer |
Files (/api/v1/vehicles/{vehicle_id}/files)
| Method | Path | Description | Auth |
|---|---|---|---|
| GET | /api/v1/vehicles/{vehicle_id}/files |
List files for vehicle | Bearer |
| POST | /api/v1/vehicles/{vehicle_id}/files |
Upload file (multipart, max 20MB) | Bearer |
| GET | /api/v1/vehicles/{vehicle_id}/files/{file_id} |
Download file | Bearer |
| DELETE | /api/v1/vehicles/{vehicle_id}/files/{file_id} |
Delete file | Bearer |
OCR (/api/v1/ocr)
| Method | Path | Description | Auth |
|---|---|---|---|
| POST | /api/v1/ocr/upload |
Upload scan for OCR (async, 202) | Bearer |
| GET | /api/v1/ocr/results/{result_id} |
Get OCR result | Bearer |
| GET | /api/v1/ocr/results |
List OCR results | Bearer |
| POST | /api/v1/ocr/results/{result_id}/apply |
Apply OCR data to vehicle | Bearer |
Sales (/api/v1/sales)
| Method | Path | Description | Auth |
|---|---|---|---|
| GET | /api/v1/sales/ |
List sales (filter by status/date) | Bearer |
| POST | /api/v1/sales/ |
Create sale (sets vehicle to 'sold') | Bearer |
| GET | /api/v1/sales/{sale_id} |
Get sale with nested data | Bearer |
| PUT | /api/v1/sales/{sale_id} |
Update sale | Bearer |
| DELETE | /api/v1/sales/{sale_id} |
Cancel sale (soft delete) | Bearer |
| POST | /api/v1/sales/{sale_id}/contract |
Regenerate contract PDF | Bearer |
| GET | /api/v1/sales/{sale_id}/contract |
Download contract PDF | Bearer |
| POST | /api/v1/sales/{sale_id}/verify-ust-id |
Verify USt-IdNr. via BZSt API | Bearer |
DATEV (/api/v1/datev)
| Method | Path | Description | Auth |
|---|---|---|---|
| POST | /api/v1/datev/export |
Create DATEV export (CSV) | Bearer |
| GET | /api/v1/datev/exports |
List DATEV exports | Bearer |
| GET | /api/v1/datev/exports/{export_id}/download |
Download DATEV CSV | Bearer |
Copilot (/api/v1/copilot)
| Method | Path | Description | Auth |
|---|---|---|---|
| POST | /api/v1/copilot/chat |
Send message to AI Copilot | Bearer |
| POST | /api/v1/copilot/action |
Execute confirmed action | Bearer |
| GET | /api/v1/copilot/history |
Get chat history | Bearer |
| POST | /api/v1/copilot/voice |
Voice input (base64 audio) | Bearer |
Retouch (/api/v1/retouch)
| Method | Path | Description | Auth |
|---|---|---|---|
| POST | /api/v1/retouch/process |
Upload image for retouching (async, 202) | Bearer |
| GET | /api/v1/retouch/results/{result_id} |
Get retouch result | Bearer |
| POST | /api/v1/retouch/price-compare |
Compare prices for vehicle | Bearer |
Health
| Method | Path | Description | Auth |
|---|---|---|---|
| GET | /api/v1/health |
Health check | No |
| GET | / |
Root info | No |
5. Frontend Build Verification
Location: frontend/.next/
Build artifacts confirmed:
BUILD_ID— present (20 bytes)build-manifest.json— presentapp-build-manifest.json— presentroutes-manifest.json— presentserver/— directory presentstatic/— directory presentprerender-manifest.json— presentrequired-server-files.json— presenttrace/— build trace present
Verdict: ✅ Frontend build artifacts are complete and present.
6. Environment Verification
Required Environment Variables (from .env.example)
| Variable | Required | Status | Notes |
|---|---|---|---|
DATABASE_URL |
✅ Yes | Set (local PostgreSQL) | postgresql+asyncpg://erp_test_user:***@localhost:5432/erp_test |
REDIS_URL |
✅ Yes | Set in .env.example | Redis NOT installed; JWT refresh tokens are stateless (no Redis storage needed) |
JWT_SECRET |
✅ Yes | Placeholder in .env.example | Must be set to a secure random string for production |
JWT_ALGORITHM |
Optional | Default HS256 | — |
JWT_ACCESS_TTL_MINUTES |
Optional | Default 15 | — |
JWT_REFRESH_TTL_DAYS |
Optional | Default 7 | — |
CORS_ORIGINS |
✅ Yes | Set | http://localhost:3000,http://localhost:3001 |
UPLOAD_DIR |
Optional | Default /tmp/uploads |
Must be persistent volume in production |
APP_NAME |
Optional | Default ERP Nutzfahrzeuge |
— |
APP_ENV |
Optional | Default development |
Set to production for deployment |
MOBILE_DE_API_KEY |
Optional | Empty | Required for mobile.de integration |
MOBILE_DE_SELLER_ID |
Optional | Empty | Required for mobile.de integration |
OPENROUTER_API_KEY |
Optional | Not in .env.example | Required for AI Copilot features (currently empty/non-functional) |
Infrastructure Status
| Service | Status | Notes |
|---|---|---|
| PostgreSQL | ✅ Running | localhost:5432, accepting connections |
| Redis | ⚠️ Not installed | Not required for JWT; may be needed for async task queues (OCR, retouch, mobile.de push) |
| OpenRouter API | ⚠️ Not configured | AI Copilot features will not work without API key |
7. Errors Found
No errors, tracebacks, warnings, or critical messages found in runtime logs.
Log output was clean:
INFO: Started server process [3383733]
INFO: Waiting for application startup.
INFO: Application startup complete.
INFO: Uvicorn running on http://0.0.0.0:8000 (Press CTRL+C to quit)
INFO: 127.0.0.1:48688 - "GET /api/v1/health HTTP/1.1" 200 OK
INFO: 127.0.0.1:48700 - "GET / HTTP/1.1" 200 OK
INFO: 127.0.0.1:48706 - "GET /api/v1/auth/login HTTP/1.1" 405 Method Not Allowed
INFO: 127.0.0.1:48710 - "GET /openapi.json HTTP/1.1" 200 OK
8. Known Risks
| # | Risk | Severity | Mitigation |
|---|---|---|---|
| 1 | Redis not installed — async task processing (OCR, retouch, mobile.de push) may fail or fall back to synchronous processing | Medium | Install Redis or verify async tasks have graceful fallback. Check if background tasks use in-memory queues. |
| 2 | OPENROUTER_API_KEY not set — AI Copilot (/api/v1/copilot/*) will not function |
Medium | Set OPENROUTER_API_KEY in production environment for Copilot features. |
| 3 | JWT_SECRET is placeholder — change-me-to-a-secure-random-string in .env.example |
High | Generate a cryptographically secure secret (≥256 bits) for production. |
| 4 | PostgreSQL is local only — no connection pooling or HA configured | Medium | Configure PgBouncer or use managed PostgreSQL (e.g., Coolify managed DB) for production. |
| 5 | UPLOAD_DIR = /tmp/uploads — ephemeral storage, files lost on container restart |
High | Mount a persistent volume for UPLOAD_DIR in production. |
| 6 | CORS_ORIGINS — currently allows localhost:3000,3001 only | Low | Add production frontend origin to CORS_ORIGINS for deployment. |
| 7 | MOBILE_DE_API_KEY empty — mobile.de push/status endpoints will fail | Low | Set API key when mobile.de integration is needed. |
| 8 | No HTTPS/TLS — backend runs on plain HTTP | Medium | Use reverse proxy (nginx/Traefik) or Coolify proxy for TLS termination. |
| 9 | No rate limiting — no rate limiting middleware detected | Medium | Add rate limiting (e.g., slowapi) before public exposure. |
9. Recommendations
Immediate (before deployment)
- Generate a secure
JWT_SECRETand configure in production environment - Set
APP_ENV=productionfor deployment - Configure persistent volume for
UPLOAD_DIR - Add production frontend origin to
CORS_ORIGINS - Install Redis if async task processing (OCR, retouch, mobile.de) is required
- Set
OPENROUTER_API_KEYif AI Copilot features are needed
Deployment preparation
- Create Dockerfile / docker-compose.yml for containerized deployment
- Configure reverse proxy with TLS termination (Coolify proxy or nginx)
- Set up PostgreSQL as managed service or with backup strategy
- Add health check to Coolify resource configuration (
GET /api/v1/health) - Configure log rotation and monitoring
Post-deployment
- Run smoke tests against production endpoints
- Verify JWT auth flow end-to-end
- Test file upload with persistent volume
- Monitor for async task failures (OCR, retouch)
10. Sign-off
| Item | Status |
|---|---|
| App starts without errors | ✅ Yes |
| Health endpoint returns 200 | ✅ Yes |
| Bounded error output shows no critical runtime failure | ✅ Yes (zero errors) |
| Frontend build artifacts present | ✅ Yes |
| Deployment docs ready | ✅ Yes (see deploy/ directory) |
| Ready for deployment | ⚠️ Conditional — requires secure JWT_SECRET, persistent storage, and Redis decision |
Runtime verification: PASSED Deployment readiness: CONDITIONAL (env vars + infrastructure must be configured)