Skip to main content
← Dashboard

Admin Console

User Management
Enter a search term to find users.
Integrity & Security
Roxy Status
Checking status...
--
Quick User Lookup
Active Lockouts
Loading lockouts...
Lockout History
Loading history...
TripWire Sensor Breakdown
Loading sensor data...
TripWire Event Log
Loading events...
Flag Submission Audit
Loading flag attempts...
Handler Management
Generate Handler Code

Generate a new handler activation code. The plaintext is shown once -- save it before closing.

Active Handlers
Loading handlers...
Handler Code History
Loading history...
System Health
Platform Stats
Loading...
Integrity Stats
Loading...
Quick Actions
Sprint Master — Project Planning
Backlog Overview
Loading...
Sprint Board
Full Backlog
Series Completion
Content Quality Pipeline
Nexus Pipeline
Loading pipeline status...
EduScan Report Explorer
EduScan Rule Catalog

Full ruleset for EduScan v1.x. Run nexus scan to check the codebase against these rules.

Heuristics (HEUR)
Code Severity Description What It Catches How to Fix
HEUR-001 low Missing title tag HTML files with no <title> element Add a descriptive <title> inside <head>
HEUR-002 low Missing meta description Files without <meta name="description"> Add a meta description tag in <head>
HEUR-003 medium Broken internal link href/src attributes pointing to paths that do not exist on disk Correct the path or remove the dead reference
HEUR-004 low Empty anchor <a> tags with no text content or accessible label Add link text or aria-label
HEUR-005 low Image missing alt attribute <img> tags with no alt Add descriptive alt text; use alt="" for decorative images
HEUR-006 warning Emoji detected Unicode emoji characters in HTML content Replace with webp icon from /assets/images/icons/
HEUR-007 medium Console.log left in production console.log() calls outside of dev/debug files Remove or replace with conditional debug logging
HEUR-008 high position:fixed under filter Elements using position:fixed when a parent has filter applied — breaks layout Switch to position:absolute + scroll offset, or restructure DOM hierarchy
HEUR-009 low Hardcoded localhost URL References to localhost or 127.0.0.1 in source files Replace with relative paths or config-driven base URLs
HEUR-010 medium Inline style overuse Files with excessive inline style="" attributes that should be class-based Move repeated styles to a CSS class
HEUR-011 low TODO / FIXME comment Source comments containing TODO, FIXME, HACK, or XXX markers Resolve the issue and remove the marker, or create a sprint item
HEUR-012 warning Missing viewport meta HTML files without <meta name="viewport"> Add the standard viewport meta tag to <head>
HEUR-013 medium Deprecated HTML element Use of <font>, <center>, <marquee>, or similar deprecated tags Replace with CSS equivalents
HEUR-014 high innerHTML with unsanitized input Patterns like element.innerHTML = userValue without escaping Use textContent or a sanitizer; escape all untrusted data
HEUR-015 low Large file warning Single files exceeding the configured size threshold (default: 200KB) Split into modules or lazy-load heavy sections
HEUR-016 warning Missing language attribute <html> tags without a lang attribute Add lang="en" (or appropriate BCP 47 code) to the root element
HEUR-017 high Lazy-loaded platform component Platform components (ModuleProgress, GameTracker, etc.) loaded via createElement('script') instead of a static <script src> tag. Bypasses DEP-004 checks, causes race conditions, and can fire completion before the student finishes reading. Replace with static <script src> and use a deliberate "Mark Complete" button instead of auto-scroll triggers
HEUR-018 medium Scroll-triggered auto-completion Calls ModuleProgress.complete() inside a scroll event listener. Completion fires automatically at a scroll threshold (often 80%) without the student taking a deliberate action. Student has no feedback about what triggered it and may miss 20% of content. Replace with a "Mark Complete" button at the bottom of the page. The student clicks deliberately after reading all content.
HEUR-019 medium Tenant config missing required fields Tenant dashboard file is missing slug, branding, licensing, or adminUids references required for multi-tenant operation. Add all required tenant config fields per the tenant schema documentation.
HEUR-020 medium Tenant dashboard broken asset references Tenant dashboard has absolute image/icon/CSS paths that do not resolve within the _app directory. Fix asset paths to be relative or use the correct absolute path from the hosting root.
HEUR-021 medium Missing house content in tenant license Tenant config licenses a house that has no content files in its directory. Tenant is paying for empty content. Add content to the licensed house or remove it from the tenant license.
HEUR-022 warning Over-deep relative index.html link An href with ../ climbs more parent directories than the file's depth inside its house, causing the link to escape the house directory entirely. Reduce the number of ../ segments to stay within the house boundary.
HEUR-023 high Broken Course Home link An href to index.html resolves to a file path that does not exist on disk (archived or deleted). Student clicks "Course Home" and gets a 404. Update href to point to a valid index.html (e.g., the course hub or house root).
HEUR-024 warning Missing Course Home link Page loads ModuleProgress.js but has no <a href="...index.html"> link. The completion overlay's "Course Home" button will not appear. Add a navigation link (visible or in breadcrumbs) with href pointing to the parent index.html.
HEUR-025 high Module completion ID mismatch The hub/index page expects a module ID (e.g., clh-001) but the module file saves completion under a different ID (e.g., script-clh-001-intro). Completions are saved but never read back — student sees no progress. Align IDs: either change the hub's module ID or change the ModuleProgress.complete() call to use the same key.
HEUR-026 high Course module links to house root instead of course hub A file inside a course directory (e.g., courses/clh/modules/) has a back/home link that escapes to the house root instead of the course's own index.html. Student leaves the course context. Reduce the ../ depth to point to the course hub, not the house root.
Security (SEC)
Code Severity Description What It Catches How to Fix
SEC-001 high API key exposed in source Hardcoded API key strings (non-Firebase) in HTML/JS files Move to environment config; never commit secrets to source
SEC-002 high eval() usage Calls to eval(), new Function(string), or setTimeout(string) Replace with explicit function references or safe dynamic dispatch
SEC-003 high document.write() usage Calls to document.write() which can open XSS vectors Replace with DOM manipulation methods
SEC-004 medium External script without integrity <script src="..."> loading from CDN without a integrity hash Add SRI integrity attribute or self-host the dependency
Structural (HTML / JS / PATH)
Code Severity Description What It Catches How to Fix
HTML-001 medium Unclosed HTML tag Tags that are opened but never closed (detected via heuristic parse) Close all opened elements; use an HTML validator to confirm
JS-001 medium Missing semicolons JS statements that rely on ASI in ways that can produce bugs Add explicit semicolons at statement ends
PATH-001 medium Absolute path in source Hardcoded absolute filesystem paths (e.g. /home/user/...) Replace with relative paths or use Paths config helper
Content Integrity (LP)
Code Severity Description What It Catches How to Fix
LP-008 medium Content type mismatch LearningPaths module declares one type (e.g. applet) but the href resolves to a different file type Align the declared type with the actual file extension, or move the file to the correct directory
Quiz Integrity (QUIZ)
Code Severity Description What It Catches How to Fix
QUIZ-001 high Redundant client-side answers Quiz has serverGrading: true but still contains correct: fields — answers exposed via View Source even though server has them Remove all correct: fields from questions. Server-side gradeQuiz CF has the answers in Firestore quiz_keys/
QUIZ-002 high Client-side answers exposed Quiz has correct: fields without serverGrading — answers fully visible to students via View Source Add serverGrading: true and houseId, seed answers to Firestore quiz_keys/, then remove correct: fields
QUIZ-003 critical Broken quiz — no answers anywhere Quiz has NO serverGrading and NO correct: fields — grades everyone 0%. Students complete real work and get no credit Add serverGrading: true and houseId, seed answers to Firestore. This is a vulnerability chain: missing config + silent failure + recorded 0% = student impact
QUIZ-004 critical Quiz regression — server grading reverted A quiz that was verified as server-graded in the baseline no longer has serverGrading: true or houseId. An edit (path fix, CSS, accessibility) accidentally reverted the server grading config Restore serverGrading: true and houseId. Check git log for what changed. Baseline: 230 verified quizzes in quiz-baseline.json
How to Run the Quality Pipeline

