feat: course sequencing insights and DFWI analysis (#85)#87
Merged
William-Hill merged 11 commits intorebranding/bishop-statefrom Feb 23, 2026
Merged
feat: course sequencing insights and DFWI analysis (#85)#87William-Hill merged 11 commits intorebranding/bishop-statefrom
William-Hill merged 11 commits intorebranding/bishop-statefrom
Conversation
…ings table sort (#85)
- 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)
Collaborator
Author
|
Workflow fix pushed to base branch — re-triggering CI by pushing a no-op update. |
- 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
William-Hill
added a commit
that referenced
this pull request
Feb 24, 2026
* feat: add cohort and enrollment intensity filters to student roster (#81) (#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) * chore: add GitHub Actions CI/CD workflows (#83) (#84) * fix: drop npm lockfile cache since package-lock.json is gitignored npm ci requires a lockfile; switch to npm install in ci-dashboard and security-audit workflows to avoid cache resolution failures. * feat: course sequencing insights and DFWI analysis (#85) (#87) * 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 * feat: NQL interface redesign — nav link, sidebar history, LLM Summarize (#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) * fix: NQL rate formatting and course_enrollments routing (#90) - 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 * fix: prevent LLM from adding institution_id filter to course_enrollments 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 * feat: add viz type tab strip for user override of LLM chart choice 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.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
course_enrollmentstable (migration + indexes) and streamsbishop_state_courses.csv(~99,559 rows) into it via an idempotent, transaction-wrapped ingestion script/api/courses/:dfwi(per-course DFWI rates with filters),gateway-funnel(Math/English gateway pass/DFWI breakdown by cohort),sequences(top 20 course prefix+number co-enrollment pairs with pass rate overlay)/coursespage with sortable high-risk course table, Recharts gateway funnel charts, and top co-enrollment pairs tableTest Plan
SELECT COUNT(*) FROM course_enrollments= 99,559/coursespage loads; DFWI table shows courses sorted by DFWI rate descending/courses(middleware enforces this)/courses