A microservice for fetching, syncing, and serving academic schedules.
- REST API for schedules, days, teachers, rooms, groups, and disciplines.
- PostgreSQL-backed persistence.
- Flexible configuration via
config.ymland environment variables. - Docker / Docker Compose support.
- Structured logging.
- Schedule sync endpoint.
- Go
1.25+ - Docker and Docker Compose
- PostgreSQL
- Redis
- Clone the repository:
git clone https://github.com/Classflow-Devs/schedule-service.git
cd schedule-service- Copy local configuration:
cp config.example.yml config.yml-
Update
.envandconfig.ymlwith your credentials and settings. -
Run with Docker:
docker network create classflow_network
docker compose --profile prod upBase path used in the Insomnia collection: /api/v2.
Return a list of available disciplines.
Query params
| Parameter | Type | Description | Required |
|---|---|---|---|
group_id |
integer | Filter disciplines by group id. | No |
teacher_id |
integer | Filter disciplines by teacher id. | No |
classroom_id |
integer | Filter disciplines by room id. | No |
q |
string | Search query for discipline name. | No |
limit |
integer | Limits result count. | No |
Status codes
200 OK— request completed successfully.400 Bad Request— invalid path or query parameters.500 Internal Server Error— unexpected server-side error.
Response
Response example
{
"disciplines": [
"Биология",
"География",
"Информатика",
"История",
"Литература"
]
}
Run schedule synchronization.
Request body
- No body.
Status codes
202 Accepted— synchronization request accepted.500 Internal Server Error— synchronization failed to start or process.
Response
Response example
{
"message": "schedule synchronization started",
"status": "accepted"
}
Return all branches with optional search.
Query params
| Parameter | Type | Description | Required |
|---|---|---|---|
q |
string | Search query for name. | No |
limit |
integer | Limits result count. | No |
Status codes
200 OK— request completed successfully.400 Bad Request— invalid query parameters.500 Internal Server Error— unexpected server-side error.
Response
Response example
{
"branches": [
{
"id": 1,
"code": "spb",
"name": "Санкт-Петербургский политехнический университет",
"country": "Россия",
"city": "Санкт-Петербург",
"address": "ул. Политехническая, 29",
"timezone": "Europe/Moscow"
}
]
}
Return a single branch by id.
Path params
| Parameter | Type | Description | Required |
|---|---|---|---|
id |
integer | Branch id. | Yes |
Status codes
200 OK— request completed successfully.400 Bad Request— invalid path parameters.404 Not Found— branch not found.500 Internal Server Error— unexpected server-side error.
Response
Response example
{
"branch": {
"id": 1,
"code": "spb",
"name": "Санкт-Петербургский политехнический университет",
"country": "Россия",
"city": "Санкт-Петербург",
"address": "ул. Политехническая, 29",
"timezone": "Europe/Moscow"
}
}
Return all specialties belonging to a branch.
Path params
| Parameter | Type | Description | Required |
|---|---|---|---|
id |
integer | Branch id. | Yes |
Status codes
200 OK— request completed successfully.400 Bad Request— invalid path parameters.500 Internal Server Error— unexpected server-side error.
Response
Response example
{
"specialties": [
{
"id": 42,
"name": "Информационные системы и программирование",
"level": "СПО-базовый уровень"
}
]
}
Return all faculties belonging to a branch.
Path params
| Parameter | Type | Description | Required |
|---|---|---|---|
id |
integer | Branch id. | Yes |
Status codes
200 OK— request completed successfully.400 Bad Request— invalid path parameters.500 Internal Server Error— unexpected server-side error.
Response
Response example
{
"faculties": [
{
"id": 7,
"uuid": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"name": "Университетский колледж информационных технологий"
}
]
}
Return all faculties with optional search.
Query params
| Parameter | Type | Description | Required |
|---|---|---|---|
q |
string | Search query for name. | No |
limit |
integer | Limits result count. | No |
Status codes
200 OK— request completed successfully.400 Bad Request— invalid query parameters.500 Internal Server Error— unexpected server-side error.
Response
Response example
{
"faculties": [
{
"id": 7,
"uuid": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"name": "Университетский колледж информационных технологий"
}
]
}
Return a single faculty by id.
Path params
| Parameter | Type | Description | Required |
|---|---|---|---|
id |
integer | Faculty id. | Yes |
Status codes
200 OK— request completed successfully.400 Bad Request— invalid path parameters.404 Not Found— faculty not found.500 Internal Server Error— unexpected server-side error.
Response
Response example
{
"faculty": {
"id": 7,
"uuid": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"name": "Университетский колледж информационных технологий"
}
}
Return all specialties with optional search.
Query params
| Parameter | Type | Description | Required |
|---|---|---|---|
q |
string | Search query for name. | No |
limit |
integer | Limits result count. | No |
Status codes
200 OK— request completed successfully.400 Bad Request— invalid query parameters.500 Internal Server Error— unexpected server-side error.
Response
Response example
{
"specialties": [
{
"id": 42,
"name": "Информационные системы и программирование",
"level": "СПО-базовый уровень"
}
]
}
Return a single specialty by id.
Path params
| Parameter | Type | Description | Required |
|---|---|---|---|
id |
integer | Specialty id. | Yes |
Status codes
200 OK— request completed successfully.400 Bad Request— invalid path parameters.404 Not Found— specialty not found.500 Internal Server Error— unexpected server-side error.
Response
Response example
{
"specialty": {
"id": 42,
"name": "Информационные системы и программирование",
"level": "СПО-базовый уровень"
}
}
Return teachers with optional filtering and search.
Query params
| Parameter | Type | Description | Required |
|---|---|---|---|
q |
string | Search query for teacher name. | No |
limit |
integer | Limits result count. | No |
branch_id |
integer | Filters teachers by branch id. | No |
Status codes
200 OK— request completed successfully.400 Bad Request— invalid path or query parameters.500 Internal Server Error— unexpected server-side error.
Response
Response example
{
"teachers": [
{
"id": 1721,
"name": "Абдулаев Руслан Яхьяевич",
"short_name": "Абдулаев Р. Я."
},
{
"id": 1631,
"name": "Авдеева Дарья Антоновна",
"short_name": "Авдеева Д. А."
},
{
"id": 1629,
"name": "Бусыгина Светлана Юрьевна",
"short_name": "Бусыгина С. Ю."
}
]
}
Return a single teacher by id.
Path params
| Parameter | Type | Description | Required |
|---|---|---|---|
id |
integer | Teacher id. | Yes |
Status codes
200 OK— request completed successfully.400 Bad Request— invalid path or query parameters.500 Internal Server Error— unexpected server-side error.
Response
Response example
{
"teacher": {
"id": 1721,
"name": "Абдулаев Руслан Яхьяевич",
"short_name": "Абдулаев Р. Я."
}
}
Return day cards for a teacher schedule.
Path params
| Parameter | Type | Description | Required |
|---|---|---|---|
id |
integer | Teacher id. | Yes |
Query params
| Parameter | Type | Description | Required |
|---|---|---|---|
period |
string | day or week. |
Yes |
date |
string | Anchor date in YYYY-MM-DD format. |
No |
extended |
string / boolean-like | Includes nested couples. Supported examples: y, yes, true, 1. |
No |
Status codes
200 OK— request completed successfully.400 Bad Request— invalid path or query parameters.500 Internal Server Error— unexpected server-side error.
Response
Response example
{
"available_week_date": "2026-03-09",
"previous_week_date": "2026-03-02",
"next_week_date": "2026-03-16",
"days": [
{
"number": 3,
"name": "Среда",
"short_name": "СР",
"month_with_year": "Март",
"date": "2026-03-11",
"couple_count": 2,
"start_couple_number": 2,
"couples": [
{
"number": 2,
"type": "Lecture",
"full_type": "Лекция",
"date": "2026-03-11",
"launch": "",
"discipline": "Основы алгоритмизации и программирования",
"subgroup": 0,
"teacher": "Абдулаев Руслан Яхьяевич",
"short_teacher": "Абдулаев Р. Я.",
"classroom": "13",
"hull": "11",
"start": "10:10",
"end": "11:40",
"groups": "ИСП-202, ИСП-203"
},
{
"number": 3,
"type": "Practice",
"full_type": "Практика",
"date": "2026-03-11",
"launch": "11:50 - 12:10",
"discipline": "Основы алгоритмизации и программирования",
"subgroup": 0,
"teacher": "Абдулаев Руслан Яхьяевич",
"short_teacher": "Абдулаев Р. Я.",
"classroom": "13",
"hull": "11",
"start": "11:50",
"end": "13:40",
"groups": "ИСП-205"
}
]
}
]
}
Return a flat teacher schedule list.
Path params
| Parameter | Type | Description | Required |
|---|---|---|---|
id |
integer | Teacher id. | Yes |
Query params
| Parameter | Type | Description | Required |
|---|---|---|---|
period |
string | day or week. |
Yes |
date |
string | Anchor date in YYYY-MM-DD format. |
No |
Status codes
200 OK— request completed successfully.400 Bad Request— invalid path or query parameters.500 Internal Server Error— unexpected server-side error.
Response
Response example
{
"couples": [
{
"number": 2,
"type": "Lecture",
"full_type": "Лекция",
"date": "2026-03-11",
"launch": "",
"discipline": "Основы алгоритмизации и программирования",
"subgroup": 0,
"teacher": "Абдулаев Руслан Яхьяевич",
"short_teacher": "Абдулаев Р. Я.",
"classroom": "13",
"hull": "11",
"start": "10:10",
"end": "11:40",
"groups": "ИСП-202, ИСП-203"
},
{
"number": 3,
"type": "Practice",
"full_type": "Практика",
"date": "2026-03-11",
"launch": "11:50 - 12:10",
"discipline": "Основы алгоритмизации и программирования",
"subgroup": 0,
"teacher": "Абдулаев Руслан Яхьяевич",
"short_teacher": "Абдулаев Р. Я.",
"classroom": "13",
"hull": "11",
"start": "11:50",
"end": "13:40",
"groups": "ИСП-205"
}
]
}
Return rooms with optional filtering and search.
Query params
| Parameter | Type | Description | Required |
|---|---|---|---|
q |
string | Generic room search query. | No |
number |
string | Exact or partial room number filter. | No |
branch_id |
integer | Filter rooms by branch id. | No |
limit |
integer | Limits result count. | No |
Status codes
200 OK— request completed successfully.400 Bad Request— invalid path or query parameters.500 Internal Server Error— unexpected server-side error.
Response
Response example
{
"classrooms": [
{
"id": 3611,
"number": "17",
"hull": "11"
},
{
"id": 3617,
"number": "17а",
"hull": "11"
}
]
}
Return a single room by id.
Path params
| Parameter | Type | Description | Required |
|---|---|---|---|
id |
integer | Room id. | Yes |
Status codes
200 OK— request completed successfully.400 Bad Request— invalid path or query parameters.500 Internal Server Error— unexpected server-side error.
Response
Response example
{
"classroom": {
"id": 3611,
"number": "17",
"hull": "11"
}
}
Return day cards for a room schedule.
Path params
| Parameter | Type | Description | Required |
|---|---|---|---|
id |
integer | Room id. | Yes |
Query params
| Parameter | Type | Description | Required |
|---|---|---|---|
period |
string | day or week. |
Yes |
date |
string | Anchor date in YYYY-MM-DD format. |
No |
extended |
string / boolean-like | Includes nested couples. Supported examples: y, yes, true, 1. |
No |
Status codes
200 OK— request completed successfully.400 Bad Request— invalid path or query parameters.500 Internal Server Error— unexpected server-side error.
Response
Response example
{
"available_week_date": "2026-03-02",
"previous_week_date": "2026-02-23",
"next_week_date": "2026-03-09",
"days": [
{
"number": 6,
"name": "Суббота",
"short_name": "СБ",
"month_with_year": "Март",
"date": "2026-03-07",
"couple_count": 6,
"start_couple_number": 1,
"couples": [
{
"number": 1,
"type": "Practice",
"full_type": "Практика",
"date": "2026-03-07",
"launch": "",
"discipline": "Информационные технологии",
"subgroup": 0,
"teacher": "Манохин В.В.",
"short_teacher": "Манохин В. В.",
"classroom": "17",
"hull": "11",
"start": "08:30",
"end": "10:00",
"groups": "ИСП-209"
},
{
"number": 2,
"type": "Lecture",
"full_type": "Лекция",
"date": "2026-03-07",
"launch": "",
"discipline": "Информационные технологии",
"subgroup": 0,
"teacher": "Манохин В.В.",
"short_teacher": "Манохин В. В.",
"classroom": "17",
"hull": "11",
"start": "10:10",
"end": "11:40",
"groups": "ИСП-208, ИСП-209"
},
{
"number": 3,
"type": "Practice",
"full_type": "Практика",
"date": "2026-03-07",
"launch": "11:50 - 12:10",
"discipline": "Информационные технологии",
"subgroup": 0,
"teacher": "Манохин В.В.",
"short_teacher": "Манохин В. В.",
"classroom": "17",
"hull": "11",
"start": "11:50",
"end": "13:40",
"groups": "ИСП-207"
},
{
"number": 4,
"type": "Practice",
"full_type": "Практика",
"date": "2026-03-07",
"launch": "",
"discipline": "Информационные технологии",
"subgroup": 0,
"teacher": "Манохин В.В.",
"short_teacher": "Манохин В. В.",
"classroom": "17",
"hull": "11",
"start": "13:50",
"end": "15:20",
"groups": "ИСП-208"
},
{
"number": 5,
"type": "Lecture",
"full_type": "Лекция",
"date": "2026-03-07",
"launch": "",
"discipline": "Информационные технологии",
"subgroup": 0,
"teacher": "Манохин В.В.",
"short_teacher": "Манохин В. В.",
"classroom": "17",
"hull": "11",
"start": "15:40",
"end": "17:10",
"groups": "ИСП-206, ИСП-207"
},
{
"number": 6,
"type": "Practice",
"full_type": "Практика",
"date": "2026-03-07",
"launch": "",
"discipline": "Информационные технологии",
"subgroup": 0,
"teacher": "Манохин В.В.",
"short_teacher": "Манохин В. В.",
"classroom": "17",
"hull": "11",
"start": "17:20",
"end": "18:50",
"groups": "ИСП-206"
}
]
}
]
}
Return a flat room schedule list.
Path params
| Parameter | Type | Description | Required |
|---|---|---|---|
id |
integer | Room id. | Yes |
Query params
| Parameter | Type | Description | Required |
|---|---|---|---|
period |
string | day or week. |
Yes |
date |
string | Anchor date in YYYY-MM-DD format. |
No |
Status codes
200 OK— request completed successfully.400 Bad Request— invalid path or query parameters.500 Internal Server Error— unexpected server-side error.
Response
Response example
{
"couples": [
{
"number": 1,
"type": "Practice",
"full_type": "Практика",
"date": "2026-03-07",
"launch": "",
"discipline": "Информационные технологии",
"subgroup": 0,
"teacher": "Манохин В.В.",
"short_teacher": "Манохин В. В.",
"classroom": "17",
"hull": "11",
"start": "08:30",
"end": "10:00",
"groups": "ИСП-209"
},
{
"number": 2,
"type": "Lecture",
"full_type": "Лекция",
"date": "2026-03-07",
"launch": "",
"discipline": "Информационные технологии",
"subgroup": 0,
"teacher": "Манохин В.В.",
"short_teacher": "Манохин В. В.",
"classroom": "17",
"hull": "11",
"start": "10:10",
"end": "11:40",
"groups": "ИСП-208, ИСП-209"
},
{
"number": 3,
"type": "Practice",
"full_type": "Практика",
"date": "2026-03-07",
"launch": "11:50 - 12:10",
"discipline": "Информационные технологии",
"subgroup": 0,
"teacher": "Манохин В.В.",
"short_teacher": "Манохин В. В.",
"classroom": "17",
"hull": "11",
"start": "11:50",
"end": "13:40",
"groups": "ИСП-207"
},
{
"number": 4,
"type": "Practice",
"full_type": "Практика",
"date": "2026-03-07",
"launch": "",
"discipline": "Информационные технологии",
"subgroup": 0,
"teacher": "Манохин В.В.",
"short_teacher": "Манохин В. В.",
"classroom": "17",
"hull": "11",
"start": "13:50",
"end": "15:20",
"groups": "ИСП-208"
},
{
"number": 5,
"type": "Lecture",
"full_type": "Лекция",
"date": "2026-03-07",
"launch": "",
"discipline": "Информационные технологии",
"subgroup": 0,
"teacher": "Манохин В.В.",
"short_teacher": "Манохин В. В.",
"classroom": "17",
"hull": "11",
"start": "15:40",
"end": "17:10",
"groups": "ИСП-206, ИСП-207"
},
{
"number": 6,
"type": "Practice",
"full_type": "Практика",
"date": "2026-03-07",
"launch": "",
"discipline": "Информационные технологии",
"subgroup": 0,
"teacher": "Манохин В.В.",
"short_teacher": "Манохин В. В.",
"classroom": "17",
"hull": "11",
"start": "17:20",
"end": "18:50",
"groups": "ИСП-206"
}
]
}
Return groups with optional filtering.
Query params
| Parameter | Type | Description | Required |
|---|---|---|---|
limit |
integer | Limits result count. | No |
q |
string | Group name filter. | No |
branch_id |
integer | Filter groups by branch id. | No |
course |
integer | Filter groups by course number. | No |
specialty |
string | Filter groups by specialty. | No |
Status codes
200 OK— request completed successfully.400 Bad Request— invalid path or query parameters.500 Internal Server Error— unexpected server-side error.
Response
Response example
{
"groups": [
{
"id": 31804,
"local_name": "ИСП-206",
"name": "090207-9о-веб-24/1",
"course": 2,
"speciality": "Информационные системы и программирование",
"faculty": "Университетский колледж информационных технологий"
},
{
"id": 31819,
"local_name": "ИСП-202",
"name": "090207-9о-пр-24/1",
"course": 2,
"speciality": "Информационные системы и программирование",
"faculty": "Университетский колледж информационных технологий"
}
]
}
Return a single group by id.
Path params
| Parameter | Type | Description | Required |
|---|---|---|---|
id |
integer | Group id. | Yes |
Status codes
200 OK— request completed successfully.400 Bad Request— invalid path or query parameters.500 Internal Server Error— unexpected server-side error.
Response
Response example
{
"group": {
"id": 31820,
"local_name": "ИСП-203",
"name": "090207-9о-пр-24/2",
"course": 2,
"speciality": "Информационные системы и программирование",
"faculty": "Университетский колледж информационных технологий"
}
}
Return day cards for a group schedule.
Path params
| Parameter | Type | Description | Required |
|---|---|---|---|
id |
integer | Group id. | Yes |
Query params
| Parameter | Type | Description | Required |
|---|---|---|---|
period |
string | day or week. |
Yes |
date |
string | Anchor date in YYYY-MM-DD format. |
No |
extended |
string / boolean-like | Includes nested couples. Supported examples: y, yes, true, 1. |
No |
Status codes
200 OK— request completed successfully.400 Bad Request— invalid path or query parameters.500 Internal Server Error— unexpected server-side error.
Response
Response example
{
"available_week_date": "2026-03-09",
"previous_week_date": "2026-03-02",
"next_week_date": "2026-03-16",
"days": [
{
"number": 2,
"name": "Вторник",
"short_name": "ВТ",
"month_with_year": "Март",
"date": "2026-03-10",
"couple_count": 4,
"start_couple_number": 2,
"couples": [
{
"number": 2,
"type": "Practice",
"full_type": "Практика",
"date": "2026-03-10",
"launch": "",
"discipline": "Технология разработки и защиты баз данных",
"subgroup": 0,
"teacher": "Озеркова И.А.",
"short_teacher": "Озеркова И. А.",
"classroom": "34",
"hull": "11",
"start": "10:10",
"end": "11:40",
"groups": ""
},
{
"number": 3,
"type": "Lecture",
"full_type": "Лекция",
"date": "2026-03-10",
"launch": "13:20 - 13:40",
"discipline": "Системное программирование",
"subgroup": 0,
"teacher": "Кочетков Станислав Сафирович",
"short_teacher": "Кочетков С. С.",
"classroom": "305",
"hull": "12",
"start": "11:50",
"end": "13:40",
"groups": ""
},
{
"number": 4,
"type": "Practice",
"full_type": "Практика",
"date": "2026-03-10",
"launch": "",
"discipline": "Информационные технологии",
"subgroup": 0,
"teacher": "Дзюба И.Г.",
"short_teacher": "Дзюба И. Г.",
"classroom": "16",
"hull": "11",
"start": "13:50",
"end": "15:20",
"groups": ""
},
{
"number": 5,
"type": "Lecture",
"full_type": "Лекция",
"date": "2026-03-10",
"launch": "",
"discipline": "Технология разработки и защиты баз данных",
"subgroup": 0,
"teacher": "Озеркова И.А.",
"short_teacher": "Озеркова И. А.",
"classroom": "13",
"hull": "11",
"start": "15:40",
"end": "17:10",
"groups": ""
}
]
}
]
}
Return a flat group schedule list.
Path params
| Parameter | Type | Description | Required |
|---|---|---|---|
id |
integer | Group id. | Yes |
Query params
| Parameter | Type | Description | Required |
|---|---|---|---|
period |
string | day or week. |
Yes |
date |
string | Anchor date in YYYY-MM-DD format. |
No |
Status codes
200 OK— request completed successfully.400 Bad Request— invalid path or query parameters.500 Internal Server Error— unexpected server-side error.
Response
Response example
{
"couples": [
{
"number": 2,
"type": "Practice",
"full_type": "Практика",
"date": "2026-03-10",
"launch": "",
"discipline": "Технология разработки и защиты баз данных",
"subgroup": 0,
"teacher": "Озеркова И.А.",
"short_teacher": "Озеркова И. А.",
"classroom": "34",
"hull": "11",
"start": "10:10",
"end": "11:40",
"groups": ""
},
{
"number": 3,
"type": "Lecture",
"full_type": "Лекция",
"date": "2026-03-10",
"launch": "13:20 - 13:40",
"discipline": "Системное программирование",
"subgroup": 0,
"teacher": "Кочетков Станислав Сафирович",
"short_teacher": "Кочетков С. С.",
"classroom": "305",
"hull": "12",
"start": "11:50",
"end": "13:40",
"groups": ""
},
{
"number": 4,
"type": "Practice",
"full_type": "Практика",
"date": "2026-03-10",
"launch": "",
"discipline": "Информационные технологии",
"subgroup": 0,
"teacher": "Дзюба И.Г.",
"short_teacher": "Дзюба И. Г.",
"classroom": "16",
"hull": "11",
"start": "13:50",
"end": "15:20",
"groups": ""
},
{
"number": 5,
"type": "Lecture",
"full_type": "Лекция",
"date": "2026-03-10",
"launch": "",
"discipline": "Технология разработки и защиты баз данных",
"subgroup": 0,
"teacher": "Озеркова И.А.",
"short_teacher": "Озеркова И. А.",
"classroom": "13",
"hull": "11",
"start": "15:40",
"end": "17:10",
"groups": ""
}
]
}
Service is configured via config.yml.
Typical options include:
- HTTP server settings
- Database connection settings
- Redis settings
- External schedule source settings
- Sync routine settings
Outbound requests to the external schedule API can be routed through SOCKS5 proxies to avoid IP blocks or rate limits.
Enable proxies in config.yml:
server:
proxies:
enabled: true
file: "./proxies.txt"Each line in proxies.txt must follow one of these formats:
| Format | Description |
|---|---|
host:port |
Unauthenticated SOCKS5 |
host:port:password |
Password-only auth (no username) |
host:port:username:password |
Full credentials |
Example proxies.txt:
192.168.1.10:1080
192.168.1.11:1080:s3cr3t
192.168.1.12:1080:alice:s3cr3t
A proxy is selected randomly for each request. If the file cannot be loaded at startup, the service continues without proxies and logs a warning.
go mod download
go run ./cmd/servergo test ./...- Fork the repository.
- Create a feature branch.
- Commit your changes.
- Push the branch.
- Open a pull request.
This project is licensed under the MIT License. See LICENSE for details.
