Backend Documentation
[TOC]
Docker
Dev
We mount the whole directory under /app so we can reflect changes of the db to local computer for better debugging.
The database backend is SQLite (/tmp/db.sqlite3). It is in the /tmp directory in the container and it will be removed when the container exits.
The ldap container creates ldap users (username, password):
ta217, ta217
thisway, hachu
chdir, plateau
user1, pw1
user2, pw2
…
user100, pw100
The cspace group is created and ta217 is added to it by default when the container starts.
The list of default groups (name[, description]) created on startup are as below:
cspace
faculty, gidNumber = 100
lab208
lab301
...
The full list is at docs/default-groups.txt. The default groups, which are groups that had permissions to make registrations in the old system, are filtered from the original group list (by hand).
To start the development server:
cd into
cspace-backendcreate a file
.env
DB_USER=[enter username]
DB_PASSWORD=[enter password]
DJANGO_SECRET_KEY=[enter anything e.g. your-secret-key]
Then execute:
docker compose -f docker-compose.yml -f docker-compose.dev.yml build --no-cache
docker compose -f docker-compose.yml -f docker-compose.dev.yml up
To stop:
cd into cspace-backend
docker compose -f docker-compose.yml -f docker-compose.dev.yml down
Production
We should not mount the whole directory under /app. Instead, we should COPY all the necessary files into the image when building.
To start the production server:
cd into cspace-backend
docker compose build --no-cache
docker compose up
To stop:
cd into cspace-backend
docker compose down
The .env file should also include
DJANGO_ALLOWED_HOSTS=[production machine ip],localhost,127.0.0.1
Note: We don’t create the cspace group and the ta217 user on startup. They are imported manually through the adminer interface.
Note: We don’t create default groups on startup, groups are imported manually from the old db. We should manually remove unused groups from the web interface during setup.
Database Tables & Columns Descriptions
users
User identity and login metadata (authentication identity is LDAP-backed).
id(PK): Internal user identifier.username: Unique login/account name.displayname: Human-readable display name.last_login_time: Last successful login timestamp.last_login_ip: Source IP for the last successful login.created_at: Record creation timestamp.updated_at: Record update timestamp.
groups
Authorization groups used for access control and registration ownership.
id(PK): Group identifier.name: Group name (for examplecspace,faculty).description: Optional group description.created_at: Record creation timestamp.updated_at: Record update timestamp.
user_group
Many-to-many mapping between users and groups, including per-group permission.
id(PK): Membership record identifier.user_id(FK ->users.id): Member user.group_id(FK ->groups.id): Group the user belongs to.permissions: Role in the group (adminormember).created_at: Record creation timestamp.updated_at: Record update timestamp.
classrooms
Classroom master data and bookability flags.
id(PK): Classroom identifier.name: Classroom name.capacity: Maximum number of people.equipment: Equipment description (json).floor: Floor number.require_permission: Whether special permission is required to register.is_deleted: Soft-delete flag.version: Version number for optimistic locking/auditing.is_valid: Validation/availability flag.
draw_events
Defines a draw/lottery window and its booking period.
id(PK): Draw event identifier.event_start_time (Datetime): Start time of booking period.event_end_time (Datetime): End time of booking period.target_start_date: Start date of the allocation window.target_end_date: End date of the allocation window.is_completed: Whether draw processing has completed.is_deleted: Soft-delete flag.created_at: Record creation timestamp.updated_at: Record update timestamp.version: Version number for optimistic locking/auditing.
draw_registrations
Applications submitted into a draw event before final registration creation.
id(PK): Draw registration identifier.draw_event_id(FK ->draw_events.id): Parent draw event.classroom_id(FK ->classrooms.id): Requested classroom.user_id(FK ->users.id): Applicant user.group_id(FK ->groups.id): Applicant group.is_selected: Whether selected by the draw.start_time(integer): Requested start time.Stored as number of seconds since start of the week (every Sunday midnight 00:00).
end_time(integer): Requested end time.Stored as number of seconds since start of the week (every Sunday midnight 00:00).
importance: Priority/importance score.description: Applicant note/details.is_deleted: Soft-delete flag.created_at: Record creation timestamp.updated_at: Record update timestamp.version: Version number for optimistic locking/auditing.
Although start_time and end_time is being stored as integers, which might seem a little bit weird, we decide to follow the same design as the old system for easier data migration. Also, registrations need not to be made from the start of a period to the end of a period. It can be from any time to any time. Moreover, this design allows for better extensibility of the system.
We have considered storing them as start_period, end_period, and day_of_week. But after thorough consideration, we decided to stay the same. The same follows for the table longterm_registrations below.
longterm_registrations
Recurring booking templates (for example weekly recurring reservations).
id(PK): Long-term registration identifier.user_id(FK ->users.id): Owner user.group_id(FK ->groups.id): Owner group.classroom_id(FK ->classrooms.id): Target classroom.start_date: Effective recurrence start date.end_date: Effective recurrence end date.start_time(Datetime): Start time.end_time(Datetime): End time.day_of_week(Chars): Day of week.description: Notes/details.created_at: Record creation timestamp.updated_at: Record update timestamp.version: Version number for optimistic locking/auditing.
Although start_time and end_time are stored as Datetime, we only need the time of the day from it.
registrations
Finalized booking records (single reservations), optionally linked to draw/long-term sources.
id(PK): Registration identifier.user_id(FK ->users.id): Booking owner user.group_id(FK ->groups.id): Booking owner group.classroom_id(FK ->classrooms.id): Reserved classroom.draw_registration_id(FK ->draw_registrations.id, nullable): Source draw registration.longterm_id(FK ->longterm_registrations.id, nullable): Source long-term template.start_time(Datetime): Reservation start timestamp.end_time(Datetime): Reservation end timestamp.importance: Priority/importance value.description: Reservation note/details.is_pending: Approval status flag (true= pending).is_deleted: Soft-delete flag.created_at: Record creation timestamp.updated_at: Record update timestamp.version: Version number for optimistic locking/auditing.
notifications
System notification content.
id(PK): Notification identifier.description: Notification body/content.created_at: Record creation timestamp.updated_at: Record update timestamp.
notification_users
Per-user/group delivery state for notifications.
id(PK): Delivery-state record identifier.notification_id(FK ->notifications.id): Notification reference.user_id(FK ->users.id): Target user.group_id(FK ->groups.id): Related group context.archived: Whether archived by user.new: Whether still marked as unread/new.created_at: Record creation timestamp.updated_at: Record update timestamp.
change_logs
Auditable service logs for actions/changes.
id(PK): Log record identifier.user_id(FK ->users.id): Actor user.group_id(FK ->groups.id): Actor group context.service: Service/module name (for examplelogin,groups).subject: Log subject/category (for exampleok,failed,add,remove).log: Detailed log message/body.created_at: Record creation timestamp.updated_at: Record update timestamp.