.. SPDX-License-Identifier: GPL-3.0-or-later ============================= Backend Architecture Overview ============================= Author: Zhenyu Yang Last updated: Apr 24, 2026 This document describes the shared structure and cross-module constraints of the Django backend. For specific business rules, see the corresponding app pages. Directory Structure ------------------- .. code:: text backend/ ├── apps/ │ ├── accounts/ │ ├── classrooms/ │ ├── courses/ │ ├── signage/ │ ├── checkins/ │ ├── borrowings/ │ ├── repairs/ │ ├── abuse/ │ └── logs/ ├── classroom_manager/ │ ├── settings/ │ └── urls.py ├── common/ ├── services/ └── manage.py Configuration & Runtime ----------------------- - The default settings module is ``classroom_manager.settings.base``; ``manage.py``, ``wsgi.py``, and ``asgi.py`` all point directly to it. - The database defaults to MySQL; connection parameters come from ``MYSQL_*`` environment variables. - The default language is ``zh-hans``; the default timezone is ``Asia/Shanghai``. - REST Framework requires authentication by default; the default pagination class is ``common.pagination.DefaultPagination`` with a max page size of 200. - Login throttling uses ``LOGIN_THROTTLE_RATE``, defaulting to ``5/minute``. - The upload directory defaults to ``LOCAL_UPLOAD_DIR=/data/uploads``; the access prefix defaults to ``/media/uploads/``. Global Routing -------------- - Django admin entry: ``/django-admin/`` - Business API common prefix: ``/api/v1/`` - The root URL configuration is defined in ``backend/classroom_manager/urls.py``. - Routes are organized in two ways: - DRF ``router.register(...)`` manages standard resources such as ``users``, ``classrooms``, ``borrow``, and ``courses``. - ``path(...)`` manages standalone actions such as authentication, uploads, system config, and signage activation. Authentication Model -------------------- - Default authentication classes: - ``apps.accounts.authentication.CookieJWTAuthentication`` - ``rest_framework.authentication.SessionAuthentication`` - After successful email or WebAuthn login on the web, tokens are returned and ``token``, ``refresh_token``, ``logged_in``, and ``csrftoken`` cookies are set. - The WeChat mini program login does not use cookies; it returns access/refresh tokens in the response body. - ``CookieJWTAuthentication`` reads the ``Authorization`` header first, then falls back to the ``token`` cookie. - The user’s active role ``current_role`` is not persisted; it comes from the JWT claim or the ``X-Current-Role`` request header. Middleware validates that it exists in ``user.roles``. - Signage devices do not use user JWTs; they use ``apps.signage.authentication.SignageDeviceAuthentication`` with the header format ``Authorization: Bearer ``. Cross-Module Dependencies ------------------------- - ``courses`` provides the source of truth for classroom schedules; ``classrooms``, ``signage``, ``borrowings``, and ``checkins`` all depend on ``CourseOccurrence``. - ``borrowings`` conflict detection checks both manual reservations and course occupancy. - ``checkins`` anchors ``CheckinSession`` creation to ``CourseOccurrence``. - ``common.SystemConfig`` provides seasonal schedules and semester start dates to ``courses``. - ``logs`` is reused across business modules via ``OperationLogContextMiddleware`` and ``log_operation()``. Responses & Pagination ---------------------- - Two response styles coexist in the project: - The ``{code, message, data}`` wrapper from ``common.responses.success/error`` - DRF’s default pagination or serializer responses - Most custom actions use the unified wrapper. - Endpoints that rely on the default ``ModelViewSet.list/retrieve/update`` implementation may return DRF’s native structure. - During frontend-backend integration, do not assume all endpoints uniformly return ``{code, message, data}``. Middleware & Shared Capabilities -------------------------------- - ``apps.logs.utils.OperationLogContextMiddleware`` - Stores the current request in a ``ContextVar``, making it available to the service layer for logging. - ``apps.accounts.middleware.CurrentRoleMiddleware`` - Resolves the active role from the JWT or ``X-Current-Role`` header. - ``common.middleware.request_timezone.RequestTimezoneMiddleware`` - Switches the current request timezone based on the ``X-Timezone`` header. Current Implementation Caveats ------------------------------ - The log permission class ``apps.logs.permissions.IsLogAdmin`` still reads the legacy ``user.role`` field, so non-Django ``is_superuser/is_staff`` accounts typically cannot reliably access log endpoints. - ``services/file_storage.py`` already has a local/S3 dual-backend abstraction, but ``common.views.upload_file`` still writes directly to the local filesystem. - Signage already has independent device authentication, but it is currently used only for information display and is not integrated into the check-in write flow.