Skip to main content

ulaskelas-backend - Documentation

Document Status
Document OwnerProduct Engineering 2026Product Engineering 2026
Contributors
Project Linkshttps://github.com/ristekoss/ulaskelas-backendhttps://github.com/ristekoss/ulaskelas-backend
Project Linkshttps://api-ulaskelas.ristek.cs.ui.ac.id
https://api-ulaskelas-stg.ristek.cs.ui.ac.id
https://api-ulaskelas.ristek.cs.ui.ac.id
https://api-ulaskelas-stg.ristek.cs.ui.ac.id
Project Links[Monitoring Dashboard][Monitoring Dashboard]
Project Links[API Documentation][API Documentation]
Project Links[Other Related Doc/Link][Other Related Doc/Link]
TeamTheodore Kevin Himawantheodore.kevin@ristek.cs.ui.ac.id
TeamAri Darrell Muljonodarrell@ristek.cs.ui.ac.id
TeamGrace Karinagracekarin@ristek.cs.ui.ac.id
TeamYeshua Marco G. Manurungmarco@ristek.cs.ui.ac.id

πŸ”Ž Background

Overview​

UlasKelas backend provides authenticated access to course information, reviews, bookmarks, discussion features, and GPA calculator data. The main problem it solves is centralizing academic and user-generated data behind a single API so frontend clients can serve course exploration and academic support features consistently.

Stakeholders​

  • Users: UI students
  • Upstream Dependencies: SSO UI
  • Downstream Consumers: UlasKelas frontend

Scope & Boundaries​

  • In Scope: course synchronization, reviews, bookmarks, discussion flows, leaderboard, GPA calculator, authenticated API access
  • Out of Scope: timetable generation, frontend rendering details, legacy data migration

βš™οΈ Architecture & Design

System Diagram​

Architecture Decisions (ADRs)​

  • Language/Framework: Python, Django, Django REST
  • Database: PostgreSQL
  • Communication: synchronous HTTP between frontend, backend, and upstream course provider

πŸ’»Technical Specifications

API Documentation​

GET /ping​

Response 200

"pong"
GET /health-check​

Response 200

{"message":"OK"}
GET /login/​

Response 302

{
"redirect_to":"/token or supplied redirect_url"
}
GET /token/​

Response 200

{
"token":"<drf_token>",
"username":"user123"
}
GET /logout/​

Response 302

{
"redirect_to":"<sso_logout_url>"
}
POST /api-auth-token/​

Request

{
"username":"string",
"password":"string"
}

Response 200

{
"token":"<drf_token>"
}
POST /update-course/​

Response 200

{
"message":"Course updated succeed on 2026-03-23 10:00:00, elapsed time: 2 seconds"
}
GET /api/v1/courses​

Response 200

{
"data":{
"courses":[
{
"id":1,
"code":"CSGE601021",
"name":"String",
"sks":3,
"term":5,
"review_count":10,
"rating_average":4.2
}
]
},
"error":null
}
GET /api/v1/courses/&#123;id&#125;​

Response 200

{
"data":{
"course":{
"id":1,
"code":"CSGE601021",
"name":"String"
}
},
"error":null
}
GET /api/v1/reviews?id=&#123;id&#125;​

Response 200

{
"data":{
"id":1,
"course_code":"CSGE601021",
"content":"Helpful course",
"author":"user123"
},
"error":null
}
GET /api/v1/reviews?page=&#123;page&#125;&course_code=&#123;code&#125;​

Response 200

{
"data":[
{
"id":1,
"course_code":"CSGE601021",
"content":"Helpful course",
"likes_count":4,
"tags":["SERU"]
}
],
"total_page":1,
"error":null
}
GET /api/v1/reviews?page=&#123;page&#125;&by_author=true​

Response 200

{
"data":[
{
"id":1,
"course_code":"CSGE601021",
"content":"Helpful course"
}
],
"total_page":1,
"error":null
}
POST /api/v1/reviews​

Request

{
"course_code":"CSGE601021",
"academic_year":"2025/2026",
"semester":1,
"content":"Helpful course",
"is_anonym":false,
"tags":["SERU"]
}

Response 201

