generated from bisco/codex-bootstrap
382 lines
7.8 KiB
Markdown
382 lines
7.8 KiB
Markdown
# 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
|
|
|
|
Check-in endpoints are for authenticated staff or admin users. Staff use a mobile-friendly Angular page to scan the QR code with a device camera or enter the token manually.
|
|
|
|
The QR code must contain only an opaque verification token or a verification URL containing that token. The backend resolves and validates the token server-side.
|
|
|
|
### QR Verification Preview
|
|
|
|
```http
|
|
POST /api/check-ins/preview/
|
|
```
|
|
|
|
Validates a QR token and returns a preview before staff confirms entrance. This endpoint must not create a successful check-in.
|
|
|
|
Request:
|
|
|
|
```json
|
|
{
|
|
"token": "opaque-check-in-token"
|
|
}
|
|
```
|
|
|
|
Response `200 OK`:
|
|
|
|
```json
|
|
{
|
|
"status": "valid",
|
|
"reservation_id": 123,
|
|
"performance_id": 10,
|
|
"show_title": "The Open Stage",
|
|
"starts_at": "2026-05-15T20:30:00+02:00",
|
|
"party_size": 2
|
|
}
|
|
```
|
|
|
|
Status codes:
|
|
|
|
- `200 OK`: token is valid and reservation can be checked in;
|
|
- `400 Bad Request`: token is missing or malformed;
|
|
- `401 Unauthorized`: staff authentication is missing;
|
|
- `403 Forbidden`: authenticated user cannot preview 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 preview response should include only the minimum information staff need to validate the party. It must not expose unnecessary reservation personal data.
|
|
|
|
### Check-In Confirmation
|
|
|
|
```http
|
|
POST /api/check-ins/confirm/
|
|
```
|
|
|
|
Validates the token again and records successful entrance.
|
|
|
|
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",
|
|
"checked_in_by": 7
|
|
}
|
|
```
|
|
|
|
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 confirm check-in;
|
|
- `404 Not Found`: token is unknown;
|
|
- `409 Conflict`: reservation is not confirmed or was already checked in;
|
|
- `410 Gone`: token is expired.
|
|
|
|
Successful confirmation creates a `CheckIn` record, or updates an existing incomplete check-in record for the reservation. A reservation cannot have two successful check-ins.
|
|
|
|
Error responses should use clear machine-readable states so the staff interface can show simple messages.
|
|
|
|
Example `409 Conflict` for duplicate check-in:
|
|
|
|
```json
|
|
{
|
|
"status": "already_checked_in",
|
|
"detail": "This reservation has already been checked in."
|
|
}
|
|
```
|
|
|
|
Example `409 Conflict` for unconfirmed reservation:
|
|
|
|
```json
|
|
{
|
|
"status": "reservation_not_confirmed",
|
|
"detail": "This reservation is not confirmed."
|
|
}
|
|
```
|
|
|
|
## 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."]
|
|
}
|
|
```
|