Skip to content

fix: NQL rate formatting and course_enrollments routing (#90)#91

Merged
William-Hill merged 8 commits intomainfrom
rebranding/bishop-state
Feb 24, 2026
Merged

fix: NQL rate formatting and course_enrollments routing (#90)#91
William-Hill merged 8 commits intomainfrom
rebranding/bishop-state

Conversation

@William-Hill
Copy link
Collaborator

Summary

  • Fixes raw decimal display for rate/probability columns (e.g. 0.7575.0%) across table cells, chart axes, chart tooltips, and KPI display
  • Adds course_enrollments table to the LLM prompt with schema, routing rules, DFWI/pass rate SQL patterns (0–1 scale), FERPA guardrails, and a worked example — so queries like "top 10 courses with highest DFW rates" hit the right table
  • Adds SchemaEntry TypeScript interface; removes as any cast; isRateColumn now covers all _rate, _probability, _pct, _percent, _percentage suffixes

Test Plan

  • "What is the retention rate by cohort?" → rates show as 75.0% not 0.75
  • "What are the top 10 courses with the highest DFW rates?" → returns course rows with dfwi_rate as percentages, not CIP codes
  • "Show retention as a KPI" → KPI displays 75.0% not 0.8%
  • Verify no student_guid appears in any query result
  • npx tsc --noEmit passes with 0 errors

) (#82)

* docs: add demo script with 6-minute talk track and screenshot guide

* docs: move DEMO.md into docs/ directory

* docs: move demo script and screenshots into docs/demo/ subdirectory

* chore: untrack large presentation files, add *.pptx and docs PDFs to .gitignore

* feat: student roster page with drill-down, filtering, sorting, and CSV export (#65)

* feat: student roster with info popovers; fix gateway models using 'Y' not 'C' for completion target

* fix: credential model — add sought-credential fallback and class_weight=balanced; add sorting for enrollment and credential type columns

* fix: update credential type popover to reflect sought-credential fallback logic

* feat: dashboard filtering by cohort, enrollment type, and credential type (#66) (#72)

- Add filter bar above KPI tiles with Cohort, Enrollment Type, and Credential Type
  dropdowns (shadcn Select) and a Clear button with filtered-student count
- All 4 dashboard API routes now accept cohort, enrollmentType, credentialType
  query params and apply parameterized WHERE clauses
- Risk alerts and retention-risk routes use a CTE so percentage denominators
  are relative to the filtered set (not the full table)
- Readiness route conditionally JOINs student_level_with_predictions when
  enrollment or credential filters are active; existing institution/cohort/level
  params unchanged
- All fetch calls on the page are re-triggered when filter state changes

* feat: audit log export endpoint with CSV download button (#67) (#73)

- Add GET /api/query-history/export that reads logs/query-history.jsonl and
  streams a CSV with headers: timestamp, institution, prompt, vizType, rowCount
- Accepts optional ?from=ISO_DATE&to=ISO_DATE query params for date-range
  filtering; returns 404 with clear message if the log file does not exist yet
- Sets Content-Disposition: attachment; filename="query-audit-log.csv"
- Add "Export" button with download icon in the QueryHistoryPanel header that
  triggers a direct browser download via <a href download>

* feat: student detail view with personalized recommendations (#77) (#79)

- Add GET /api/students/[guid] joining student_level_with_predictions +
  llm_recommendations; returns 404 for unknown GUIDs
- Add /students/[guid] page with:
    - Student header: GUID, cohort, enrollment, credential, at-risk + readiness badges
    - FERPA disclaimer (de-identified GUID only, no PII stored)
    - Six prediction score cards (retention, readiness, gateway math/English,
      GPA risk, time-to-credential) color-coded green/yellow/red
    - AI Readiness Assessment card: rationale, risk factors (orange dot list),
      and recommended actions (checkbox-style checklist)
    - Graceful fallback when no assessment has been generated yet
    - Back button uses router.back() to preserve roster filter state
- Student roster rows are now fully clickable (onClick → router.push)
  with the GUID cell retaining its Link for ctrl/cmd+click support

* feat: Supabase Auth + role-based access control (FR6, #75) (#80)

* feat: Supabase Auth + role-based access control (FR6, #75)

Auth layer
- Install @supabase/supabase-js + @supabase/ssr
- lib/supabase/client.ts  — browser client (createBrowserClient)
- lib/supabase/server.ts  — server client (createServerClient + cookies)
- lib/supabase/middleware-client.ts — session refresh helper for middleware

Roles
- lib/roles.ts — Role type, ROUTE_PERMISSIONS map, canAccess() helper,
  ROLE_LABELS and ROLE_COLORS per role
- Five roles: admin | advisor | ir | faculty | leadership
  /students/**            → admin, advisor, ir
  /query                  → admin, advisor, ir, faculty
  /api/students/**        → admin, advisor, ir
  /api/query-history/export → admin, ir
  / and /methodology      → all roles (public within auth)

Middleware
- middleware.ts — unauthenticated → redirect /login; role resolved from
  user_roles table; canAccess() enforced; role + user-id + email forwarded
  as request headers (x-user-role, x-user-id, x-user-email) for API routes

Login page
- app/login/page.tsx — email/password form using createBrowserClient
- app/auth/callback/route.ts — PKCE code exchange handler

Navigation
- components/nav-header.tsx — sticky top bar: role badge, email, sign-out
- app/layout.tsx — server component reads session + role, renders NavHeader
  when authenticated

API guards
- /api/students: 403 for faculty + leadership
- /api/students/[guid]: 403 for faculty + leadership
- /api/query-history/export: 403 for non-admin/ir

Database & seed
- migrations/001_user_roles.sql — user_roles table + RLS policy
- scripts/seed-demo-users.ts — creates 5 demo users via service role key
  (admin/advisor/ir/faculty/leadership @bscc.edu, pw: BishopState2025!)

* fix: seed script accepts NEXT_PUBLIC_ env var names; install tsx dev dep

* feat: add cohort and enrollment intensity filters to student roster (#81)

* fix: use correct DB enrollment intensity values (Full-Time/Part-Time with hyphens)
npm ci requires a lockfile; switch to npm install in ci-dashboard and
security-audit workflows to avoid cache resolution failures.
* feat: add course_enrollments migration and data ingestion script (#85)

* fix: transaction safety and validation in course enrollment ingestion (#85)

* feat: add course DFWI, gateway funnel, and sequence API routes (#85)

* fix: sequence join granularity, gateway funnel clarity, DFWI result cap (#85)

* feat: add /courses page with DFWI table, gateway funnel, and co-enrollment pairs (#85)

* fix: percentage display and component cleanup in /courses page (#85)

* fix: gateway type label values (M/E) and add RBAC to gateway-funnel route (#85)

* feat: sortable column headers, info popovers for DFWI/pass rate, pairings table sort (#85)

* feat: tabbed courses page with AI-powered co-enrollment explainability

- Redesign /courses page with 3 tabs: DFWI Rates, Gateway Funnel, Co-enrollment Insights
- Add POST /api/courses/explain-pairing route: queries per-pair stats (individual
  DFWI/pass rates, breakdown by delivery method and instructor type) then calls
  gpt-4o-mini to generate an advisor-friendly narrative
- Co-enrollment Insights tab shows sortable pairings table with per-row Explain
  button that fetches and renders stats chips + LLM analysis inline
- Tab state is client-side (no Radix Tabs dependency needed)

* ci: trigger re-run after workflow fix

* fix: update ESLint for Next.js 16 (next lint removed)

- Replace next lint with direct eslint . in package.json lint script
- Rewrite eslint.config.mjs to use eslint-config-next flat config exports
  directly instead of deprecated FlatCompat bridge
- Add eslint and eslint-config-next as devDependencies
- Suppress pre-existing rule violations (no-explicit-any, no-unescaped-entities,
  set-state-in-effect) to avoid CI failures on legacy code
…ze (#88) (#89)

* docs: NQL interface redesign design doc (#88)

* docs: NQL redesign implementation plan (#88)

* feat: add Query link to global nav header (#88)

* feat: add POST /api/query-summary LLM result narration (#88)

* fix: harden query-summary route input validation (#88)

* refactor: adapt QueryHistoryPanel for sidebar layout (#88)

* fix: restore institution label, fix text size, restore truncation threshold (#88)

* feat: sidebar layout + LLM Summarize button on query page (#88)
- Add isRateColumn helper and formatCellValue to render 0–1 probabilities
  as percentages in table cells, chart axes, tooltips, and KPI display
- Fix KPI suffix to only append % when value is actually in 0–1 range
- Add course_enrollments table to LLM prompt with schema, routing rules,
  DFWI/pass rate SQL patterns, FERPA guardrails, and worked example
- Add SchemaEntry interface; remove as-any cast on courseColumns
- SQL patterns return 0–1 scale; display layer handles multiplication
course_enrollments has no institution_id column; the INSTITUTION context
in the prompt was causing the LLM to borrow the Institution_ID filter
from the student table and apply it to course queries, producing:
  Error: column "institution_id" does not exist
Renders Table/Bar/Line/Pie/KPI buttons above query results. Defaults to
the LLM's chosen vizType and resets on each new query, so users can
switch views without re-running the query.
@William-Hill William-Hill merged commit 6aeb82d into main Feb 24, 2026
4 checks passed
@William-Hill William-Hill deleted the rebranding/bishop-state branch February 24, 2026 17:33
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant