Skip to content

Architecture

NesiciCoding edited this page May 15, 2026 · 3 revisions

Architecture

Overview

Rubric Maker is a client-side single-page application. There is no backend, no database, and no network requests at runtime (except for the optional Common Standards Project API and Microsoft Graph). All state is stored in the browser's localStorage.

Browser
  └── React SPA (Vite bundle)
        ├── React Router 6        — client-side routing
        ├── AppContext             — global state (rubrics, students, grades)
        ├── localStorage           — persistence layer
        ├── Tiptap                 — rich-text editing
        ├── PDF.js / Mammoth       — document rendering
        ├── Tesseract.js           — OCR (in a Web Worker)
        ├── docx / pdfjs-dist      — export generation
        └── i18next                — UI translations

External APIs (both optional):

  • Common Standards Project API — fetches educational standards for the standards picker
  • Microsoft Graph API — accesses OneDrive files via Azure MSAL authentication

Directory structure

src/
├── App.tsx                  # Root component; defines all routes
├── main.tsx                 # Entry point — mounts <App /> into #root
├── i18n.ts                  # i18next initialisation
│
├── components/              # Reusable UI components
│   ├── Layout/
│   │   ├── Topbar.tsx       # Top navigation bar
│   │   └── Sidebar.tsx      # Left navigation sidebar
│   ├── Statistics/          # Chart components (recharts-based)
│   ├── Editor/              # Tiptap editor wrappers
│   ├── CEFR/                # CEFR badge and level picker
│   ├── Comments/            # Comment bank modal
│   ├── Standards/           # Common Standards picker modal
│   └── ...                  # Other modals and shared components
│
├── pages/                   # One file per route
│   ├── RubricBuilder.tsx    # Create / edit a rubric
│   ├── RubricList.tsx       # List all rubrics
│   ├── GradeStudent.tsx     # Main grading interface
│   ├── ComparativeGrading.tsx
│   ├── Dashboard.tsx        # Statistics overview
│   ├── StatisticsPage.tsx   # Full analytics page
│   ├── StudentsPage.tsx     # Student roster management
│   ├── StudentProfilePage.tsx
│   ├── ExportPage.tsx       # Export to PDF / Word / CSV
│   ├── SpeakingSession.tsx  # Oral assessment
│   ├── SelfAssessPage.tsx   # Student self-assessment
│   ├── PeerReviewView.tsx   # Peer review
│   ├── CommentBankPage.tsx
│   ├── AttachmentsPage.tsx
│   ├── SettingsPage.tsx
│   └── ...
│
├── context/
│   ├── AppContext.tsx        # Main state: rubrics, students, grades, settings
│   └── ToastContext.tsx      # Global toast notification system
│
├── hooks/
│   ├── useToast.ts           # Convenience hook for triggering toasts
│   └── useVoiceGrading.ts    # Speech recognition hook
│
├── services/
│   ├── standardsApi.ts       # Common Standards Project API client
│   ├── microsoftGraph.ts     # Microsoft Graph API client
│   └── msalConfig.ts         # Azure MSAL configuration
│
├── store/
│   └── storage.ts            # localStorage read / write / serialise helpers
│
├── utils/
│   ├── gradeCalc.ts          # Score calculation (total points, weighted)
│   ├── pdfExport.ts          # PDF report generation
│   ├── docxExport.ts         # Word document generation (raw)
│   ├── docxTemplateExport.ts # Word mail-merge template export
│   ├── textExtraction.ts     # PDF.js + Tesseract OCR pipeline
│   ├── rubricImport.ts       # Import rubric from JSON
│   ├── vocabularyAnalyser.ts # NLP vocabulary analysis
│   ├── grammarChecker.ts     # Grammar analysis via compromise.js
│   ├── learningGoalsAggregator.ts
│   ├── essayShareCode.ts     # Share code generation
│   ├── studentShareCode.ts
│   ├── nanoid.ts             # Unique ID generation
│   └── ...
│
├── types/
│   └── index.ts              # All shared TypeScript interfaces and types
│
├── data/
│   ├── cefrDescriptors.ts    # CEFR level descriptor text
│   ├── speakingDimensions.ts # Speaking assessment dimensions
│   ├── templates.ts          # Default rubric templates
│   └── voTracks.ts           # Dutch VO education track data
│
└── locales/
    ├── en.json               # English UI strings
    └── nl.json               # Dutch UI strings

State management

There is no Redux or Zustand. State is managed with React's built-in useContext + useReducer.

AppContext holds:

  • rubrics — all rubric definitions
  • students — student records and class assignments
  • grades — graded rubric submissions (indexed by student + rubric)
  • commentBank — reusable feedback snippets
  • settings — user preferences (language, theme, etc.)

On every state change, AppContext writes the updated state to localStorage via storage.ts. On startup, it reads the initial state from localStorage.

ToastContext is a lightweight notification queue. Components call useToast() to show success/error/info messages.


Persistence layer

src/store/storage.ts provides typed read/write functions over localStorage. Data is serialised as JSON. There is no migration system — structural changes require a manual backup/restore or a one-time migration function added to the startup path in AppContext.

localStorage has a browser-imposed limit of roughly 5–10 MB. Large attachments (PDFs, images) stored as base64 can approach this limit quickly. The app warns the user when storage is running low.


Routing

Routes are defined in src/App.tsx using React Router 6's <Routes> / <Route> components. All routes are client-side; the server (or nginx/SharePoint) must fall back to index.html for any path to support deep linking.


Document processing pipeline

When a student attachment is opened:

  1. The file is read as an ArrayBuffer in the browser.
  2. PDF files → rendered via PDF.js in a canvas; text layer extracted for search.
  3. DOCX files → converted to HTML by Mammoth and rendered inline.
  4. Images → displayed directly; if no text is detected, Tesseract.js OCR runs in a Web Worker to extract text.

OCR is CPU-intensive. Tesseract runs in a Web Worker to avoid blocking the UI thread.


Export pipeline

Export format Library Entry point
PDF report PDF.js (canvas → blob) src/utils/pdfExport.ts
Word (raw) docx src/utils/docxExport.ts
Word (template) docx + custom mail-merge src/utils/docxTemplateExport.ts
CSV PapaParse src/pages/ExportPage.tsx
JSON backup Native JSON.stringify src/context/AppContext.tsx

All exports are generated entirely in the browser and downloaded via file-saver.


Tech stack summary

Layer Library Version
UI framework React 18.3
Language TypeScript 5.9
Build tool Vite 7
Routing React Router 6.22
Rich-text editor Tiptap 3.23
Drag and drop @hello-pangea/dnd 18
Charts Recharts 2.12
Document rendering PDF.js, Mammoth, docx-preview
OCR Tesseract.js 5.1
NLP compromise.js 14.15
Export (Word) docx 9.5
Export (CSV) PapaParse 5.4
Microsoft auth @azure/msal-browser 3.2
i18n i18next, react-i18next 25 / 16
Speech react-speech-recognition 4
Testing Vitest + Testing Library 4.1
Container runtime nginx Alpine

Clone this wiki locally