This project contains the API source code that is hosted on a different server.
The complete REST API is documented below. All endpoints return JSON responses and validate input using Marshmallow schemas.
Health Check:
GET /health → {"status": "ok"}Main Endpoints:
/buildings- Building management/rooms- Room availability and filtering/classes- Class scheduling
- Python 3.8 or higher
- pip (Python package manager)
- Modern web browser (Chrome, Firefox, Safari, Edge)
git clone https://github.com/LLG-Mapper/api.git
cd apiOr clone using GitHub Desktop
Windows
# From api/ directory
scripts\setupmacOS/Linux
# From api/ directory
./scripts/setup.sh # macOS/LinuxWindows
# From api/ directory
scripts\startmacOS/Linux
# From api/ directory
./scripts/start.sh # macOS/LinuxThe API will be available at http://localhost:5000 (development mode).
- Framework: Flask 3.1.2
- ORM: SQLAlchemy 2.0.45
- Database: SQLite (development), configurable for production
- Serialization: Marshmallow 3.21.3
- Migrations: Flask-Migrate with Alembic
- CORS: Flask-CORS 6.0.2
api/
├── app/
│ ├── __init__.py # Flask app factory
│ ├── config.py # Configuration
│ ├── extensions.py # Flask extensions
│ ├── models/ # SQLAlchemy ORM models
│ │ ├── building.py
│ │ ├── room.py
│ │ ├── class_.py
│ │ ├── teacher.py
│ │ ├── group.py
│ │ ├── subject.py
│ │ ├── feature.py
│ │ ├── room_type.py
│ │ └── enums.py
│ ├── schemas/ # Marshmallow validation
│ │ ├── building.py
│ │ ├── room.py
│ │ ├── class_.py
│ │ ├── teacher.py
│ │ ├── group.py
│ │ ├── subject.py
│ │ ├── feature.py
│ │ └── room_type.py
│ ├── routes/ # API endpoints
│ │ ├── buildings.py
│ │ ├── rooms.py
│ │ ├── classes.py
│ │ ├── health.py
│ │ └── __init__.py
│ └── services/ # Business logic
│ └── availability_service.py
├── migrations/ # Database migrations
├── scripts/ # Database setup
├── app.py # Entry point
├── requirements.txt
└── README.md # Project overview (this file)
Main building/campus entity for organizing rooms.
| Field | Type | Constraints |
|---|---|---|
| id | Integer | Primary Key |
| name | String(50) | Unique, Required |
| code | String(3) | Unique, Required |
| floor | Integer | Default: 0 (for uneven grounds) |
Example:
{
"id": 1,
"name": "Victor Hugo",
"code": "VH",
"floor": 1
}Classification of room types (classroom, lab, auditorium, etc.).
| Field | Type | Constraints |
|---|---|---|
| id | Integer | Primary Key |
| name | String(50) | Unique, Required |
| code | String(10) | Unique, Required |
Example:
{
"id": 1,
"name": "Laboratory",
"code": "LAB"
}Room amenities/equipment (projector, whiteboard, computers, etc.).
| Field | Type | Constraints |
|---|---|---|
| id | Integer | Primary Key |
| name | String(50) | Unique, Required |
| code | String(10) | Unique, Required |
Example:
{
"id": 1,
"name": "Projector",
"code": "PROJ"
}Physical classroom or space.
| Field | Type | Constraints |
|---|---|---|
| id | Integer | Primary Key |
| number | Integer | Required |
| name | String(50) | Optional (auto: {building.code}{number}) |
| building_id | Integer | Foreign Key → Building |
| floor | Integer | Required |
| capacity | Integer | Optional |
| is_open | Boolean | Default: true |
| type_id | Integer | Foreign Key → RoomType |
| locationX | Integer | Required (map coordinate) |
| locationY | Integer | Required (map coordinate) |
| sizeX | Integer | Required (map dimension) |
| sizeY | Integer | Required (map dimension) |
Relationships:
- Building (Many-to-One)
- RoomType (Many-to-One)
- Features (Many-to-Many via room_features)
- Classes (One-to-Many)
Example:
{
"id": 1,
"number": 209,
"name": "VH209",
"building": {"id": 1, "name": "Victor Hugo", "code": "VH", "floor": 1},
"floor": 2,
"capacity": 40,
"is_open": true,
"type": {"id": 1, "name": "Classroom", "code": "CLASS"},
"location": [130, 47],
"size": [60, 40],
"features": [
{"id": 1, "name": "Projector", "code": "PROJ"},
{"id": 2, "name": "Whiteboard", "code": "WBOARD"}
]
}Academic subject (Math, French, Physics, etc.).
| Field | Type | Constraints |
|---|---|---|
| id | Integer | Primary Key |
| name | String(50) | Unique, Required |
| code | String(10) | Unique, Required |
| color | Enum(Color) | Default: BLUE |
Color Options: BLUE, GREEN, RED, YELLOW, PURPLE, ORANGE, GRAY
Example:
{
"id": 1,
"name": "Mathematics",
"code": "MATH",
"color": "BLUE"
}Instructor information.
| Field | Type | Constraints |
|---|---|---|
| id | Integer | Primary Key |
| name | String(50) | Required |
| surname | String(50) | Required |
| gender | Boolean | Required (true=F, false=M) |
| subject_id | Integer | Foreign Key → Subject (Optional) |
Relationships:
- Subject (Many-to-One)
- Classes (One-to-Many)
Example:
{
"id": 1,
"name": "Michel Dupont",
"surname": "Dupont",
"gender": false,
"subject": {"id": 1, "name": "Mathematics", "code": "MATH", "color": "BLUE"}
}Note: Response includes formatted name with gender prefix (
M/Mme.)
Student class/cohort.
| Field | Type | Constraints |
|---|---|---|
| id | Integer | Primary Key |
| name | String(50) | Required |
| grade | Enum(Grade) | Required |
Grade Options:
10= 2nde (Grade 10)11= 1ère (Grade 11)12= Terminale (Grade 12)13= CPGE 1 (Grade 13)14= CPGE 2 (Grade 14)
Example:
{
"id": 1,
"name": "2nd-1",
"grade": 10
}Scheduled class session.
| Field | Type | Constraints |
|---|---|---|
| id | Integer | Primary Key |
| room_id | Integer | Foreign Key → Room (Required) |
| teacher_id | Integer | Foreign Key → Teacher (Required) |
| group_id | Integer | Foreign Key → Group (Required) |
| subject_id | Integer | Foreign Key → Subject (Required) |
| start_date | Date | Required |
| end_date | Date | Optional (NULL = one-off session) |
| start_time | Time | Required |
| end_time | Time | Required |
| recurrence | Enum(Frequency) | Default: WEEKLY |
| weekday | Integer | 0=Monday, 6=Sunday (optional) |
Weekdays 0 = Monday ... 6 = Sunday
Recurrence Options:
ONCE= One-time sessionWEEKLY= Every weekWEEK_A= Alternating week AWEEK_B= Alternating week B
Relationships:
- Room (Many-to-One)
- Teacher (Many-to-One)
- Group (Many-to-One)
- Subject (Many-to-One)
Example:
{
"id": 1,
"room": {...},
"teacher": {...},
"group": {...},
"subject": {...},
"start_date": "2024-01-15",
"end_date": "2024-06-30",
"start_time": "09:00:00",
"end_time": "10:00:00",
"recurrence": "WEEKLY",
"weekday": 0
}Active Endpoints:
-
GET /health
-
GET /buildings- List all buildingsGET /buildings/{id}- Get building by IDPOST /buildings- Create buildingPUT /buildings/{id}- Update buildingDELETE /buildings/{id}- Delete building
-
GET /rooms- List rooms (with filtering & availability)GET /rooms/{id}- Get room by IDPOST /rooms- Create roomPUT /rooms/{id}- Update roomDELETE /rooms/{id}- Delete room
-
GET /classes- List classesGET /classes/{id}- Get class by IDPOST /classes- Create classPUT /classes/{id}- Update classDELETE /classes/{id}- Delete class
Planned Endpoints (Coming Soon):
-
Room Types
GET /room-types- List room typesPOST /room-types- Create room type
-
Features
GET /features- List featuresPOST /features- Create feature
-
Teachers
GET /teachers- List teachersGET /teachers/{id}- Get teacher by IDPOST /teachers- Create teacher
-
Groups
GET /groups- List groupsPOST /groups- Create group
GET /healthResponse (200 OK):
{
"status": "ok"
}GET /buildingsResponse (200 OK):
[
{
"id": 1,
"name": "Victor Hugo",
"code": "VH",
"floor": 1
}
]GET /buildings/{id}POST /buildings
Content-Type: application/json
{
"name": "Molière",
"code": "M",
"floor": 0
}Response (201 Created):
{
"id": 1,
"name": "Molière",
"code": "M",
"floor": 0
}PUT /buildings/{id}
Content-Type: application/json
{
"floor": 1
}DELETE /buildings/{id}Response (204 No Content)
GET /rooms?building_id=1&floor=2&feature_codes=PROJ,WBOARD&is_available=true&availability_at=2024-01-15T09:00:00Query Parameters:
| Parameter | Type | Description |
|---|---|---|
| building_id | integer | Filter by building |
| floor | integer | Filter by floor number |
| feature_codes | string[] | Filter by features (comma-separated codes) |
| is_available | boolean | Filter by availability status |
| availability_at | ISO datetime | Check availability at specific time |
Response (200 OK):
[
{
"id": 1,
"number": 209,
"name": "VH209",
"building": {...},
"floor": 2,
"capacity": 40,
"is_open": true,
"type": {...},
"location": [130, 47],
"size": [60, 40],
"features": [...]
}
]Or with availability:
{
"availability_at": "2024-01-15T09:00:00",
"rooms": [...]
}GET /rooms/{id}POST /rooms
Content-Type: application/json
{
"number": 209,
"name": "VH209",
"building_id": 1,
"floor": 2,
"capacity": 40,
"is_open": true,
"type_id": 1,
"locationX": 130,
"locationY": 47,
"sizeX": 60,
"sizeY": 40,
"feature_ids": [1, 2]
}Response (201 Created):
{
"id": 1,
"number": 209,
"name": "VH209",
...
}PUT /rooms/{id}
Content-Type: application/json
{
"capacity": 45,
"is_open": false,
"feature_ids": [1, 3]
}DELETE /rooms/{id}Response (204 No Content)
GET /classesResponse (200 OK):
[
{
"id": 1,
"room": {...},
"teacher": {...},
"group": {...},
"subject": {...},
"start_date": "2024-01-15",
"end_date": "2024-06-30",
"start_time": "09:00:00",
"end_time": "10:00:00",
"recurrence": "WEEKLY",
"weekday": 0
}
]GET /classes/{id}POST /classes
Content-Type: application/json
{
"room_id": 1,
"teacher_id": 1,
"group_id": 1,
"subject_id": 1,
"start_date": "2024-01-15",
"end_date": "2024-06-30",
"start_time": "09:00:00",
"end_time": "10:00:00",
"recurrence": "WEEKLY",
"weekday": 0
}Response (201 Created):
{
"id": 1,
...
}PUT /classes/{id}
Content-Type: application/json
{
"start_time": "10:00:00",
"end_time": "11:00:00"
}DELETE /classes/{id}Response (204 No Content)
All endpoints return validation errors with detailed messages:
POST /buildings
Content-Type: application/json
{
"name": "Test"
}Response (400 Bad Request):
{
"errors": {
"code": ["Missing data for required field."]
}
}- Dates: ISO format
YYYY-MM-DD - Times: ISO format
HH:MM:SS - DateTime: ISO format
YYYY-MM-DDTHH:MM:SS
Room coordinates are returned as arrays:
{
"location": [130, 47], // [X, Y]
"size": [60, 40] // [width, height]
}ONCE - "once"
WEEKLY - "weekly"
WEEK_A - "weekA"
WEEK_B - "weekB"
BLUE
GREEN
RED
YELLOW
PURPLE
ORANGE
GRAY
10 → 2nde (Grade 10)
11 → 1ère (Grade 11)
12 → Terminale (Grade 12)
13 → CPGE 1 (Grade 13)
14 → CPGE 2 (Grade 14)
# Create new migration
flask db migrate -m "Description"
# Apply migrations
flask db upgrade
# Rollback
flask db downgradeAll POST/PUT requests are validated using Marshmallow schemas:
- Type checking
- Required field validation
- Relationship integrity
Responses automatically handle:
- Enum value conversion
- Datetime/Date/Time formatting
- Nested relationship serialization
- Field inclusion/exclusion based on context
For issues or questions about the API or project setup, please refer to the main project README or open an issue on the repository.
This project is licensed under the MIT License. See the LICENSE file for details.