# ovladisluvv/gradetrack architecture

> Architecture diagram of the GitHub repository ovladisluvv/gradetrack, generated by GitDiagram from its file tree, README and a sample of source files (last updated 2026-08-06). It is an AI-made overview: check details against the source.

- Interactive diagram: https://gitdiagram.com/ovladisluvv/gradetrack
- Repository: https://github.com/ovladisluvv/gradetrack

## Overview

#### Purpose and entry points
GradeTrack is a Python 3.12 desktop application for MSU students. It authenticates against `lk.msu.ru`, retrieves grade HTML, calculates averages, and evaluates whether an honors diploma is reachable. GUI startup is `src/gui/app.py` (`python -m gui.app` from `src`); packaged startup is defined by `GradeTrack.spec`.

#### Layered application boundary
The repository uses a deliberate downward dependency structure: GUI orchestrates services; services combine web I/O with pure core logic; core does not perform network I/O. Package boundaries are represented by:
- `src/gui/__init__.py`
- `src/services/__init__.py`
- `src/core/__init__.py`

This separation permits analysis of saved HTML without network access and keeps portal-specific behavior out of grading rules.

#### Portal access and scraping
`src/web` owns the authenticated HTTP session with the external MSU personal-account service. Authentication obtains CSRF state and submits credentials; failures become typed domain exceptions. Scraping returns raw grades-page HTML only, leaving its interpretation to core.
- `src/web/auth.py`
- `src/web/scraper.py`
- `src/web/exceptions.py`

The material external dependency is `lk.msu.ru`; its authentication flow and page markup are integration boundaries prone to upstream change.

#### Grade ingestion and normalization
Core converts fetched or saved HTML into structured grade records, then filters unusable/unpassed entries and maps textual grades to numeric values. During preprocessing, each record is also classified as diploma-relevant.
- `src/core/parser.py`
- `src/core/preprocessor.py`
- `src/core/grade_models.py`

Flow: HTML → `GradeInfo`-style models → normalized numeric grades plus `in_diploma` classification. This is the principal boundary between unstable portal markup and stable analytical inputs.

#### Diploma curriculum data
Diploma inclusion is data-driven rather than hard-coded. The selector resolves subject lists by faculty, program, department, and semester; early semesters use program-level files, while later semesters can use department-specific lists.
- `src/core/diploma_subjects.py`
- `data/in_diploma/vmk/fiit/sem1.txt`
- `data/in_diploma/vmk/pmi/ani/sem5.txt`

The provided curriculum coverage makes honors-diploma analysis materially targeted at VMK bachelor programs. University-selection structure is supplied separately through `data/university_structure.yaml`.

#### Analysis and service orchestration
The analyzer calculates averages with and without retake penalties, optional semester ranges, diploma-grade distribution, and honors-diploma reachability. `grades_service` is the application-facing facade: one path runs scrape-to-analysis, another accepts preexisting HTML.
- `src/core/analyzer.py`
- `src/services/grades_service.py`
- `data/test_grades.html`

Control flow is GUI/user choices → service → authenticated scrape (or saved HTML) → parse/preprocess/curriculum tagging → analysis result → GUI rendering.

#### Desktop runtime, state, and delivery
PyQt6 provides the only user interface: a terminal-styled wizard collects credentials and academic selections, maintains navigation/session state, and moves blocking portal work to a background thread. Configuration and data paths support both source and PyInstaller execution.
- `src/gui/state_manager.py`
- `src/gui/wizard_view.py`
- `src/gui/terminal_view.py`

Deployment supports native PyInstaller binaries and Dockerized GUI execution with X11/OpenGL. Docker mounts `config` and `data`, so those are runtime-editable inputs; image publishing and releases are automated via `.github/workflows/docker-publish.yml` and `.github/workflows/release.yml`.

