eedb049bab
Next.js 16 app with full CRUD lead management: - REST API (/api/leads) with GET (pagination), POST, PUT, DELETE (soft delete) - Zod validation (server + client), Supabase (PostgreSQL) - Responsive UI: leads table (desktop) + cards (mobile), modal form, toast notifications - 43 tests (Vitest + React Testing Library): validation, components, pagination - Docker setup (multi-stage build, health check) - Supabase migration + 15 seed leads - Documentation (CLAUDE.md, README, API docs) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
3.0 KiB
3.0 KiB
API Documentation
Base URL
http://localhost:3000/api
Endpoints
List Leads
GET /api/leads?page=1&limit=10
Query Parameters:
| Parameter | Type | Default | Description |
|---|---|---|---|
| page | number | 1 | Page number (min: 1) |
| limit | number | 10 | Items per page (min: 1, max: 100) |
Response (200):
{
"data": [
{
"id": "uuid",
"first_name": "Max",
"email": "max@beispiel.de",
"phone": "+49 123 456789",
"fitness_goal": "abnehmen",
"created_at": "2026-01-01T00:00:00Z",
"updated_at": "2026-01-01T00:00:00Z",
"deleted_at": null
}
],
"meta": {
"current_page": 1,
"per_page": 10,
"total": 15,
"total_pages": 2,
"has_more": true
}
}
Create Lead
POST /api/leads
Content-Type: application/json
Request Body:
{
"first_name": "Max",
"email": "max@beispiel.de",
"phone": "+49 123 456789",
"fitness_goal": "abnehmen"
}
| Field | Type | Required | Validation |
|---|---|---|---|
| first_name | string | yes | 2-100 chars, trimmed |
| string | yes | Valid email, max 255, lowercased | |
| phone | string | no | Max 20 chars, digits/spaces/+/- |
| fitness_goal | enum | yes | abnehmen, muskelaufbau, ausdauer, flexibilitaet |
Response (201):
{
"data": { ... }
}
Error (422) - Validation:
{
"error": {
"code": "VALIDATION_ERROR",
"message": "Validierungsfehler",
"details": {
"email": ["Bitte eine gueltige E-Mail-Adresse eingeben"]
}
}
}
Error (409) - Duplicate email:
{
"error": {
"code": "CONFLICT",
"message": "Ein Lead mit dieser E-Mail-Adresse existiert bereits"
}
}
Get Lead
GET /api/leads/:id
Response (200):
{
"data": { ... }
}
Error (404):
{
"error": {
"code": "NOT_FOUND",
"message": "Lead nicht gefunden"
}
}
Update Lead
PUT /api/leads/:id
Content-Type: application/json
Request Body (partial update):
{
"first_name": "Maximilian",
"fitness_goal": "muskelaufbau"
}
All fields are optional but at least one must be provided.
Response (200):
{
"data": { ... }
}
Delete Lead (Soft Delete)
DELETE /api/leads/:id
Sets deleted_at timestamp instead of removing the record.
Response (200):
{
"data": {
"message": "Lead erfolgreich geloescht"
}
}
Error Response Format
All errors follow this structure:
{
"error": {
"code": "ERROR_CODE",
"message": "Human-readable message",
"details": {}
}
}
| HTTP Status | Code | Description |
|---|---|---|
| 400 | INVALID_ID / INVALID_JSON | Bad request |
| 404 | NOT_FOUND | Resource not found |
| 409 | CONFLICT | Duplicate entry |
| 422 | VALIDATION_ERROR | Input validation failed |
| 500 | DATABASE_ERROR / INTERNAL_ERROR | Server error |