{
"data":{
"id":1,
"course_code":"CSGE601021",
"content":"Helpful course"
},
"error":null
}
PUT /api/v1/reviews​

Request

{
"review_id":1,
"content":"Updated review"
}

Response 200

{
"data":{
"id":1,
"content":"Updated review"
},
"error":null
}
DELETE /api/v1/reviews?review_id=&#123;id&#125;​

Response 200

{
"data":{
"review_id":1,
"is_active":false
},
"error":null
}
GET /api/v1/ds-reviews​

Response 200

{
"data":[
{
"id":1,
"content":"Helpful course"
}
],
"error":null
}
POST /api/v1/ds-reviews​

Request

[
{
"id":1,
"sentimen":1,
"hate_speech_status":"APPROVED"
}
]

Response 200

{
"data":[
{
"id":1,
"hate_speech_status":"APPROVED"
}
],
"error":null
}
POST /api/v1/likes​

Request

{
"review_id":1,
"is_like":true
}

Response 200

{
"data":{
"review_id":1,
"is_like":true
},
"error":null
}
GET /api/v1/bookmarks​

Response 200

{
"data":[
{
"user":"user123",
"course_id":1,
"course_code":"CSGE601021",
"course_name":"String"
}
],
"error":null
}
POST /api/v1/bookmarks​

Request

{
"course_code":"CSGE601021",
"is_bookmark":true
}

Response 200

{
"data":{
"course_code":"CSGE601021",
"is_bookmark":true
},
"error":null
}
GET /api/v1/tags​

Response 200

{
"data":{
"tags":["SERU","JELAS"]
},
"error":null
}
POST /api/v1/tags​

Request

{
"tags":["seru","jelas"]
}

Response 200

{
"data":{
"tags":["SERU","JELAS"]
},
"error":null
}
DELETE /api/v1/tags​

Request

{
"tags":["seru"]
}

Response 200

{
"data":{
"tags":["SERU"]
},
"error":null
}
GET /api/v1/account​

Response 200

{
"data":{
"username":"user123",
"study_program":"Ilmu Komputer"
},
"error":null
}
GET /api/v1/leaderboard​

Response 200

{
"data":[
{
"username":"user123",
"likes_count":42,
"generation":"2022"
}
],
"error":null
}
GET /update-leaderboard/​

Response 200

{
"message":"Leaderboard updated succeed on 2026-03-23 10:00:00, elapsed time: 1 seconds"
}
GET /api/v1/calculator-gpa​

Response 200

{
"data":{
"all_semester_gpa":[],
"cumulative_gpa":{
"cumulative_gpa":0.0,
"total_sks":0
},
"courses":[]
},
"error":null
}
POST /api/v1/calculator-gpa​

Request

{
"given_semesters":["Semester 5","Semester 6"]
}

Response 201

{
"data":[
{
"pk":1,
"given_semester":"Semester 5",
"total_sks":0,
"semester_gpa":0.0,
"semester_mutu":0.0
}
],
"error":null
}
GET /api/v1/calculator-gpa/&#123;given_semester&#125;​

Response 200

{
"data":{
"pk":1,
"given_semester":"Semester 5",
"total_sks":6,
"semester_gpa":3.5,
"semester_mutu":21.0
},
"error":null
}
DELETE /api/v1/calculator-gpa/&#123;given_semester&#125;​

Response 200

{
"data":{
"given_semester":"Semester 5",
"deleted":true
},
"error":null
}
GET /api/v1/course-semester?given_semester=Semester%205​

Response 200

{
"data":{
"semester":{
"pk":1,
"given_semester":"Semester 5",
"total_sks":6,
"semester_gpa":3.5,
"semester_mutu":21.0
},
"courses_calculator":[
{
"id":1,
"course_id":10,
"course_name":"String",
"course_sks":3,
"total_score":85.0,
"total_percentage":100.0
}
]
},
"error":null
}

Data Model/Schema​

https://drive.google.com/file/d/1w8n4m_3daoie64Aly3Emxl7NyGBe1esy/view?usp=sharing

Project Structure​

