# Project export: BridgeBack - Building a Better Way Back After Absence

This document was generated by HackStack to give an AI agent context about a hackathon project. Sections are labeled with their provenance; content marked as truncated was cut to keep this document small.

## Project metadata

- Hackathon: OpenAI Build Week
- Tagline: BridgeBack works backwards from the next lesson to find the few prerequisite gaps a returning pupil needs to close - then gives teachers control of a short, focused route back into class.
- Devpost: https://devpost.com/software/bridgeback
- GitHub: https://github.com/DanielButler1/BridgeBack
- Demo: https://bridgeback.phaseo.app/
- Video: https://www.youtube.com/embed/3roIWobSEm4?enablejsapi=1&hl=en_US&rel=0&start=&version=3&wmode=transparent
- Team: 1 GitHub contributor(s) — Daniel Butler (43 commits)

## Devpost submission (written by the team)

### Inspiration

Returning to school after an absence can turn learning into a wall of missed work. In England's state-funded schools, 18.7% of pupils were persistently absent in 2024/25; persistent absence means missing at least 10% of possible sessions. The rate was 24.3% in secondary schools and 35.8% in special schools. NFER's qualitative study with 85 pupils across nine secondary schools found that catching up was one of pupils' biggest concerns and that pupils valued teachers explaining what they had missed. BridgeBack begins with a different question: not “What work did this pupil miss?” but “What is the minimum they need to understand to take part in the next lesson?”

### What it does

BridgeBack is a curriculum re-entry engine. A teacher supplies the upcoming lesson and relevant source materials. GPT-5.6 proposes a source-labelled prerequisite map, which the teacher reviews before it can reach a pupil. A short diagnostic checks only those prerequisites. BridgeBack then selects no more than three focused activities, preserving progress across refreshes and keeping the pupil's next action clear. The guided journey follows Mia, a fictional Year 10 pupil returning before a binary-search lesson. A second mathematics example applies the same method to simultaneous equations. Optional image generation and a five-minute Realtime voice conversation give pupils visual and spoken ways to work through an unlocked concept.

### How we built it

Next.js 16, React 19, TypeScript, Tailwind CSS and shadcn/ui Clerk authentication with fixed synthetic judge accounts Convex for the production database, storage, role checks and persisted progress GPT-5.6 Sol for lesson dependency analysis, Terra for diagnostics, and Luna for pupil-sized learning support Structured Outputs with Zod, source references, prompt-injection boundaries, store: false, and teacher approval gates GPT Image 2 for optional concept illustrations gpt-realtime-2.1 over WebRTC for lesson-grounded “Talk it through” sessions Playwright, Vitest and axe-core for unit, end-to-end, mobile and accessibility checks What makes it different Most catch-up workflows begin with the backlog. BridgeBack begins with the destination, the lesson happening next, and works backwards. Its main product decision is deliberate subtraction: missed resources that are not prerequisites stay out of the pupil's immediate route. Responsible design The Build Week deployment uses fictional users and synthetic learning records. Diagnostic results are readiness signals, not grades or mastery claims. BridgeBack does not infer absence reasons, emotion, disability, behaviour or risk, and it is not approved for live school or child data. store: false reduces response persistence but is not described as Zero Data Retention. The repository documents the additional DPIA, safeguarding, retention, procurement and validation gates required before a real-school pilot. Evidence boundary The attendance figures describe England, not the whole UK. The NFER research is a selected qualitative sample, not nationally representative. The OCR-aligned curriculum packs provide specification navigation and prerequisite taxonomy, not a complete replacement curriculum. The project does not yet claim reduced workload, improved attainment or teacher validation. Accomplishments A working, two-sided teacher and pupil journey backed by production Convex data Teacher-reviewed, source-grounded concept maps and diagnostics Persistent pupil progress and consistent views across roles Computer science and mathematics demonstrations Responsive mobile concept navigation and automated accessibility checks Optional visual and voice learning modes behind explicit pupil actions Challenges and learning The hardest design problem was deciding what the AI must not do. A useful re-entry route needs enough intelligence to connect concepts, but it cannot quietly become a grading, profiling or safeguarding system. Source labels, narrow diagnostics, deterministic path limits and teacher approval made the experience both clearer and safer. Built with Codex Codex was used throughout Build Week to turn the research-backed hypothesis into a vertical slice, implement and test the Next.js/Convex/Clerk architecture, review security and child-data boundaries, refine the two-sided experience, and prepare the deployment and submission materials. The final Devpost entry must also include the required /feedback Codex Session ID.

