susunjadwal-backend - Documentation
| Document Status | ||
|---|---|---|
| Document Owner | Product Engineering 2026 | Product Engineering 2026 |
| Contributors | ||
| Project Links | https://github.com/ristekoss/susunjadwal-backend | https://github.com/ristekoss/susunjadwal-backend |
| Project Links | https://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] |
| Team | Theodore Kevin Himawan | theodore.kevin@ristek.cs.ui.ac.id |
| Team | Ari Darrell Muljono | darrell@ristek.cs.ui.ac.id |
| Team | Grace Karina | gracekarin@ristek.cs.ui.ac.id |
| Team | Yeshua Marco G. Manurung | marco@ristek.cs.ui.ac.id |
π Background
Overviewβ
Susun Jadwal backend provides authentication, course data retrieval, user schedule storage, review submission, and course scraping workflows. The service exists so UI students can sign in with SSO, fetch available courses per major and period, build schedule variants, and request fresh course data when the source data in SIAK changes.
Stakeholdersβ
- Users: UI students and admins
- Upstream Dependencies: UI CAS/SSO, SIAK academic data sources, RabbitMQ, MongoDB
- Downstream Consumers: susunjadwal-frontend
Scope & Boundariesβ
- In Scope: Flask API, MongoDB document models, JWT auth, review moderation, uploader flow, RabbitMQ-based scraping triggers, SSE-based SIAKNG scraping
- Out of Scope: frontend implementation, legacy data migration, and analytics pipelines
βοΈ Architecture & Design
System Diagramβ
Architecture Decisions (ADRs)β
- Language/Framework: Python, Flask, MongoEngine, Pydantic
- Database: MongoDB
- Communication: Synchronous HTTP calls
π»Technical Specifications
API Documentationβ
GET /β
Response 200
{ "message": "susunjadwal is live!" }
GET /reviewβ
Response 200
{ "message": "review feature is up" }
GET /scrape-siak-ng/statusβ
Response 200
{
"message": "SIAK NG scraper service is running",
"version": "1.0"
}
Authenticationβ
POST /auth/β
Request
{ "ticket": "string", "service_url": "string" }
Response 200
{
"user_id": "<mongo_id>",
"major_id": "<mongo_id>",
"token": "<jwt>",
"err": false
}
POST /auth/v2/β
Request
{ "ticket": "string", "service_url": "string" }
Response 200
{
"user_id": "<mongo_id>",
"major_id": "<mongo_id>",
"token": "<jwt>",
"err": false
}
Response 201
{
"user_name": "string",
"full_name": "string",
"completion_id": "<uuid>"
}
POST /auth/completion/β
Request
{
"completion_id": "<uuid>",
"npm": "string",
"kd_org": "string"
}
Response 200
{
"user_id": "<mongo_id>",
"major_id": "<mongo_id>",
"token": "<jwt>",
"err": false
}
GET /auth/meβ
Response 200
{ "message": "token is valid", "token_is_valid": true }
Faculties & Majorsβ
GET /facultiesβ
Response 200
["Faculty A", "Faculty B"]
GET /faculty/<faculty_idx>/majorsβ
Response 200
{ "kd_org": "Major Name" }
Courses & Periodsβ
GET /majors/<kd_org>/courses_by_kdβ
Response 200
{
"name": "2025-2",
"courses": [
{
"name": "string",
"credit": 3,
"classes": [
{
"name": "A",
"schedule_items": [
{
"day": "Mon",
"start": "08.00",
"end": "09.40"
}
]
}
]
}
]
}
GET /majors/<major_id>/all_coursesβ
Response 200
{
"courses": [
{
"name": "string",
"code": "string",
"credit": 3
}
]
}
GET /coursesβ
Response 200
{
"courses": [
{
"name": "string",
"code": "string",
"credit": 3
}
]
}
User Schedulesβ
POST /users/<user_id>/user_scheduleβ
Request
{
"schedule_items": [
{
"name": "Class A",
"day": "Mon",
"start": "08.00",
"end": "09.40"
}
]
}
Response 201
{ "id": "<user_schedule_id>" }
GET /user_schedules/β
Response 200
{
"user_schedule": {
"id": "<id>",
"name": "Schedule 1",
"schedule_items": []
}
}
GET /users/<user_id>/user_schedulesβ
Response 200
{
"user_schedules": [
{
"id": "<id>",
"name": "Schedule 1"
}
]
}
PUT /users/<user_id>/user_schedules/β
Request
{ "schedule_items": [] }
Response 200
{
"user_schedule": {
"id": "<id>",
"name": "Schedule 1"
}
}
POST /users/<user_id>/user_schedules//change_nameβ
Request
{ "name": "New Name" }
Response 200
{ "id": "<id>", "name": "New Name" }
DELETE /users/<user_id>/user_schedules/β
Response 204 Scraping
POST /scrape-scheduleβ
Request
{ "username": "string", "password": "string" }
POST /scrape-siak-ngβ
Request
{ "username": "string", "password": "string" }
Reviewsβ
POST /review/<user_id>β
Request
{ "rating": 5, "comment": "Great app" }
Response 201
{ "message": "Review saved" }
Adminβ
POST /admin/loginβ
Request
{ "username": "string", "password": "string" }
Response 200
{ "token": "<admin_jwt>" }
GET /admin/reviews-overviewβ
Response 200
{
"average_rating": 4.5,
"rating_counts": { "5": 10 }
}
GET /admin/reviews/listβ
Response 200
{
"reviews": [
{
"id": "<id>",
"rating": 5,
"comment": "Great"
}
]
}
PATCH /admin/review/status/β
Request
{ "reviewed": true }
Response 200
{ "id": "<id>", "reviewed": true }
DELETE /admin/review/delete/β
Response 200
{ "message": "Review deleted successfully." }
Data Model/Schemaβ
Project Structureβ
susunjadwal-backend/
βββ .github/
β βββ issue-template.md # issue template for repository contributors
β βββ workflows/
β βββ deploy-prod.yaml # production deployment pipeline
β βββ deploy-staging.yaml # staging deployment pipeline
βββ .dockerignore # Docker build ignore rules
βββ .env.example # example environment variable file
βββ .gitignore # Git ignore rules
βββ app/
β βββ __init__.py # Flask app setup, config, blueprints, Mongo, CORS, Sentry, RabbitMQ init
β βββ cron.py # disabled cron blueprint and scheduled task hooks
β βββ decorators.py # JWT and owner/admin authorization decorators
β βββ exceptions/
β β βββ __init__.py
β β βββ auth.py # authentication-related custom exceptions
β βββ jwt_utils.py # JWT encode/decode helpers
β βββ message_queue.py # RabbitMQ connection/pool helpers
β βββ utils.py # shared Flask-side utility helpers
β βββ services/
β β βββ __init__.py
β β βββ auth/
β β β βββ __init__.py
β β β βββ auth.py # auth v2 and onboarding completion logic
β β βββ scrapper/
β β βββ __init__.py
β β βββ schedule_scrapper.py # RabbitMQ-backed course refresh orchestration
β βββ views/
β βββ __init__.py
β βββ auth.py # auth and metadata endpoints
β βββ main.py # courses and user schedules
β βββ review.py # review submission
β βββ admin.py # admin review moderation
β βββ scraper.py # SSE-based SIAK NG scraping
βββ models/
β βββ __init__.py
β βββ admin.py # admin credential model
β βββ major.py # academic major document
β βββ period.py # period, course, class, and schedule embedded schema
β βββ review.py # user review document
β βββ user.py # user profile and scraping timestamps
β βββ user_schedule.py # saved user schedule document
βββ scraper/
β βββ __init__.py
β βββ credentials.template.json # template credential payload for scraper flows
β βββ main.py # HTML parsing and uploader ingestion helpers
β βββ siak_ng_scraper.py # direct SIAK NG scraping and SSE event formatting
βββ scripts/
β βββ init-mongo.sh # initialize non-root MongoDB user
β βββ launch.sh # local Flask launch entrypoint
β βββ mongo_dump.sh # MongoDB dump helper
β βββ start.sh # alternate server startup script
βββ sso/
β βββ __init__.py
β βββ additional-info.json # major/faculty metadata lookup
β βββ cas.py # CAS client implementation
β βββ faculty-base-additional-info.json # faculty base metadata
β βββ faculty_exchange_route.json # RabbitMQ routing map by faculty
β βββ utils.py # SSO/CAS helper functions
βββ uploader/
β βββ __init__.py
β βββ decorators.py # uploader cookie auth guards
β βββ templates/
β β βββ login.html # uploader login page
β β βββ upload.html # uploader upload form
β βββ utils.py # uploader auth and URL helpers
β βββ views.py # uploader login, logout, and HTML upload endpoints
βββ widgets/
β βββ __init__.py
β βββ flask_pika_mod.py # Flask-Pika integration wrapper
βββ cron.sh # cron/container helper script
βββ Dockerfile # application container build
βββ LICENSE.md # repository license
βββ README.md # contributor and setup guide
βββ TECH_DOC.md # technical documentation
βββ dev.docker-compose.yaml # local MongoDB and RabbitMQ stack
βββ docker-compose.yaml # full local container stack
βββ requirements.txt # Python dependency list
Componentsβ
| Layer | Paths | Responsibility |
|---|---|---|
| App Bootstrap | app/init.py | Initializes Flask configuration, loads SSO metadata files, registers all blueprints, enables CORS, connects to MongoDB, initializes RabbitMQ, and starts background scraping consumer threads. |
| Route Layer | app/views/*.py, uploader/views.py | Exposes HTTP endpoints under /susunjadwal/api, organized by domain including authentication, course catalog, user schedules, reviews, admin moderation, scraping, and uploader workflows. |
| Auth Services | app/services/auth/auth.py, app/jwt_utils.py, app/decorators.py, uploader/decorators.py | Handles CAS-based authentication, JWT generation and validation, onboarding completion flow, role-based access control (user/admin), and uploader cookie authentication. |
| Domain Models | models/*.py | Defines MongoEngine document schemas for admins, users, majors, periods, courses, reviews, and user schedules, including embedded structures for nested data. |
| Scraping Services for SIAKNG | app/services/scrapper/schedule_scrapper.py, scraper/main.py, scraper/siak_ng_scraper.py | Manages course data scraping via RabbitMQ jobs, parses uploaded HTML files, performs SIAK NG scraping, streams progress using SSE, and stores results into Period documents. |
| Messaging and Integration | app/message_queue.py, sso/cas.py, sso/utils.py | Provides RabbitMQ connection handling, CAS client implementation, and SSO utility functions used across services. |
| Review and Admin Workflow | app/views/review.py, app/views/admin.py, models/review.py, models/admin.py | Handles user review submission, computes aggregated ratings, supports paginated review listing, and enables admin moderation including status updates and deletion. |
| Uploader Workflow | uploader/views.py, uploader/utils.py, scraper/main.py | Supports uploader login with whitelist validation, processes HTML uploads, validates period and major, extracts course data, and stores detailed course information for the active period. |
βοΈ Operational Playbook
Infrastructureβ
- Cloud Provider: Pusilkom
- Link: https://api-ulaskelas.ristek.cs.ui.ac.id
Environment Variablesβ
| Key | Description | Default (Dev) | Sensitive? |
|---|---|---|---|
| ACTIVE_PERIOD | Active academic period used for filtering courses (e.g. semester identifier) | 2025-2 | No |
| ADMIN_CREDENTIAL_VERIFICATION | Method or flag used to verify admin privileges | issuperuser | No |
| MONGODB_DB | Name of the MongoDB database used by the backend | backend | No |
| MONGODB_HOST | Hostname or IP address of the MongoDB server | β | Yes |
| MONGODB_PASSWORD | Password for MongoDB authentication | β | Yes |
| MONGODB_PORT | Port used to connect to MongoDB | 27017 | No |
| MONGODB_USERNAME | Username for MongoDB authentication | β | Yes |
| RABBITMQ_ERLANG_COOKIE | Shared secret used by RabbitMQ nodes for clustering | β | Yes |
| RABBIT_HOST | Hostname of the RabbitMQ server | β | Yes |
| RABBIT_PASSWORD | Password for RabbitMQ authentication | β | Yes |
| RABBIT_USERNAME | Username for RabbitMQ authentication | β | Yes |
| SECRET_KEY | Secret key used for JWT signing and application security | β | Yes |
| SENTRY_DSN | Data Source Name for Sentry error tracking service | β | Yes |
| SSO_UI_FORCE_HTTPS | Flag to enforce HTTPS in SSO redirects | TRUE | No |
| UPDATE_COURSE_LIST_EXCHANGE_NAME | Name of RabbitMQ exchange for course list updates | update_course | No |
πQuestions
π List of frequently asked questions or question that need to be answered that is related to this initiative ..