docs: add initial architecture documentation

This commit is contained in:
2026-04-28 10:45:37 +02:00
parent 05b06d409f
commit 1eb6aca588
7 changed files with 1112 additions and 32 deletions

315
docs/api-contract.md Normal file
View File

@@ -0,0 +1,315 @@
# API Contract
This document proposes the initial REST API for AzioneLab. Endpoint names are intentionally explicit and small-project friendly.
All examples use JSON unless noted otherwise.
## Public Content
### List Shows
```http
GET /api/shows/
```
Returns published shows.
Response `200 OK`:
```json
{
"results": [
{
"id": 1,
"title": "The Open Stage",
"slug": "the-open-stage",
"summary": "A contemporary theatre performance.",
"poster_image": "https://example.org/media/shows/open-stage.jpg"
}
]
}
```
### Show Detail
```http
GET /api/shows/{slug}/
```
Response `200 OK`:
```json
{
"id": 1,
"title": "The Open Stage",
"slug": "the-open-stage",
"summary": "A contemporary theatre performance.",
"description": "Full public show description.",
"poster_image": "https://example.org/media/shows/open-stage.jpg",
"performances": [
{
"id": 10,
"starts_at": "2026-05-15T20:30:00+02:00",
"venue": {
"name": "AzioneLab Theatre",
"city": "Rome"
},
"booking_enabled": true,
"available_seats": 24
}
]
}
```
Status codes:
- `200 OK`: show found;
- `404 Not Found`: show does not exist or is not published.
### List Performances
```http
GET /api/performances/
```
Optional filters:
- `show`: show slug;
- `from`: start date/time lower bound.
Response `200 OK`:
```json
{
"results": [
{
"id": 10,
"show": {
"title": "The Open Stage",
"slug": "the-open-stage"
},
"venue": {
"name": "AzioneLab Theatre",
"city": "Rome"
},
"starts_at": "2026-05-15T20:30:00+02:00",
"booking_enabled": true,
"available_seats": 24
}
]
}
```
### Performance Detail
```http
GET /api/performances/{id}/
```
Response `200 OK`:
```json
{
"id": 10,
"show": {
"title": "The Open Stage",
"slug": "the-open-stage",
"summary": "A contemporary theatre performance."
},
"venue": {
"name": "AzioneLab Theatre",
"address": "Via Example 10",
"city": "Rome"
},
"starts_at": "2026-05-15T20:30:00+02:00",
"booking_enabled": true,
"available_seats": 24
}
```
Status codes:
- `200 OK`: performance found;
- `404 Not Found`: performance does not exist or is not public.
## Booking
### Create Reservation
```http
POST /api/performances/{id}/reservations/
```
Creates a pending reservation and sends a confirmation email.
Request:
```json
{
"name": "Maria Rossi",
"email": "maria.rossi@example.org",
"phone": "+390600000000",
"party_size": 2,
"notes": "We will arrive a few minutes early."
}
```
Response `201 Created`:
```json
{
"id": 123,
"status": "pending",
"performance": 10,
"party_size": 2,
"message": "Reservation created. Please check your email to confirm it."
}
```
Status codes:
- `201 Created`: pending reservation created;
- `400 Bad Request`: invalid input;
- `404 Not Found`: performance does not exist or is not public;
- `409 Conflict`: booking is closed or capacity is already unavailable.
Validation rules:
- `name` is required;
- `email` must be a valid email address;
- `party_size` must be a positive integer;
- public clients must not set reservation status;
- the backend must validate booking availability server-side.
### Confirm Reservation
```http
POST /api/reservations/confirm/
```
Confirms a pending reservation using the token from the email link.
Request:
```json
{
"token": "opaque-confirmation-token"
}
```
Response `200 OK`:
```json
{
"reservation_id": 123,
"status": "confirmed",
"party_size": 2,
"qr_code_url": "https://example.org/api/reservations/123/qr-code/"
}
```
Status codes:
- `200 OK`: reservation confirmed;
- `400 Bad Request`: token is missing or malformed;
- `404 Not Found`: token is unknown;
- `409 Conflict`: token already used, reservation already handled, or no capacity remains;
- `410 Gone`: token expired.
### Retrieve QR Code
```http
GET /api/reservations/{id}/qr-code/
```
Returns the generated QR code for a confirmed reservation. Access must be protected by a valid QR token, signed URL, or equivalent control so that reservation IDs are not enough to retrieve QR codes.
Response `200 OK`:
```json
{
"reservation_id": 123,
"qr_code_image": "data:image/png;base64,...",
"printable": true
}
```
Status codes:
- `200 OK`: QR code available;
- `403 Forbidden`: caller is not allowed to access the QR code;
- `404 Not Found`: reservation not found;
- `409 Conflict`: reservation is not confirmed.
## Check-In
### Verify QR Code
```http
POST /api/check-ins/verify/
```
Validates a QR token and records check-in. This endpoint is for authenticated staff or an authenticated scanning interface.
Request:
```json
{
"token": "opaque-check-in-token"
}
```
Response `200 OK`:
```json
{
"status": "checked_in",
"reservation_id": 123,
"performance_id": 10,
"party_size": 2,
"checked_in_at": "2026-05-15T19:55:00+02:00"
}
```
Status codes:
- `200 OK`: reservation checked in;
- `400 Bad Request`: token is missing or malformed;
- `401 Unauthorized`: staff authentication is missing;
- `403 Forbidden`: authenticated user cannot perform check-in;
- `404 Not Found`: token is unknown;
- `409 Conflict`: reservation is not confirmed or was already checked in;
- `410 Gone`: token is expired.
The response should include only the minimum information staff need to admit the party.
## Administration
The initial administration API is Django admin.
Admin paths:
```http
GET /admin/
```
Admin users can manage shows, venues, performances, reservations, reservation tokens, and check-ins according to staff permissions.
Status codes:
- `302 Found`: unauthenticated browser redirected to admin login;
- `200 OK`: authenticated admin page;
- `403 Forbidden`: authenticated user lacks the required permission.
## Error Format
Use Django REST Framework's standard validation error format unless a project-specific envelope is introduced later.
Example `400 Bad Request`:
```json
{
"email": ["Enter a valid email address."],
"party_size": ["Ensure this value is greater than or equal to 1."]
}
```