## README (from the GitHub repository)

# BridgeBack

**The shortest path back into the next lesson.**

BridgeBack is an OpenAI Build Week Education-track project for pupils returning to school after absence. Instead of assigning every missed resource, it identifies the minimum prerequisite concepts a pupil needs to participate in the upcoming lesson.

**Live Build Week deployment:** [bridgeback.phaseo.app](https://bridgeback.phaseo.app)

**Public demo video:** [BridgeBack: Building a Better Way Back After Absence](https://youtu.be/3roIWobSEm4) (2:56)

> [!IMPORTANT]
> BridgeBack is a functional, production-deployed Build Week product demonstrated with synthetic data. Its end-to-end teacher and pupil workflows are live, but it is not yet approved for identifiable pupil or school data. See [Production readiness](docs/PRODUCTION-READINESS.md) for the implemented foundations and the release gates for a supervised real-school pilot.

BridgeBack is best understood as a **curriculum re-entry engine**. Most catch-up tools begin with the backlog. BridgeBack begins with the destination, the lesson happening next, then works backwards through a source-grounded, teacher-reviewed dependency graph. The innovation is deliberate subtraction: irrelevant missed work stays out, while the teacher controls what is allowed into the pupil's route.

The guided demo follows Mia, a fictional Year 10 pupil returning after four weeks away, as her class begins GCSE Computer Science binary search. The protected school workspace supports creating a real class and upcoming lesson separately from that judge journey.

## What works today

- Separate teacher and pupil routes with role checks at the server and data layers
- Build-safe Clerk sessions with one-click, signed HTTP-only synthetic judge sessions
- A full Convex schema for users, classes, lessons, resources, concept graphs, diagnostics, responses, pathways and AI runs
- Authorized Convex file uploads, graph approval and persisted diagnostic answers
- Deterministic scoring and prerequisite traversal capped at three concepts
- Editable, source-labelled prerequisite graph rendered with React Flow
- GPT-5.6 Terra diagnostics generated from the teacher-approved graph
- A deterministic learning path capped at three concepts including the upcoming target
- GPT-5.6 Luna micro-lessons with explanations, worked examples, closed checks and exact source references
- Credential-free local demo mode using the same product screens
- GPT-5.6 Sol file-aware lesson analysis with Zod Structured Outputs, editable draft persistence and teacher approval
- Optional, pupil-triggered GPT Image 2 concept illustrations for the first two unlocked learning activities; the demo returns a representative sample visual
- A responsive concept map that becomes an ordered prerequisite list on small screens
- A protected school workspace for class creation, lesson setup, resource upload, analysis and teacher approval
- A second interactive GCSE Mathematics example showing simultaneous-equation prerequisites and a two-activity route
- Safety identifiers, `store: false`, prompt-injection boundaries and AI run telemetry
- Unit tests, desktop and iPhone browser journeys, automated WCAG checks and GitHub Actions CI
- A reproducible two-minute Remotion submission film with an OpenAI `gpt-4o-mini-tts` narration generator
- A five-minute, lesson-grounded “Talk it through” voice mode using `gpt-realtime-2.1` over WebRTC

## Run locally

```bash
npm install
npm run dev
```

Open [http://localhost:3000](http://localhost:3000).

BridgeBack defaults to a credential-free local demo. Copy `.env.example` to `.env.local` to connect the services.

## Connect Clerk and Convex

1. Create two synthetic Clerk users: **Ms Morgan** and **Mia**. Do not use real pupil details.
2. Create a Clerk JWT template named `convex`, then copy its issuer domain into `CLERK_JWT_ISSUER_DOMAIN`.
3. Run `npx convex dev` and keep it running. This provisions `CONVEX_DEPLOYMENT` and `NEXT_PUBLIC_CONVEX_URL`.
4. Add the Clerk publishable/secret keys and both synthetic Clerk user IDs to `.env.local`.
5. Set `DEMO_AUTH_ENABLED=true` only for the judging deployment.
6. Seed the database once:

```bash
npx convex run seed:seedDemo '{"teacherSubject":"user_teacher_id","pupilSubject":"user_pupil_id"}'
```

The public judge buttons map only to those two fixed IDs. The server creates a Clerk session and stores only its opaque ID inside a signed, HTTP-only, same-site cookie that expires after four hours. Disable `DEMO_AUTH_ENABLED` outside the demo.

Add `OPENAI_API_KEY` to the Convex deployment environment before running live lesson analysis:

```bash
npx convex env set OPENAI_API_KEY
```

## Stack

- Next.js 16 App Router and React 19
- TypeScript and Tailwind CSS 4
- shadcn/ui using preset `b1s9c8K70` (`base-nova`)
- React Flow for concept dependencies
- Zod for educational domain schemas
- Clerk for authentication and Convex for database, storage and server actions
- OpenAI JavaScript SDK and the Responses API
- Playwright and axe-core for browser and accessibility checks

## GPT-5.6 routing

| Job | Model | Reason |
| --- | --- | --- |
| Lesson dependency graph | `gpt-5.6-sol` | Implemented with Structured Outputs |
| Approved diagnostic | `gpt-5.6-terra` | Balanced structured educational generation |
| Pupil micro-lessons | `gpt-5.6-luna` | Efficient, responsive instructional generation |
| Optional concept illustration | `gpt-image-2` | High-quality visual support, limited to two unlocked activities |

Teacher review remains mandatory before any generated dependency map is assigned to pupils.

## Verify locally

```bash
npm run verify
npx playwright install chromium
npm run test:e2e
```

Browser tests cover the public pages, both demo roles, refresh persistence, desktop Chromium, iPhone-sized Chromium, and serious/critical WCAG violations.

## Product principles

1. Prepare for what comes next; do not recreate every missed lesson.
2. Never show a pupil more than three next steps.
3. Treat diagnostic results as readiness signals, not grades or definitive mastery claims.
4. Keep teachers in control of prerequisite relationships and source material.
5. Use synthetic pupil data in the proof of concept.
6. Never infer emotion, disability, absence reasons, behaviour or risk.
7. Never use BridgeBack for grades, placement, discipline or attendance consequences.

## Safety and privacy decisions

Curriculum mappings are versioned and source-linked. See [Curriculum packs and versioning](docs/CURRICULUM-PACKS.md) for coverage, review rules and the copyright boundary.

The rationale for BridgeBack's synthetic-data boundary, child-protection principles, data flow, OpenAI retention choices, teacher oversight, prohibited uses, and real-school release blockers is documented in [Safety, privacy, and product decisions](docs/SAFETY-PRIVACY-DECISIONS.md).

## Public release

- [Production readiness](docs/PRODUCTION-READINESS.md)
- [Build Week submission draft](docs/SUBMISSION-DRAFT.md)
- [Vercel deployment runbook](docs/DEPLOYMENT.md)
- [School integration pilot](docs/SCHOOL-INTEGRATION-PILOT.md)
- [Impact measurement plan](docs/IMPACT-MEASUREMENT.md)
- [AI evaluation plan](docs/AI-EVALUATION.md)
- [AI-simulated teacher walkthrough](docs/SIMULATED-TEACHER-REVIEW.md)
- [Security architecture](docs/SECURITY-ARCHITECTURE.md)
- [Submission film project](video/README.md)

Licensed under the [Apache License 2.0](LICENSE).

## How Codex accelerated the build

BridgeBack was created during OpenAI Build Week through an extended collaboration with Codex. The commit history and primary Codex session document work completed during the submission period.

### Where Codex accelerated the workflow

- Turned the research-backed problem statement into a working vertical slice across the teacher and pupil journeys.
- Scaffolded the Next.js interface with the supplied shadcn preset and iterated on responsive, accessible layouts through browser review.
- Designed and implemented the C

[README truncated for size]

## Detected evidence (automated analysis)

Indexed codebase: 111 recognized source files, 489 KB.
- CSS (language) — detected in the code
- JavaScript (language) — detected in the code
- Next.js (technology) — detected in the code
- OpenAI (technology) — detected in the code
- React (technology) — detected in the code
- Tailwind CSS (technology) — detected in the code
- TypeScript (language) — detected in the code
- Vercel (technology) — claimed on Devpost, not found in the code
- AI coding agent: Claude Code — evidence: config files committed to the repository
- AI coding agent: Codex — evidence: config files committed to the repository

## Codebase structure (from repository index)

### Files (120 of 125)

```
.env.example
.github/workflows/quality.yml
.gitignore
AGENTS.md
CLAUDE.md
components.json
convex/_generated/api.d.ts
convex/_generated/api.js
convex/_generated/dataModel.d.ts
convex/_generated/server.d.ts
convex/_generated/server.js
convex/aiRuns.ts
convex/analyseLesson.ts
convex/auth.config.ts
convex/curriculum.ts
convex/generateLearning.ts
convex/lib/auth.ts
convex/lib/education.test.ts
convex/lib/education.ts
convex/lib/pathway.test.ts
convex/lib/pathway.ts
convex/product.ts
convex/pupil.ts
convex/schema.ts
convex/seed.ts
convex/teacher.ts
convex/viewer.ts
convex/voice.ts
docs/AI-EVALUATION.md
docs/CURRICULUM-PACKS.md
docs/DEPLOYMENT.md
docs/IMPACT-MEASUREMENT.md
docs/PRODUCTION-READINESS.md
docs/SAFETY-PRIVACY-DECISIONS.md
docs/SCHOOL-INTEGRATION-PILOT.md
docs/SECURITY-ARCHITECTURE.md
docs/SIMULATED-TEACHER-REVIEW.md
docs/SUBMISSION-DRAFT.md
docs/VIDEO-RECORDING-RUNBOOK.md
eslint.config.mjs
LICENSE
next.config.ts
package.json
playwright.config.ts
postcss.config.mjs
README.md
src/app/api/demo/sign-in/[role]/route.ts
src/app/api/demo/token/route.ts
src/app/api/realtime/session/route.ts
src/app/app/classes/[classId]/loading.tsx
src/app/app/classes/[classId]/page.tsx
src/app/app/page.tsx
src/app/demo/maths/page.tsx
src/app/demo/page.tsx
src/app/demo/pupil/page.tsx
src/app/demo/teacher/page.tsx
src/app/for-schools/page.tsx
src/app/globals.css
src/app/how-it-works/page.tsx
src/app/layout.tsx
src/app/page.tsx
src/app/pupil/page.tsx
src/app/safeguards/page.tsx
src/app/sign-in/[[...sign-in]]/page.tsx
src/app/teacher/page.tsx
src/app/why/page.tsx
src/components/app-providers.tsx
src/components/app-shell.tsx
src/components/bridgeback-mark.tsx
src/components/concept-map.tsx
src/components/demo-header.tsx
src/components/marketing-chrome.tsx
src/components/maths-demo.tsx
src/components/product-class-workspace.tsx
src/components/product-workspace.tsx
src/components/pupil-journey.tsx
src/components/talk-it-through.tsx
src/components/teacher-dashboard.tsx
src/components/ui/avatar.tsx
src/components/ui/badge.tsx
src/components/ui/button.tsx
src/components/ui/card.tsx
src/components/ui/input.tsx
src/components/ui/label.tsx
src/components/ui/progress.tsx
src/components/ui/select.tsx
src/components/ui/separator.tsx
src/components/ui/sheet.tsx
src/components/ui/tabs.tsx
src/components/ui/textarea.tsx
src/components/ui/tooltip.tsx
src/lib/auth/demo-session.ts
src/lib/auth/server.ts
src/lib/bridgeback-schema.ts
src/lib/config.ts
src/lib/curriculum-catalog.test.ts
src/lib/curriculum-catalog.ts
src/lib/demo-data.ts
src/lib/learning-feedback.test.ts
src/lib/learning-feedback.ts
src/lib/maths-demo-data.ts
src/lib/openai/client.ts
src/lib/openai/model-routing.ts
src/lib/realtime-tutor.test.ts
src/lib/realtime-tutor.ts
src/lib/utils.ts
src/proxy.ts
tests/e2e/accessibility.spec.ts
tests/e2e/demo.spec.ts
tests/e2e/production-realtime.spec.ts
tsconfig.json
vercel.json
video/.gitignore
video/.prettierrc
video/eslint.config.mjs
video/package.json
video/README.md
video/remotion.config.ts
video/scripts/generate-voiceover.ts
video/src/Composition.tsx
[5 more files omitted for size]
```

### Dependencies

- package.json: @axe-core/playwright@^4.12.1, @base-ui/react@^1.6.0, @clerk/nextjs@^7.5.17, @playwright/test@^1.61.1, @tailwindcss/postcss@^4, @types/node@^20, @types/react@^19, @types/react-dom@^19, @xyflow/react@^12.11.2, class-variance-authority@^0.7.1, clsx@^2.1.1, convex@^1.42.1, eslint@^9, eslint-config-next@16.2.10, lucide-react@^1.24.0, next@16.2.10, openai@^6.46.0, react@19.2.4, react-dom@19.2.4, shadcn@^4.13.0, tailwind-merge@^3.6.0, tailwindcss@^4, tw-animate-css@^1.4.0, typescript@^5, vitest@^4.1.10, zod@^4.4.3
- video/package.json: @remotion/cli@4.0.490, @remotion/eslint-config-flat@4.0.490, @remotion/google-fonts@^4.0.490, @remotion/media@^4.0.490, @remotion/tailwind-v4@4.0.490, @types/react@19.2.7, @types/web@0.0.166, eslint@9.19.0, mediabunny@^1.50.8, openai@^6.47.0, prettier@3.8.1, react@19.2.3, react-dom@19.2.3, remotion@4.0.490, tailwindcss@4.0.0, typescript@5.9.3

### Recent commits (newest first)

- fix(demo): restore clean synthetic state on reset
- docs: complete Build Week submission evidence
- docs: define production readiness gates
- style(copy): remove em dashes
- test(e2e): verify production demo entry flows
- feat(ai): upgrade illustrations to GPT Image 2
- fix(ui): capitalise status labels
- docs(video): add recording runbook
- docs(release): mark repository public
- feat(site): adopt BridgeBack custom domain
- fix(learning): improve generated visual explanations
- fix(concept-map): inset node status icons
- fix(teacher): align concept map controls
- test(realtime): verify production voice sessions
- fix(demo): clarify learning feedback and mobile navigation
- docs(release): prepare deployment and submission draft
- feat(maths): complete the curriculum re-entry journey
- feat(voice): add realtime learning conversations
- feat(curriculum): add OCR specification pathways
- feat: add mathematics demo and Build Week film

## Key source files (fetched from GitHub, selected and truncated for size)

### CLAUDE.md

```markdown
@AGENTS.md

```

### AGENTS.md

```markdown
<!-- BEGIN:nextjs-agent-rules -->
# This is NOT the Next.js you know

This version has breaking changes. APIs, conventions, and file structure may all differ from your training data. Read the relevant guide in `node_modules/next/dist/docs/` before writing any code. Heed deprecation notices.
<!-- END:nextjs-agent-rules -->

## Commit Checkpoints

- At the end of every completed Codex turn that changes the repository, create a commit containing the changes made during that turn.
- Use Conventional Commits for every commit. Format messages as `<type>(<optional scope>): <description>`; use types such as `feat`, `fix`, `refactor`, `docs`, `test`, `chore`, and `build`.
- Keep commits focused on the work completed in that turn. Do not combine unrelated changes into one commit.
- Before committing, run the relevant validation for the changed files and inspect `git diff --staged`.

```

### package.json

```
{
  "name": "bridgeback",
  "version": "0.1.0",
  "private": true,
  "scripts": {
    "dev": "next dev",
    "build": "next build",
    "typecheck": "tsc --noEmit",
    "start": "next start",
    "lint": "eslint",
    "test": "vitest run --exclude tests/e2e/**",
    "test:e2e": "playwright test",
    "verify": "npm run typecheck && npm run lint && npm test && npm run build"
  },
  "dependencies": {
    "@base-ui/react": "^1.6.0",
    "@clerk/nextjs": "^7.5.17",
    "@xyflow/react": "^12.11.2",
    "class-variance-authority": "^0.7.1",
    "clsx": "^2.1.1",
    "convex": "^1.42.1",
    "lucide-react": "^1.24.0",
    "next": "16.2.10",
    "openai": "^6.46.0",
    "react": "19.2.4",
    "react-dom": "19.2.4",
    "shadcn": "^4.13.0",
    "tailwind-merge": "^3.6.0",
    "tw-animate-css": "^1.4.0",
    "zod": "^4.4.3"
  },
  "devDependencies": {
    "@axe-core/playwright": "^4.12.1",
    "@playwright/test": "^1.61.1",
    "@tailwindcss/postcss": "^4",
    "@types/node": "^20",
    "@types/react": "^19",
    "@types/react-dom": "^19",
    "eslint": "^9",
    "eslint-config-next": "16.2.10",
    "tailwindcss": "^4",
    "typescript": "^5",
    "vitest": "^4.1.10"
  },
  "overrides": {
    "postcss": "^8.5.10"
  }
}

```

### video/package.json

```
{
  "name": "video",
  "version": "1.0.0",
  "description": "Two-minute OpenAI Build Week submission film for BridgeBack",
  "repository": {},
  "license": "Apache-2.0",
  "type": "module",
  "private": true,
  "dependencies": {
    "@remotion/cli": "4.0.490",
    "@remotion/google-fonts": "^4.0.490",
    "@remotion/media": "^4.0.490",
    "@remotion/tailwind-v4": "4.0.490",
    "mediabunny": "^1.50.8",
    "openai": "^6.47.0",
    "react": "19.2.3",
    "react-dom": "19.2.3",
    "remotion": "4.0.490",
    "tailwindcss": "4.0.0"
  },
  "devDependencies": {
    "@remotion/eslint-config-flat": "4.0.490",
    "@types/react": "19.2.7",
    "@types/web": "0.0.166",
    "eslint": "9.19.0",
    "prettier": "3.8.1",
    "typescript": "5.9.3"
  },
  "scripts": {
    "dev": "remotion studio",
    "build": "remotion bundle",
    "render": "remotion render BridgeBackBuildWeek out/bridgeback-build-week.mp4",
    "still": "remotion still BridgeBackBuildWeek out/bridgeback-preview.png --frame=1500",
    "voiceover": "node --strip-types scripts/generate-voiceover.ts",
    "upgrade": "remotion upgrade",
    "lint": "eslint src && tsc"
  },
  "sideEffects": [
    "*.css"
  ]
}

```

### video/src/index.ts

```typescript
import { registerRoot } from "remotion";
import { RemotionRoot } from "./Root";

registerRoot(RemotionRoot);

```

### src/app/layout.tsx

```typescript
import type { Metadata } from "next";
import { Geist_Mono, Montserrat } from "next/font/google";
import { AppProviders } from "@/components/app-providers";
import "./globals.css";

const montserrat = Montserrat({
  variable: "--font-montserrat",
  subsets: ["latin"],
  display: "swap",
});

const geistMono = Geist_Mono({
  variable: "--font-geist-mono",
  subsets: ["latin"],
});

export const metadata: Metadata = {
  metadataBase: new URL("https://bridgeback.phaseo.app"),
  title: "BridgeBack | The shortest path back into learning",
  description:
    "BridgeBack finds the few concepts a returning pupil needs to understand the next lesson, with a teacher-guided learning pathway.",
  alternates: {
    canonical: "/",
  },
  openGraph: {
    type: "website",
    url: "/",
    title: "BridgeBack | The shortest path back into learning",
    description:
      "BridgeBack finds the few concepts a returning pupil needs to understand the next lesson, with a teacher-guided learning pathway.",
  },
  icons: {
    icon: [{ url: "/bridgeback-icon.svg", type: "image/svg+xml", sizes: "any" }],
    shortcut: "/bridgeback-icon.svg",
  },
};

export default function RootLayout({
  children,
}: Readonly<{
  children: React.ReactNode;
}>) {
  return (
    <html
      lang="en"
      className={`${montserrat.variable} ${geistMono.variable} h-full antialiased`}
    >
      <body className="flex min-h-full flex-col">
        <AppProviders>{children}</AppProviders>
      </body>
    </html>
  );
}

```

### convex/_generated/server.js

```javascript
/* eslint-disable */
/**
 * Generated utilities for implementing server-side Convex query and mutation functions.
 *
 * THIS CODE IS AUTOMATICALLY GENERATED.
 *
 * To regenerate, run `npx convex dev`.
 * @module
 */

import {
  actionGeneric,
  httpActionGeneric,
  queryGeneric,
  mutationGeneric,
  internalActionGeneric,
  internalMutationGeneric,
  internalQueryGeneric,
} from "convex/server";

/**
 * Define a query in this Convex app's public API.
 *
 * This function will be allowed to read your Convex database and will be accessible from the client.
 *
 * @param func - The query function. It receives a {@link QueryCtx} as its first argument.
 * @returns The wrapped query. Include this as an `export` to name it and make it accessible.
 */
export const query = queryGeneric;

/**
 * Define a query that is only accessible from other Convex functions (but not from the client).
 *
 * This function will be allowed to read from your Convex database. It will not be accessible from the client.
 *
 * @param func - The query function. It receives a {@link QueryCtx} as its first argument.
 * @returns The wrapped query. Include this as an `export` to name it and make it accessible.
 */
export const internalQuery = internalQueryGeneric;

/**
 * Define a mutation in this Convex app's public API.
 *
 * This function will be allowed to modify your Convex database and will be accessible from the client.
 *
 * @param func - The mutation function. It receives a {@link MutationCtx} as its first argument.
 * @returns The wrapped mutation. Include this as an `export` to name it and make it accessible.
 */
export const mutation = mutationGeneric;

/**
 * Define a mutation that is only accessible from other Convex functions (but not from the client).
 *
 * This function will be allowed to modify your Convex database. It will not be accessible from the client.
 *
 * @param func - The mutation function. It receives a {@link MutationCtx} as its first argument.
 * @returns The wrapped mutation. Include this as an `export` to name it and make it accessible.
 */
export const internalMutation = internalMutationGeneric;

/**
 * Define an action in this Convex app's public API.
 *
 * An action is a function which can execute any JavaScript code, including non-deterministic
 * code and code with side-effects, like calling third-party services.
 * They can be run in Convex's JavaScript environment or in Node.js using the "use node" directive.
 * They can interact with the database indirectly by calling queries and mutations using the {@link ActionCtx}.
 *
 * @param func - The action. It receives an {@link ActionCtx} as its first argument.
 * @returns The wrapped action. Include this as an `export` to name it and make it accessible.
 */
export const action = actionGeneric;

/**
 * Define an action that is only accessible from other Convex functions (but not from the client).
 *
 * @param func - The function. It receives an {@link ActionCtx} as its first argument.
 * @returns The wrapped function. Include this as an `export` to name it and make it accessible.
 */
export const internalAction = internalActionGeneric;

/**
 * Define an HTTP action.
 *
 * The wrapped function will be used to respond to HTTP requests received
 * by a Convex deployment if the requests matches the path and method where
 * this action is routed. Be sure to route your httpAction in `convex/http.js`.
 *
 * @param func - The function. It receives an {@link ActionCtx} as its first argument
 * and a Fetch API `Request` object as its second.
 * @returns The wrapped function. Import this function from `convex/http.js` and route it to hook it up.
 */
export const httpAction = httpActionGeneric;

```

### src/app/app/page.tsx

```typescript
import { ProductWorkspace } from "@/components/product-workspace";
import { requireProductSession } from "@/lib/auth/server";

export default async function ProductPage() { await requireProductSession(); return <ProductWorkspace />; }

```

### src/app/pupil/page.tsx

```typescript
import { DemoHeader } from "@/components/demo-header";
import { PupilJourney } from "@/components/pupil-journey";
import { requireDemoRole } from "@/lib/auth/server";

export default async function PupilPage() {
  await requireDemoRole("pupil");
  return <div className="min-h-screen bg-background"><DemoHeader role="pupil" /><main className="mx-auto w-full max-w-[1480px] px-4 pt-6 sm:px-6 lg:px-8"><PupilJourney /></main></div>;
}

```

### src/app/teacher/page.tsx

```typescript
import { DemoHeader } from "@/components/demo-header";
import { TeacherDashboard } from "@/components/teacher-dashboard";
import { requireDemoRole } from "@/lib/auth/server";

export default async function TeacherPage() {
  await requireDemoRole("teacher");
  return <div className="min-h-screen bg-background"><DemoHeader role="teacher" /><main className="mx-auto w-full max-w-[1480px] px-4 pt-6 sm:px-6 lg:px-8"><TeacherDashboard /></main></div>;
}

```

[101 more indexed source files omitted to keep this export small. The full file list is in the Codebase structure section above.]