Skip to main content

Ristek Tutor Backend - Documentation

πŸ”Ž Background

Overview​

Ristek Tutor Kelas is a peer tutoring platform backend that connects UI students seeking academic help (tutees) with qualified student tutors. The service handles user registration via UI SSO, tutor applications with course score verification, session scheduling and availability management, booking with payment proof uploads, session rescheduling flows, and post-session logging with admin verification and payment tracking.

Stakeholders​

  • Users: UI students (tutees), student tutors, admin/panitia (session log verification & payment)
  • Upstream Dependencies: UI SSO CAS (https://sso.ui.ac.id/cas2), MinIO/S3 (file storage for profile pictures, payment proofs, log proofs)
  • Downstream Consumers: Ristek Tutor Kelas Frontend

Scope & Boundaries​

  • In Scope: User authentication (SSO JWT, SSO CAS ticket, dev login), user profile management, tutor application & approval workflow, tutor session CRUD, tutee booking with payment proof, session rescheduling (request + confirm), tutor log submission with proof, admin log verification/rejection/payment marking, mata kuliah management, file uploads to S3/MinIO.
  • Out of Scope: Frontend application, payment gateway integration, notification/email system, advanced scheduling algorithms.

βš™οΈ Architecture & Design

System Diagram​

Architecture Decisions (ADRs)​

  • Language/Framework: Python 3.11 / Django 5.2.4 / Django REST Framework 3.16.0
  • Database: SQLite3 (default; libpq-dev installed in Docker for potential PostgreSQL migration)
  • Authentication: SimpleJWT 5.5.0 with custom token serializer (30-day access token lifetime), SSO UI integration via CAS v2 client and JWT verification
  • File Storage: S3-compatible storage via MinIO + django-storages (boto3/S3Boto3Storage) for profile pictures, payment proofs, and log proofs
  • API Documentation: drf-spectacular 0.28.0 (OpenAPI 3.0 schema with Swagger UI and ReDoc)
  • Communication: Synchronous RESTful API over HTTP
  • Static Files: WhiteNoise for serving Django admin and DRF static assets
  • CORS: django-cors-headers with configurable allowed origins

πŸ’»Technical Specifications

API Documentation​

The application auto-generates OpenAPI specs via drf-spectacular. Interactive documentation is available at: Swagger UI: /api/schema/swagger-ui/ ReDoc: /api/schema/redoc/ Raw Schema: /api/schema/

User Endpoints (/user/)​

MethodPathAuthDescription
POST/user/sso/login/β€”SSO JWT login (accepts sso_token, returns JWT access + refresh)
POST/user/sso/callback/β€”SSO CAS ticket validation (accepts ticket + service, returns JWT)
POST/user/login/β€”Dev login with username/password (returns JWT access + refresh)
GET/user/me/JWTGet current user profile
PATCH/user/update_profile/JWTUpdate user profile (onboarding; marks is_complete)
PUT/user/tutor_profile/JWTUpdate tutor profile (tutor only)
POST/user/apply/JWTApply to become a tutor (with course scores)
GET/user/tutors/JWTList all tutors
POST/user/course_score_info/JWTCreate course score entry for tutor

Tutor Session Endpoints (/tutor-session/)​

MethodPathAuthDescription
GET/tutor-session/sessions/JWTList available sessions (filterable by matkul, tutor, date range)
GET/tutor-session/matkul/JWTList all mata kuliah
POST/tutor-session/create-session/JWTCreate a new tutor session
GET/tutor-session/my-sessions/JWTList own sessions (as tutor or tutee)
GET/tutor-session/my-sessions/<pk>/JWTGet session detail
PUT/tutor-session/my-sessions/<pk>/JWTUpdate session (meeting link, resources, status)
DELETE/tutor-session/my-sessions/<pk>/JWTCancel session
POST/tutor-session/availability/JWTCreate tutor availability slot
GET/tutor-session/tutee/sessions/JWTList tutee's booked sessions
GET/tutor-session/tutee/sessions/<pk>/JWTGet tutee session detail
PUT/tutor-session/tutee/sessions/<pk>/JWTUpdate booking (session type, emails)
PATCH/tutor-session/tutee/sessions/<pk>/emails/JWTUpdate booking participant emails
POST/tutor-session/tutee/book/<pk>/JWTBook a session (with payment proof upload)
POST/tutor-session/tutee/reschedule/request/<pk>/JWTRequest session reschedule
POST/tutor-session/tutee/reschedule/confirm/<pk>/JWTConfirm reschedule with new time slot

Tutor Logs Endpoints (/logs/)​

MethodPathAuthDescription
GET/logs/tutor/logsJWTList tutor's own logs
POST/logs/tutor/logsJWTCreate log (with participant count + image proof)
GET/logs/tutor/logs/<pk>JWTGet log detail
PUT/logs/tutor/logs/<pk>JWTUpdate log
DELETE/logs/tutor/logs/<pk>JWTDelete log (only if pending or rejected)
GET/logs/admin/logsJWT + AdminList all logs (admin view)
GET/logs/admin/logs/<pk>JWT + AdminGet log detail (admin)
PUT/logs/admin/logs/<pk>/verifyJWT + AdminVerify log β†’ set status to approved
PUT/logs/admin/logs/<pk>/payJWT + AdminMark log as paid
PUT/logs/admin/logs/<pk>/rejectJWT + AdminReject log

Admin & Documentation​

MethodPathDescription
*/admin/Django Admin panel
GET/api/schema/OpenAPI 3.0 schema (JSON/YAML)
GET/api/schema/swagger-ui/Swagger UI
GET/api/schema/redoc/ReDoc

Data Model/Schema​

User App​

ModelKey FieldsPurpose
UserProfileuser (OneToOne β†’ auth.User), npm, jurusan (JSON), is_tutor, profile_picture_url (S3 ImageField), batch, line_id, phone_number, default_class_type (Reguler/Teman Belajar), preferred_subjects (M2M β†’ MataKuliah), is_completeStudent profile with onboarding status
TutorProfileuser (OneToOne β†’ auth.User), subjects (M2M β†’ MataKuliah), gpa, is_completeTutor-specific profile
UpgradeToTutorRequestuser (OneToOne β†’ UserProfile), request_date, status (Pending/Approved/Rejected)Tutor application workflow
CourseScoreInfocourse (FK β†’ MataKuliah), score (Float), tutor (FK β†’ TutorProfile)Course score evidence for tutor applications

Tutor Session App​

ModelKey FieldsPurpose
MataKuliahname (unique, max 1024)Course/subject catalog
TutorSessiontutor (FK β†’ TutorProfile), tutee (FK β†’ UserProfile, nullable), session_date, start_time, end_time (computed: +90min), mata_kuliah (FK), meeting_link, resource_link, status, is_rescheduled_session, original_session (FK β†’ self)Tutoring session with lifecycle status
Bookingsession (FK β†’ TutorSession), tutee (FK β†’ UserProfile), name, mata_kuliah (FK), payment_proof (S3 ImageField), session_type (individual/duo/triad/penta/hepta/deca), emails (JSONField)Session booking with payment proof
BookingEmailbooking (FK β†’ Booking), emailLegacy email model (unused; Booking.emails JSONField used instead)
Session statuses: tersedia β†’ telah dipesan β†’ dikonfirmasi β†’ dibookingdireschedulein request reschedule
Session types: individual, duo, triad, penta, hepta, deca

Tutor Logs App​

ModelKey FieldsPurpose
Logtutor_session (OneToOne β†’ TutorSession), participant_count, image_proof_url (S3 ImageField), status (pending/approved/paid/rejected), created_atPost-session log with admin verification workflow
Log statuses: pending (Dalam Peninjauan) β†’ approved (Menunggu Pembayaran) β†’ paid (Sudah Dibayar)rejected (Ditolak)

Project Structure​

ristek-tutor-backend/
β”œβ”€β”€ .github/
β”‚ └── workflows/
β”‚ └── build-and-deploy.yml # Manual deploy to staging/prod via AWS ECR
β”œβ”€β”€ scripts/
β”‚ └── docker-entrypoint.sh # collectstatic β†’ migrate β†’ gunicorn
β”œβ”€β”€ tutorkelas/ # Django project module
β”‚ β”œβ”€β”€ settings.py # Django config (DB, JWT, CORS, MinIO/S3, SSO)
β”‚ β”œβ”€β”€ urls.py # Root URL config (admin, user, sessions, logs, docs)
β”‚ β”œβ”€β”€ wsgi.py # WSGI application
β”‚ └── asgi.py # ASGI application
β”œβ”€β”€ user/ # User & auth Django app
β”‚ β”œβ”€β”€ models.py # UserProfile, TutorProfile, UpgradeToTutorRequest, CourseScoreInfo
β”‚ β”œβ”€β”€ views.py # SSO login, CAS callback, dev login, profile CRUD, tutor application
β”‚ β”œβ”€β”€ serializers.py # DRF serializers + custom JWT token serializer
β”‚ β”œβ”€β”€ urls.py # User route definitions
β”‚ β”œβ”€β”€ admin.py # Django admin registration
β”‚ β”œβ”€β”€ cas_client.py # CAS v2 client for SSO UI ticket verification
β”‚ β”œβ”€β”€ prodi.py # Faculty codes, study program mappings (kd_org)
β”‚ β”œβ”€β”€ management/commands/
β”‚ β”‚ └── fake_profile.py # Management command to generate fake users/tutors (Faker)
β”‚ └── migrations/ # 7 migration files
β”œβ”€β”€ tutor_session/ # Session & booking Django app
β”‚ β”œβ”€β”€ models.py # MataKuliah, TutorSession, Booking, BookingEmail
β”‚ β”œβ”€β”€ views.py # Session CRUD, booking, reschedule request/confirm
β”‚ β”œβ”€β”€ serializers.py # DRF serializers for sessions and bookings
β”‚ β”œβ”€β”€ urls.py # Session route definitions
β”‚ β”œβ”€β”€ admin.py # Django admin registration
β”‚ β”œβ”€β”€ tests.py # Empty test placeholder
β”‚ └── migrations/ # 9 migration files
β”œβ”€β”€ tutor_logs/ # Log & verification Django app
β”‚ β”œβ”€β”€ models.py # Log model (proof + status workflow)
β”‚ β”œβ”€β”€ views.py # Tutor log CRUD, admin verify/pay/reject
β”‚ β”œβ”€β”€ serializers.py # DRF serializers for logs
β”‚ β”œβ”€β”€ urls.py # Log route definitions
β”‚ β”œβ”€β”€ admin.py # Django admin registration
β”‚ β”œβ”€β”€ tests.py # Empty test placeholder
β”‚ └── migrations/ # 4 migration files
β”œβ”€β”€ staticfiles/ # Collected static files (DRF, admin)
β”œβ”€β”€ Dockerfile # Python 3.11-slim, pip install, entrypoint
β”œβ”€β”€ docker-compose.yml # MinIO + backend services
β”œβ”€β”€ .env.example # Environment variable template
β”œβ”€β”€ requirements.txt # Python dependencies (pinned versions)
β”œβ”€β”€ manage.py # Django management script
└── db.sqlite3 # SQLite database file

Components​

LayerPathsResponsibility
User Appuser/Handles all authentication and user management. Provides three login methods: SSO JWT token verification (sso_login), SSO CAS ticket validation via a custom CAS v2 client (sso_cas_callback), and username/password authentication for development (dev_login). All login endpoints return SimpleJWT access + refresh tokens with custom claims (nama, user, npm, jurusan, fakultas). Manages user profiles with onboarding flow (update_user_profile marks is_complete), tutor profiles, tutor application workflow (apply_for_tutor creates UpgradeToTutorRequest + CourseScoreInfo entries), and tutor listing.
CAS Clientuser/cas_client.pyCustom CAS v2 protocol client that validates tickets against the SSO UI CAS server. Parses the XML service validation response using BeautifulSoup to extract user attributes (username, nama, npm, kd_org).
Prodi Mappinguser/prodi.pyMaps UI faculty/study program codes (kd_org) to human-readable faculty and program names. Used during SSO authentication to enrich user profiles.
Tutor Session Apptutor_session/Core scheduling module. Tutors create availability sessions with date, time, and mata kuliah. Tutees browse available sessions (filterable by subject, tutor, date range), book sessions with payment proof uploads, and can request rescheduling. Sessions have an 8-state lifecycle from tersedia through booking, confirmation, rescheduling, to expiry or cancellation. Each session is 90 minutes (computed end_time). Supports multiple session types (individual through deca/10-person groups) with participant email collection.
Tutor Logs Apptutor_logs/Post-session verification system. After a session is completed, tutors submit logs with participant count and image proof. Admins can verify (approve), reject, or mark logs as paid through dedicated endpoints. Logs follow a 4-state workflow: pending β†’ approved β†’ paid, or pending β†’ rejected.
Custom JWT Serializeruser/serializers.pyExtends SimpleJWT's TokenObtainPairSerializer to include custom claims: nama (full name), user (username), npm, jurusan, and fakultas in the JWT payload.
Data Seedinguser/management/commands/fake_profile.pyDjango management command that generates fake users, tutor profiles, and sessions using the Faker library for development/testing purposes.

☁️ Operational Playbook

Infrastructure​

  • Cloud Provider: AWS ECR + Pusilkom instance
  • CI/CD: GitHub Actions (build-and-deploy.yml), manual workflow dispatch for production (stable tag) and staging (latest tag) builds, pushed to AWS ECR (638207107223.dkr.ecr.ap-southeast-1.amazonaws.com/ristek-tutor-backend)
  • Runtime: Gunicorn (2 workers) behind Docker, port configurable via $PORT (default 8000)
  • File Storage: MinIO (S3-compatible), runs alongside backend in Docker Compose (ports 9000/9001)
  • Static Files: WhiteNoise serving collected static assets
  • Database: SQLite3 (volume-mounted db.sqlite3 in Docker Compose)
  • Startup: docker-entrypoint.sh runs collectstatic β†’ migrate β†’ gunicorn

Environment Variables​

(example)

KeyDescriptionDefault (Dev)Sensitive?
DJANGO_SECRET_KEYDjango cryptographic secret keyβ€”Yes
DEBUGDebug mode (True/False)FalseNo
ALLOWED_HOSTSComma-separated allowed hosts*No
CORS_ALLOWED_ORIGINSComma-separated CORS origins (also used for CSRF trusted origins)http://localhost:3000No
SSO_AUTH_HOSTSSO CAS base URLhttps://sso.ui.ac.id/cas2No
SSO_JWT_SECRETSecret key for verifying SSO JWT tokensβ€”Yes
MINIO_STORAGE_ENDPOINTMinIO internal endpointminio:9000No
MINIO_PUBLIC_ENDPOINTMinIO public-facing endpointSame as internalNo
MINIO_STORAGE_ACCESS_KEYMinIO access keyβ€”Yes
MINIO_STORAGE_SECRET_KEYMinIO secret keyβ€”Yes
MINIO_STORAGE_USE_HTTPSUse HTTPS for MinIOfalseNo
MINIO_STORAGE_MEDIA_BUCKET_NAMEMinIO media bucket namemediaNo
MINIO_STORAGE_AUTO_CREATE_MEDIA_POLICYBucket access policypublic-readNo
MINIO_ROOT_USERMinIO root user (Docker Compose)β€”Yes
MINIO_ROOT_PASSWORDMinIO root password (Docker Compose)β€”Yes
MINIO_DEFAULT_BUCKETSDefault buckets to create (Docker Compose)tutorkelasNo
PORTGunicorn bind port8000No

πŸ™‹Questions

πŸ—’ List of frequently asked questions or question that need to be answered that is related to this initiative ..