ulaskelas-backend/
β”œβ”€β”€ __init__.py # package marker
β”œβ”€β”€ asgi.py # ASGI entrypoint
β”œβ”€β”€ settings.py # default Django settings
β”œβ”€β”€ settings_heroku.py # deployment settings override for Heroku-style runtime
β”œβ”€β”€ urls.py # root URL router
└── wsgi.py # WSGI entrypoint and background job bootstrap
main/
β”œβ”€β”€ __init__.py # package marker
β”œβ”€β”€ admin.py # Django admin registrations
β”œβ”€β”€ apps.py # app config
β”œβ”€β”€ decorators.py # app-level decorators
β”œβ”€β”€ fasilkom_courses.py # static recommended course grouping for GPA auto-fill
β”œβ”€β”€ models.py # core relational data model
β”œβ”€β”€ serializers.py # serializers for course, review, account, GPA, and Tanya Teman payloads
β”œβ”€β”€ urls.py # API endpoint registration under /api/v1 and /api/v2
β”œβ”€β”€ utils.py # response helpers, validation, GPA math, pagination, and profile bootstrap
β”œβ”€β”€ views.py # ping, health, login, logout, bookmarks, tags, account, leaderboard, manual sync
β”œβ”€β”€ views_calculator.py # calculator and score-component CRUD
β”œβ”€β”€ views_course.py # course listing, filtering, fuzzy search, and detail retrieval
β”œβ”€β”€ views_gpa_calculator.py # GPA planner, course-semester, course-component, and subcomponent logic
β”œβ”€β”€ views_review.py # review CRUD and DS moderation endpoints
β”œβ”€β”€ views_tanyateman.py # question, answer, like, upload, and notification flows
β”œβ”€β”€ migrations/
β”‚ β”œβ”€β”€ 0001_initial.py # initial schema
β”‚ β”œβ”€β”€ ... # schema evolution for GPA, Tanya Teman, and likes
β”‚ └── 0026_auto_20251113_1512.py
└── tests/
β”œβ”€β”€ __init__.py
β”œβ”€β”€ test_model.py # model tests
└── test_serializer.py # serializer tests
courseUpdater/
β”œβ”€β”€ __init__.py # package marker
β”œβ”€β”€ courseApi.py # fetches and upserts course catalog from SUNJAD_BASE_URL
└── updater.py # APScheduler job definition for periodic course sync
leaderboard_updater/
β”œβ”€β”€ __init__.py # package marker
└── updater.py # recomputes likes leaderboard values on Profile
live_config/
β”œβ”€β”€ __init__.py # package marker
β”œβ”€β”€ admin.py # admin registration for live config models
β”œβ”€β”€ apps.py # app config
β”œβ”€β”€ models.py # persisted config model definitions
β”œβ”€β”€ utils.py # config helper utilities
β”œβ”€β”€ views.py # runtime config accessors used by serializers and filters
β”œβ”€β”€ migrations/
β”‚ β”œβ”€β”€ 0001_initial.py # initial live config schema
β”‚ └── __init__.py
└── defaultConfig/
β”œβ”€β”€ course_prefixes.json # code prefix to label mapping
β”œβ”€β”€ cs_course_code_map.json # course code mapping for CS-related logic
β”œβ”€β”€ kd_org.json # organization code mapping
└── study_program.json # study program to course prefix mapping
sso/
β”œβ”€β”€ __init__.py # SSO defaults including base CAS config
β”œβ”€β”€ cas.py # CAS client implementation
β”œβ”€β”€ decorators.py # SSO decorator used by login flow
└── utils.py # protocol, redirect, and logout helper utilities
Dockerfile # container build definition
docker-compose.yml # local compose stack
docker-compose-prod.yml # prod-like compose stack
deployment.sh # deployment helper script
manage.py # Django management entrypoint
requirements.txt # Python dependencies
sample.env # sample environment variables
README.md # repository readme and tech doc
pull_request_template.md # pull request template

Components​