Run these commands from the project root on the build machine. Reports are written to _tools/reports/ and the findings store is updated at _tools/nexus/findings.json.

Full Pipeline (recommended)
nexus full
Runs EduScan, Sprint, HED, Audit, Spellbook, and Todo spokes. Syncs all findings into findings.json. Use this before any deploy.
Status Dashboard
nexus status
Prints a consolidated view of findings by source and severity. Fast — reads from the existing findings.json without re-scanning.
EduScan Only
nexus scan
Runs only the EduScan spoke. Faster than a full pipeline run when only content quality matters.
Deploy Gate
nexus gate --strict
Fails with exit code 1 if any critical findings exist across EduScan, HED, or Audit sources. Integrate into CI to block bad deploys.
Auto-Triage
nexus triage --apply
Creates sprint backlog items from high-severity findings that have no existing sprint ticket. Add --dry-run to preview without writing.
Direct EduScan (strict profile)
node eduscan/cli.js --profile strict
Bypass Nexus and invoke EduScan directly with the strict ruleset. Outputs TREASURE_MAP.json. Run from _tools/.
Pull HED Export
nexus pull hed
Fetches the latest HED export from the Cloud Function endpoint and caches it locally for the HED spoke adapter.
Note: _tools/ is gitignored. Report files must be generated locally and are never deployed. The findings.json is the only durable store; it is not tracked in git by default and must be explicitly added if you want to commit a snapshot.
Account Operations
Merge Accounts

Select two user accounts to merge. The higher XP, combined completions, and primary email are kept.

Bulk Student Import

Upload a CSV file with columns: email, displayName, house, classCode

Orphan Detection

Find accounts with no class membership and no activity in 30+ days.

Role Management
Current Admins & Handlers
Loading roles...
Grant / Revoke Role

Search for a user, then grant or revoke admin or handler privileges. Changes take effect on their next page load.

Tasks
--
Open
--
In Progress
--
Done Today
--
Total Active
--
My Tasks
New Task
No file selected
Open 0
Loading...
In Progress 0
Recently Done 0
Task Detail
Status
Assign To
Comments
No comments yet.
Spellbook
--
Total Spells
--
Sealed
--
Bound
--
Scribed
--
Cast
--
Banished
--
Most Recent
Spell Library
Loading spells...
Static snapshot — run nexus full --publish to sync live data
Tenant Management
Loading tenants...
Create New Tenant
Edit Tenant
Danger Zone

Deleting a tenant is a soft-delete that marks it as deleted and makes the dashboard inaccessible. Tenant data is preserved for audit purposes but cannot be easily restored.

CTF Tournament Management
Field Manual — How CTF Tournaments Work
\u25B6
Loading tournaments...
Create New Tournament
Challenges
No challenges added yet. Click "+ Add Challenge" to begin.
Tournament Details
DRAFT
Join Code
Share Links
Registered Teams
No teams registered yet.
Challenges
Add Challenge
Select Arena Boxes
Course Tree Mapper

Visualize navigation structure for any course hub. Data generated by eduscan --tree --all