Architecture Overview

IC Insight is a Chrome Manifest V3 extension. All logic runs client-side. The only external network calls made are to the logged-in user's own Infinite Campus instance via the IC REST API (see Network Refresh).


File Structure

extension/
├── manifest.json           # Extension config: permissions, content scripts, pages
├── background.js           # Service worker: handles ICI_IC_FETCH messages for IC API calls
├── ic-api-client.js        # ICApiClient: IC REST API session check and grade fetch logic
├── content.js              # Content script: overlay rendering, DOM parsing, caching
├── sebi-prefs.js           # Content script: SEBI preference helpers, SEBI.normalizeCategoryKey()
├── styles.css              # Overlay base styles and CSS variable fallbacks
├── themes.css              # Full light/dark theme CSS variable definitions
├── dashboard.html/.js/.css # Hub page: course cards, GPA, sorting, sparklines
├── details.html/.js        # Per-course deep-dive page: breakdown, permanent edits, history chart
├── options.html/.js        # Settings page
├── popup.html/.js          # Extension toolbar popup
├── gpa-engine.js           # GPAEngine: quality-points GPA calculation (cumulative)
├── storage-manager.js      # StorageManager: schema versioning, past report cards, import/export
├── scenarios-manager.js    # ScenariosManager: CRUD for named what-if scenarios
├── drag-drop-handler.js    # DragDropHandler: Dashboard card ordering (drag + sort modes)
├── refresh-controller.js   # RefreshController: bulk course refresh with network/classic strategies
├── history-snapshots.js    # HistorySnapshots: snapshot CRUD and deduplication
├── trends-engine.js        # TrendsEngine: time-series data shaping for the history chart
├── charts.js               # Chart rendering (sparklines + full history chart)
├── user-prefs.js           # UserPrefs: theme, color palette, welcome messages, user name
├── onboarding-tour.js      # OnboardingTour: first-use guided tour
└── icons/                  # Extension icon images

Entry Points

Entry Point How triggered Purpose
content.js + sebi-prefs.js Injected on every *.infinitecampus.org page at document_idle Overlay panel, parsing, caching
background.js Loaded as service worker Handles ICI_IC_FETCH messages - makes credentialed fetch() calls to the IC API on behalf of extension pages
popup.html User clicks extension icon Links to Dashboard, Options, overlay re-center
dashboard.html Opened manually or via overlay Dashboard button Full course hub
details.html?key=… Opened via Dashboard "View details" link Per-course breakdown + history
options.html Via popup or Chrome extensions menu All settings

Data Flow

Parse → Cache → Display

User visits IC grades page
       │
       ▼
content.js: initializeICI()
       │  detects grades page / iframe
       ▼
parseModel()  ──► parseModelWithQuarters() ──► parseCategoriesInSection()
       │                  │                          │
       │            parseQuarterInfo()          extractScore/Multiplier/DroppedFlag
       │
       ▼
computeBreakdown(model, sebiPrefs)
       │  applies: permEdits → permAdds → whatIfAdds → whatIfDrops/Edits
       │  resolves: letter grades → numeric
       │  adds: synthetic rolled-up past-quarter assignments (rolling mode)
       │
       ▼
setSummary() + renderBreakdown()  →  overlay panel rendered
       │
       ▼
cacheSnapshot(model)
       │  computes breakdown WITHOUT perm edits/adds
       │  merges new quarters with existing cached quarters
       │  writes to chrome.storage.local[courseKey]
       │  updates ICI_CACHE_INDEX
       │  captureHistorySnapshot() (manual source only)

Dashboard Load

dashboard.html opens
       │
       ▼
loadIndexCore()
       ├── loads ICI_CACHE_INDEX, ICI_GPA_SCALE, ICI_GPA_WEIGHTS
       ├── deduplicates courses by name (merge)
       ├── applies DragDropHandler.applySorting()
       │
       ├── for each course key:
       │     ├── load snapshot from storage
       │     ├── applyPermOverrides(cats, PE_key, PA_key)
       │     ├── recomputeOverall(cats, sebiPrefs, key, quarters, gradebookLogic)
       │     └── render course card + sparkline
       │
       ├── compute currentYearGPA
       ├── autoCaptureAllCourses() → HistorySnapshots.captureSnapshot() for each
       ├── updateCumulativeGPA() → GPAEngine.calculateCumulativeGPA()
       └── loadPastReportCards()

Module Globals

content.js module-level state

Variable Type Purpose
currentModel object | null Currently parsed course model from the page
whatIfAdds array Active what-if addition items
whatIfDrops array Active what-if drop items
whatIfEdits array Active what-if edit items
permEdits object Active permanent score overrides keyed by `quarterId
permAdds array Active permanent assignment additions
uiState object Overlay position, size, minimized state
sebiPrefs object SEBI preferences for current course (categoryKey → boolean)

Global window objects (loaded as scripts)

  • window.SEBI - from sebi-prefs.js
  • window.GPAEngine - from gpa-engine.js
  • window.StorageManager - from storage-manager.js
  • window.ScenariosManager - from scenarios-manager.js
  • window.DragDropHandler - from drag-drop-handler.js
  • window.HistorySnapshots - from history-snapshots.js
  • window.TrendsEngine - from trends-engine.js
  • window.UserPrefs - from user-prefs.js
  • window.ICApiClient - from ic-api-client.js (loaded in dashboard.html before refresh-controller.js)

Permissions

Permission Reason
storage All data is stored locally in chrome.storage.local
activeTab Popup can send messages to the currently active IC tab
tabs chrome.tabs.query used to locate an open IC tab during session validation
Host: *.infinitecampus.org/*, infinitecampus.org/* Content script injection scope; also required for background SW to make credentialed API calls