LayerPathsResponsibility
App BootstrapUlasKelas/settings.py, UlasKelas/urls.py, UlasKelas/wsgi.py, UlasKelas/asgi.pyInitializes Django configuration, registers root URL routing, and defines entrypoints for HTTP serving and background processes.
Route Layermain/views.py, main/views_course.py, main/views_review.py, main/views_calculator.py, main/views_gpa_calculator.py, main/urls.py, live_config/views.pyExposes HTTP endpoints, organized by domain including authentication, course catalog, reviews, bookmarks, leaderboard, GPA planner, Tanya Teman, and live configuration.
Auth Servicesmain/views.py, main/utils.py, main/decorators.py, sso/cas.py, sso/decorators.py, sso/utils.pyHandles CAS-based authentication, token generation, session validation, redirect handling, and first-time user profile initialization.
Domain Modelsmain/models.py, live_config/models.pyDefines relational database schemas for profiles, courses, reviews, bookmarks, likes, GPA planning entities, Tanya Teman content, and configuration data.
Course Sync ServicescourseUpdater/courseApi.py, courseUpdater/updater.pyFetches course data from Susun Jadwal, performs upsert operations into the Course model, and provides scheduled synchronization logic.
Review and Community Workflowmain/views_review.py, main/views.py, main/views_tanyateman.py, main/serializers.py, main/models.pyHandles review submission, likes, tags, bookmarks, leaderboard retrieval, Tanya Teman questions and answers, optional image uploads, and notification flows.
GPA Planner and Score Calculationmain/views_gpa_calculator.py, main/views_calculator.py, main/utils.py, main/models.pyManages semester planning, course selection, score calculators, weighted components, subcomponent scoring, and cumulative GPA computation.
Integration & Messagesso/cas.py, sso/utils.py, live_config/defaultConfig/*Provides CAS integration, SSO utilities, and static configuration datasets for course labeling and study program mapping.
Background Jobs for Leaderboardleaderboard_updater/updater.py, courseUpdater/updater.pyHandles scheduled leaderboard recalculation and periodic course synchronization.

☁️ Operational Playbook

Infrastructure​

Environment Variables​

KeyDescriptionDefault (Dev)Sensitive?
ACCESS_KEY_IDAWS access key ID used to authenticate requests to AWS servicesβ€”Yes
ACCESS_KEY_SECRETAWS secret access key used for secure authentication with AWS servicesβ€”Yes
AWS_REGIONAWS region where services (e.g. S3) are hostedap-southeast-1No
AWS_S3_FOLDER_PREFIXPrefix or folder path used to organize files in the S3 bucketproductionNo
BUCKET_NAMEName of the AWS S3 bucket used for file storageristek-ulaskelasNo
DEBUGFlag to enable or disable debug mode in the applicationFALSENo
DJANGO_SETTINGS_MODULESpecifies the Django settings module used by the applicationUlasKelas.settingsNo
EMAIL_HOST_PASSWORDPassword used for authenticating the email service accountβ€”Yes
EMAIL_HOST_USEREmail address used as the sender for outgoing emailsnoreply@ristek.cs.ui.ac.idNo
NOTIFICATION_RECIPIENT_
EMAIL
Email address that receives system notifications or alertstemankuliah.ristek@gmail.comNo
POSTGRES_DBName of the PostgreSQL database used by the applicationulaskelas_backend_prodNo
POSTGRES_HOSTHostname or IP address of the PostgreSQL database serverβ€”Yes
POSTGRES_PASSWORDPassword for PostgreSQL database authenticationβ€”Yes
POSTGRES_PORTPort used to connect to the PostgreSQL database5432No
POSTGRES_USERUsername for PostgreSQL database authenticationβ€”Yes
PYTHONPATHPath configuration for Python module resolution./envNo
SECRET_KEYSecret key used for cryptographic signing and security in Djangoβ€”Yes
SENTRY_DSNData Source Name used for sending error logs to Sentryβ€”Yes
SUNJAD_BASE_URLBase URL for the SusunJadwal API servicehttps://api.susunjadwal.cs.ui.ac.idNo
ULASKELAS_ADMIN_LINKURL endpoint for accessing the UlasKelas admin dashboardhttps://api-ulaskelas.ristek.cs.ui.ac.id/admin/loginNo
ULASKELAS_ANSWER_LINKRelative path for accessing answer management in admin panel/admin/main/answerNo
ULASKELAS_QUESTION_LINKRelative path for accessing question management in admin panel/admin/main/questionNo

πŸ™‹Questions

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