Main entry points: [`src/services/grades_service.py`](https://github.com/ovladisluvv/gradetrack/blob/main/src/services/grades_service.py) (Grades facade), [`src/gui/wizard_view.py`](https://github.com/ovladisluvv/gradetrack/blob/main/src/gui/wizard_view.py) (Wizard views), [`src/core/preprocessor.py`](https://github.com/ovladisluvv/gradetrack/blob/main/src/core/preprocessor.py) (Grade normalizer), [`GradeTrack.spec`](https://github.com/ovladisluvv/gradetrack/blob/main/GradeTrack.spec) (PyInstaller build)

## Diagram (Mermaid)

```mermaid
flowchart TD

subgraph group_gui["Desktop UI"]
  node_gui_app["GUI startup<br/>PyQt6 entry point<br/>[app.py]"]
  node_wizard["Wizard views<br/>PyQt6 views<br/>[wizard_view.py]"]
  node_terminal["Terminal view<br/>PyQt6 view<br/>[terminal_view.py]"]
  node_ui_state["Navigation state<br/>state manager<br/>[state_manager.py]"]
end

subgraph group_services["Application Service"]
  node_grades_service["Grades facade<br/>[grades_service.py]"]
  node_saved_html["Saved grade HTML<br/>offline input<br/>[test_grades.html]"]
end

subgraph group_core["Core Analysis"]
  node_parser["HTML parser<br/>grade ingestion<br/>[parser.py]"]
  node_preprocessor["Grade normalizer<br/>preprocessing<br/>[preprocessor.py]"]
  node_grade_models["Grade records<br/>domain models<br/>[grade_models.py]"]
  node_curriculum["Diploma selector<br/>curriculum resolver"]
  node_curriculum_data["VMK curriculum lists<br/>runtime data<br/>[sem1.txt]"]
  node_analyzer["Honors analyzer<br/>analysis engine<br/>[analyzer.py]"]
end

subgraph group_integration["Portal &amp; Delivery"]
  node_auth["Portal authentication<br/>authenticated session<br/>[auth.py]"]
  node_scraper["Grade HTML scraper<br/>web client<br/>[scraper.py]"]
  node_portal(("lk.msu.ru<br/>external portal"))
  node_app_spec["PyInstaller build<br/>desktop packaging<br/>[GradeTrack.spec]"]
  node_docker_publish["Docker publishing<br/>CI workflow<br/>[docker-publish.yml]"]
  node_release["Release automation<br/>CI workflow<br/>[release.yml]"]
end

node_gui_app -->|"starts"| node_wizard
node_wizard -->|"updates"| node_ui_state
node_wizard -->|"submits choices"| node_grades_service
node_grades_service -->|"authenticates"| node_auth
node_auth -->|"CSRF and credentials"| node_portal
node_grades_service -->|"fetches grades"| node_scraper
node_scraper -->|"requests grades page"| node_portal
node_grades_service -.->|"accepts offline input"| node_saved_html
node_grades_service -->|"passes HTML"| node_parser
node_parser -->|"creates"| node_grade_models
node_grade_models -->|"normalizes"| node_preprocessor
node_preprocessor -->|"checks inclusion"| node_curriculum
node_curriculum -->|"loads subject lists"| node_curriculum_data
node_preprocessor -->|"provides tagged grades"| node_analyzer
node_analyzer -->|"returns result"| node_grades_service
node_grades_service -->|"renders result"| node_terminal
node_app_spec -->|"packages entry point"| node_gui_app
node_docker_publish -.->|"delivers image build"| node_app_spec
node_release -.->|"publishes binaries"| node_app_spec

click node_gui_app "https://github.com/ovladisluvv/gradetrack/blob/main/src/gui/app.py"
click node_wizard "https://github.com/ovladisluvv/gradetrack/blob/main/src/gui/wizard_view.py"
click node_terminal "https://github.com/ovladisluvv/gradetrack/blob/main/src/gui/terminal_view.py"
click node_ui_state "https://github.com/ovladisluvv/gradetrack/blob/main/src/gui/state_manager.py"
click node_grades_service "https://github.com/ovladisluvv/gradetrack/blob/main/src/services/grades_service.py"
click node_auth "https://github.com/ovladisluvv/gradetrack/blob/main/src/web/auth.py"
click node_scraper "https://github.com/ovladisluvv/gradetrack/blob/main/src/web/scraper.py"
click node_parser "https://github.com/ovladisluvv/gradetrack/blob/main/src/core/parser.py"
click node_preprocessor "https://github.com/ovladisluvv/gradetrack/blob/main/src/core/preprocessor.py"
click node_grade_models "https://github.com/ovladisluvv/gradetrack/blob/main/src/core/grade_models.py"
click node_curriculum "https://github.com/ovladisluvv/gradetrack/blob/main/src/core/diploma_subjects.py"
click node_curriculum_data "https://github.com/ovladisluvv/gradetrack/blob/main/data/in_diploma/vmk/fiit/sem1.txt"
click node_analyzer "https://github.com/ovladisluvv/gradetrack/blob/main/src/core/analyzer.py"
click node_saved_html "https://github.com/ovladisluvv/gradetrack/blob/main/data/test_grades.html"
click node_app_spec "https://github.com/ovladisluvv/gradetrack/blob/main/GradeTrack.spec"
click node_docker_publish "https://github.com/ovladisluvv/gradetrack/blob/main/.github/workflows/docker-publish.yml"
click node_release "https://github.com/ovladisluvv/gradetrack/blob/main/.github/workflows/release.yml"

classDef toneNeutral fill:#f8fafc,stroke:#334155,stroke-width:1.5px,color:#0f172a
classDef toneBlue fill:#dbeafe,stroke:#2563eb,stroke-width:1.5px,color:#172554
classDef toneAmber fill:#fef3c7,stroke:#d97706,stroke-width:1.5px,color:#78350f
classDef toneMint fill:#dcfce7,stroke:#16a34a,stroke-width:1.5px,color:#14532d
classDef toneRose fill:#ffe4e6,stroke:#e11d48,stroke-width:1.5px,color:#881337
classDef toneIndigo fill:#e0e7ff,stroke:#4f46e5,stroke-width:1.5px,color:#312e81
classDef toneTeal fill:#ccfbf1,stroke:#0f766e,stroke-width:1.5px,color:#134e4a
class node_gui_app,node_wizard,node_terminal,node_ui_state toneBlue
class node_grades_service,node_saved_html toneAmber
class node_parser,node_preprocessor,node_grade_models,node_curriculum,node_curriculum_data,node_analyzer toneMint
class node_auth,node_scraper,node_portal,node_app_spec,node_docker_publish,node_release toneRose
```

## Components

### Desktop UI

PyQt6 wizard runtime.

- [GUI startup](https://github.com/ovladisluvv/gradetrack/blob/main/src/gui/app.py): PyQt6 entry point · `src/gui/app.py`
- [Wizard views](https://github.com/ovladisluvv/gradetrack/blob/main/src/gui/wizard_view.py): PyQt6 views · Collects credentials and academic selections. · `src/gui/wizard_view.py`
- [Terminal view](https://github.com/ovladisluvv/gradetrack/blob/main/src/gui/terminal_view.py): PyQt6 view · Renders analysis output. · `src/gui/terminal_view.py`
- [Navigation state](https://github.com/ovladisluvv/gradetrack/blob/main/src/gui/state_manager.py): state manager · Maintains wizard and session state. · `src/gui/state_manager.py`

### Application Service

- [Grades facade](https://github.com/ovladisluvv/gradetrack/blob/main/src/services/grades_service.py): service · Supports portal scraping and saved-HTML analysis. · `src/services/grades_service.py`
- [Saved grade HTML](https://github.com/ovladisluvv/gradetrack/blob/main/data/test_grades.html): offline input · Allows analysis without portal access. · `data/test_grades.html`

### Core Analysis

Pure parsing, normalization, and diploma rules.

- [HTML parser](https://github.com/ovladisluvv/gradetrack/blob/main/src/core/parser.py): grade ingestion · Converts portal or saved HTML into grade records. · `src/core/parser.py`
- [Grade normalizer](https://github.com/ovladisluvv/gradetrack/blob/main/src/core/preprocessor.py): preprocessing · Filters records, maps grades, and tags diploma relevance. · `src/core/preprocessor.py`
- [Grade records](https://github.com/ovladisluvv/gradetrack/blob/main/src/core/grade_models.py): domain models · Structured GradeInfo-style analytical inputs. · `src/core/grade_models.py`
- [Diploma selector](https://github.com/ovladisluvv/gradetrack/blob/main/src/core/diploma_subjects.py): curriculum resolver · Resolves subject lists by program, department, and semester. · `src/core/diploma_subjects.py`
- [VMK curriculum lists](https://github.com/ovladisluvv/gradetrack/blob/main/data/in_diploma/vmk/fiit/sem1.txt): runtime data · Program and department-specific diploma subjects. · `data/in_diploma/vmk/fiit/sem1.txt`
- [Honors analyzer](https://github.com/ovladisluvv/gradetrack/blob/main/src/core/analyzer.py): analysis engine · Calculates averages, distributions, and diploma reachability. · `src/core/analyzer.py`

### Portal & Delivery

- [Portal authentication](https://github.com/ovladisluvv/gradetrack/blob/main/src/web/auth.py): authenticated session · Obtains CSRF state and maps failures to typed exceptions. · `src/web/auth.py`
- [Grade HTML scraper](https://github.com/ovladisluvv/gradetrack/blob/main/src/web/scraper.py): web client · Returns raw grades-page HTML. · `src/web/scraper.py`
- **lk.msu.ru**: external portal · Upstream authentication and markup boundary.
- [PyInstaller build](https://github.com/ovladisluvv/gradetrack/blob/main/GradeTrack.spec): desktop packaging · Defines packaged application startup. · `GradeTrack.spec`
- [Docker publishing](https://github.com/ovladisluvv/gradetrack/blob/main/.github/workflows/docker-publish.yml): CI workflow · Builds and publishes the GUI image. · `.github/workflows/docker-publish.yml`
- [Release automation](https://github.com/ovladisluvv/gradetrack/blob/main/.github/workflows/release.yml): CI workflow · Publishes native releases. · `.github/workflows/release.yml`

## Connections

- GUI startup → Wizard views: starts
- Wizard views → Navigation state: updates
- Wizard views → Grades facade: submits choices
- Grades facade → Portal authentication: authenticates
- Portal authentication → lk.msu.ru: CSRF and credentials
- Grades facade → Grade HTML scraper: fetches grades
- Grade HTML scraper → lk.msu.ru: requests grades page
- Grades facade → Saved grade HTML: accepts offline input
- Grades facade → HTML parser: passes HTML
- HTML parser → Grade records: creates
- Grade records → Grade normalizer: normalizes
- Grade normalizer → Diploma selector: checks inclusion
- Diploma selector → VMK curriculum lists: loads subject lists
- Grade normalizer → Honors analyzer: provides tagged grades
- Honors analyzer → Grades facade: returns result
- Grades facade → Terminal view: renders result
- PyInstaller build → GUI startup: packages entry point
- Docker publishing → PyInstaller build: delivers image build
- Release automation → PyInstaller build: publishes binaries
