> ## Documentation Index
> Fetch the complete documentation index at: https://docs.timeback.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Examples

> Starter templates and reference implementations

Templates and example integrations help you move faster and avoid rework. Use these as starting points for your integration.

## Starter Templates

| Template                  | Framework          | Description                               |
| ------------------------- | ------------------ | ----------------------------------------- |
| `nextjs-app-router`       | Next.js            | App Router with SSO and activity tracking |
| `nuxt`                    | Nuxt 3             | Server middleware with Vue composables    |
| `svelte-kit`              | SvelteKit          | Hooks-based integration with stores       |
| `solid-start`             | SolidStart         | Middleware with primitives                |
| `tanstack-start`          | TanStack Start     | File-based routes with React              |
| `express`                 | Express            | Standalone API server                     |
| `express-auth0`           | Express + Auth0    | Custom auth mode with Auth0               |
| `express-supabase`        | Express + Supabase | Custom auth mode with Supabase            |
| `bun-react`               | Bun + React        | Minimal SSO example                       |
| `bun-react-identity-only` | Bun + React        | Identity-only mode (no activity tracking) |

All templates are available in the [examples directory](https://github.com/superbuilders/timeback-dev/tree/main/examples).

## bun-react

<Info>
  **Source:** [examples/bun-react](https://github.com/superbuilders/timeback-dev/tree/main/examples/bun-react)
</Info>

SSO authentication and activity tracking with Bun server and React frontend.

This example shows the **SDK handlers** (`/api/timeback/*`) plus a simple UI.
For an example that also demonstrates the **direct API escape hatch** (`timeback.api`),
see `examples/bun-react-full`.

### Quick Start

```sh theme={null}
cp .env.example .env
# Add your TIMEBACK_SSO_CLIENT_ID and TIMEBACK_SSO_CLIENT_SECRET
bun install
bun dev
```

### Structure

| File                  | Purpose                         |
| --------------------- | ------------------------------- |
| `src/index.ts`        | Bun server + Timeback routes    |
| `src/lib/timeback.ts` | SSO config + session management |
| `src/App.tsx`         | SignInButton + activity demo    |
| `src/frontend.tsx`    | React entry point               |

### Key Patterns

**Native handler** — Mount Timeback routes:

```typescript theme={null}
// index.ts
import { timebackHandler } from './lib/timeback'

if (url.pathname.startsWith('/api/timeback')) {
	return timebackHandler(request)
}
```

**SignInButton** — Pre-styled SSO button:

```tsx theme={null}
import { SignInButton } from '@timeback/sdk/react'

;<SignInButton />
```

**Activity tracking** — Track learning time:

```tsx theme={null}
import { useTimeback } from '@timeback/sdk/react'

const timeback = useTimeback()

const activity = timeback.activity.start({
  id: 'lesson_1',
  name: 'Fractions',
  course: { subject: 'FastMath', grade: 3 }, // must match timeback.config.json
})

<p>Time: {activity.totalActiveMs}ms</p>
```

***

## bun-react-full

<Info>
  **Source:** [examples/bun-react-full](https://github.com/superbuilders/timeback-dev/tree/main/examples/bun-react-full)
</Info>

SSO authentication and activity tracking with Bun server and React frontend.

This “full” variant also includes a small demo of **direct API access** via `timeback.api`
(an escape hatch for calling Timeback services like OneRoster).

### Quick Start

```sh theme={null}
cp .env.example .env
# Add your TIMEBACK_SSO_CLIENT_ID and TIMEBACK_SSO_CLIENT_SECRET
bun install
bun dev
```

### Structure

| File                  | Purpose                         |
| --------------------- | ------------------------------- |
| `src/index.ts`        | Bun server + Timeback routes    |
| `src/lib/timeback.ts` | SSO config + session management |
| `src/App.tsx`         | SignInButton + activity demo    |
| `src/frontend.tsx`    | React entry point               |

### Key Patterns

**Native handler** — Mount Timeback routes:

```typescript theme={null}
// index.ts
import { timebackHandler } from './lib/timeback'

if (url.pathname.startsWith('/api/timeback')) {
	return timebackHandler(request)
}
```

**SignInButton** — Pre-styled SSO button:

```tsx theme={null}
import { SignInButton } from '@timeback/sdk/react'

;<SignInButton />
```

**Activity tracking** — Track learning time:

```tsx theme={null}
import { useActivity } from '@timeback/sdk/react'

const activity = useActivity({
  id: 'lesson_1',
  name: 'Fractions',
  course: { subject: 'FastMath', grade: 3 } // must match a unique course in timeback.config.json
})

<p>Time: {activity.totalActiveMs}ms</p>
```

***

## bun-react-gradeless

<Info>
  **Source:** [examples/bun-react-gradeless](https://github.com/superbuilders/timeback-dev/tree/main/examples/bun-react-gradeless)
</Info>

SSO authentication and activity tracking for **grade-less apps** (e.g., CS platforms).

This example demonstrates using `courseCode` instead of `(subject, grade)` for course identity.

### Quick Start

```sh theme={null}
cp .env.example .env
# Add your TIMEBACK_SSO_CLIENT_ID and TIMEBACK_SSO_CLIENT_SECRET
bun install
bun dev
```

### Grade-less Course Configuration

Apps without grade levels use `courseCode` as the course identifier:

```json theme={null}
// timeback.config.json
{
	"$schema": "https://timeback.dev/schema.json",
	"name": "CodeQuest",
	"courses": [
		{
			"subject": "Other",
			"courseCode": "INTRO-CS-101",
			"ids": { "staging": "...", "production": "..." }
		},
		{
			"subject": "Other",
			"courseCode": "DATA-STRUCTURES-201",
			"ids": { "staging": "...", "production": "..." }
		}
	]
}
```

### Activity Tracking with courseCode

When evaluating examples, it’s often useful to **preview what would be sent**
without actually sending Caliper events. This example uses:

* normal `activity.end(...)` (production-like)
* a server-side hook (`beforeActivitySend`) to optionally skip sending and log what *would* be sent

#### Demo toggle

In `.env`:

```sh theme={null}
# 0 = preview (log would-send events, do not send)
# 1 = send for real
TIMEBACK_DEMO_SEND_ACTIVITY=0
```

Compare this to grade-based apps (see `examples/bun-react`):

```tsx theme={null}
// Grade-based
course: { subject: 'Math', grade: 3 }
```

### Structure

| File                   | Purpose                         |
| ---------------------- | ------------------------------- |
| `src/index.ts`         | Bun server + Timeback routes    |
| `src/lib/timeback.ts`  | SSO config + session management |
| `src/App.tsx`          | SignInButton + activity demo    |
| `timeback.config.json` | Grade-less course configuration |

***

## bun-react-identity-only

<Info>
  **Source:** [examples/bun-react-identity-only](https://github.com/superbuilders/timeback-dev/tree/main/examples/bun-react-identity-only)
</Info>

SSO authentication with Bun server and React frontend — **no activity tracking**.

This example demonstrates `createTimebackIdentity()` for apps that only need Timeback SSO without the full SDK.

### Quick Start

```sh theme={null}
cp .env.example .env
# Add your TIMEBACK_SSO_CLIENT_ID and TIMEBACK_SSO_CLIENT_SECRET
bun install
bun dev
```

### Structure

| File                  | Purpose                         |
| --------------------- | ------------------------------- |
| `src/index.ts`        | Bun server + Timeback routes    |
| `src/lib/timeback.ts` | SSO config + session management |
| `src/App.tsx`         | SignInButton + session display  |
| `src/frontend.tsx`    | React entry point               |

### Key Differences from Full SDK

* Uses `createTimebackIdentity()` instead of `createTimeback()`
* No `api` credentials required
* No `timeback.config.json` required
* Only identity routes are available (no activity tracking)

### Key Patterns

**Identity-only server** — No API credentials needed:

```typescript theme={null}
// lib/timeback.ts
import { createTimebackIdentity } from '@timeback/sdk'

export const timeback = createTimebackIdentity({
	env: 'staging',
	identity: {
		mode: 'sso',
		clientId: process.env.TIMEBACK_SSO_CLIENT_ID!,
		clientSecret: process.env.TIMEBACK_SSO_CLIENT_SECRET!,
		onCallbackSuccess: ({ user, redirect }) => {
			setSession(user)
			return redirect('/')
		},
		getUser: () => getSession(),
	},
})
```

**SignInButton** — Pre-styled SSO button:

```tsx theme={null}
import { SignInButton } from '@timeback/sdk/react'

;<SignInButton />
```

***

## bun-react-resumable

<Info>
  **Source:** [examples/bun-react-resumable](https://github.com/superbuilders/timeback-dev/tree/main/examples/bun-react-resumable)
</Info>

SSO authentication and activity tracking with Bun server and React frontend.

This example shows the **SDK handlers** (`/api/timeback/*`) plus a simple UI.
For an example that also demonstrates the **direct API escape hatch** (`timeback.api`),
see `examples/bun-react-full`.

### Quick Start

```sh theme={null}
cp .env.example .env
# Add your TIMEBACK_SSO_CLIENT_ID and TIMEBACK_SSO_CLIENT_SECRET
bun install
bun dev
```

### Structure

| File                  | Purpose                         |
| --------------------- | ------------------------------- |
| `src/index.ts`        | Bun server + Timeback routes    |
| `src/lib/timeback.ts` | SSO config + session management |
| `src/App.tsx`         | SignInButton + activity demo    |
| `src/frontend.tsx`    | React entry point               |

### Key Patterns

**Native handler** — Mount Timeback routes:

```typescript theme={null}
// index.ts
import { timebackHandler } from './lib/timeback'

if (url.pathname.startsWith('/api/timeback')) {
	return timebackHandler(request)
}
```

**SignInButton** — Pre-styled SSO button:

```tsx theme={null}
import { SignInButton } from '@timeback/sdk/react'

;<SignInButton />
```

**Activity tracking** — Track learning time:

```tsx theme={null}
import { useTimeback } from '@timeback/sdk/react'

const timeback = useTimeback()

const activity = timeback.activity.start({
  id: 'lesson_1',
  name: 'Fractions',
  course: { subject: 'FastMath', grade: 3 }, // must match timeback.config.json
})

<p>Time: {activity.totalActiveMs}ms</p>
```

***

## express

<Info>
  **Source:** [examples/express](https://github.com/superbuilders/timeback-dev/tree/main/examples/express)
</Info>

Minimal Express.js backend demonstrating the Timeback SDK's Express adapter.

### Quick Start

```bash theme={null}
bun install
bun dev
```

### Verify Routes

Run the verification script to test all routes:

```bash theme={null}
bun run verify
```

This starts the server, tests all endpoints, and reports results.

### Routes

| Method | Path                               | Description           |
| ------ | ---------------------------------- | --------------------- |
| GET    | `/health`                          | Health check          |
| GET    | `/api/timeback/identity/signin`    | Initiate SSO sign-in  |
| GET    | `/api/timeback/identity/callback`  | SSO callback handler  |
| GET    | `/api/timeback/identity/signout`   | Sign out              |
| POST   | `/api/timeback/activity/heartbeat` | Submit time heartbeat |
| POST   | `/api/timeback/activity/submit`    | Submit completion     |

### Testing

```bash theme={null}
# Health check
curl http://localhost:3000/health

# Submit heartbeat (requires authentication)
curl -X POST http://localhost:3000/api/timeback/activity/heartbeat \
  -H "Content-Type: application/json" \
  -d '{
    "id": "lesson-123",
    "name": "Introduction to Fractions",
    "course": { "subject": "FastMath", "grade": 3 },
    "runId": "11111111-1111-1111-1111-111111111111",
    "startedAt": "2026-01-16T10:00:00Z",
    "endedAt": "2026-01-16T10:05:00Z",
    "elapsedMs": 300000,
    "pausedMs": 0
  }'

# Submit completion (requires authentication)
curl -X POST http://localhost:3000/api/timeback/activity/submit \
  -H "Content-Type: application/json" \
  -d '{
    "id": "lesson-123",
    "name": "Introduction to Fractions",
    "course": { "subject": "FastMath", "grade": 3 },
    "runId": "11111111-1111-1111-1111-111111111111",
    "endedAt": "2026-01-16T10:05:00Z",
    "metrics": { "totalQuestions": 10, "correctQuestions": 8, "xpEarned": 80 }
  }'
```

### Integration Options

The SDK provides two ways to integrate with Express:

#### Option 1: Middleware (recommended)

```typescript theme={null}
import { toExpressMiddleware } from '@timeback/sdk/express'

app.use('/api/timeback', toExpressMiddleware(timeback))
```

#### Option 2: Router mounting

```typescript theme={null}
import { mountExpressRoutes } from '@timeback/sdk/express'

const router = express.Router()
mountExpressRoutes(timeback, router)
app.use('/api/timeback', router)
```

***

## express-auth0

<Info>
  **Source:** [examples/express-auth0](https://github.com/superbuilders/timeback-dev/tree/main/examples/express-auth0)
</Info>

Demonstrates using the Timeback SDK with **Auth0** as a custom identity provider.

This example uses Auth0's **email/password authentication** (Resource Owner Password Grant) with the official `auth0` Node.js SDK.

### Architecture

```
┌─────────────────────────────────────────────────────────────────┐
│                         Frontend (React)                        │
│  ┌─────────────┐    ┌─────────────┐    ┌─────────────────────┐  │
│  │ Login Form  │───▶│ POST /auth  │───▶│ Session Cookie Set  │  │
│  │ email/pass  │    │   /login    │    │ User State Updated  │  │
│  └─────────────┘    └─────────────┘    └─────────────────────┘  │
│                                                                 │
│  ┌─────────────────────────────────────────────────────────┐    │
│  │              TimebackProvider + useTimeback             │    │
│  │  • Activity tracking      • Profile fetching            │    │
│  │  • Requests include session cookie automatically        │    │
│  └─────────────────────────────────────────────────────────┘    │
└─────────────────────────────────────────────────────────────────┘
                              │
                              ▼
┌─────────────────────────────────────────────────────────────────┐
│                      Backend (Express)                          │
│  ┌─────────────────┐    ┌─────────────────────────────────────┐ │
│  │ POST /auth/login│───▶│ Auth0 SDK (passwordGrant)           │ │
│  │                 │    │ Validates credentials with Auth0    │ │
│  │                 │◀───│ Returns user info + tokens          │ │
│  │                 │    └─────────────────────────────────────┘ │
│  │ Creates session │                                            │
│  │ cookie (JWT)    │                                            │
│  └─────────────────┘                                            │
│                                                                 │
│  ┌─────────────────────────────────────────────────────────┐    │
│  │                    Timeback SDK                         │    │
│  │  identity.mode: 'custom'                                │    │
│  │  getEmail: parses session cookie → returns email        │    │
│  └─────────────────────────────────────────────────────────┘    │
└─────────────────────────────────────────────────────────────────┘
```

### Auth0 Setup

1. **Create an Auth0 Application**
   * Go to Auth0 Dashboard → Applications → Create Application
   * Choose "Regular Web Application"
   * Note your **Domain**, **Client ID**, and **Client Secret**

2. **Enable Password Grant**
   * In your application settings, go to **Advanced Settings** → **Grant Types**
   * Enable **Password** grant type

3. **Create a Database Connection** (if you don't have one)
   * Go to Authentication → Database → Create Connection
   * Enable it for your application

4. **Create Test Users**
   * Go to User Management → Users → Create User
   * Create users with email/password

### Quick Start

```bash theme={null}
# Install dependencies
just install

# Copy environment template
just setup

# Edit .env with your Auth0 credentials
# Then start development servers
just dev
```

### Environment Variables

Create `.env` from `.env.example`:

```bash theme={null}
# Auth0 (from your Auth0 Dashboard)
AUTH0_DOMAIN=your-tenant.auth0.com
AUTH0_CLIENT_ID=your-client-id
AUTH0_CLIENT_SECRET=your-client-secret

# Session secret (generate with: openssl rand -base64 32)
SESSION_SECRET=your-random-secret

# Timeback API (from Timeback Dashboard)
TIMEBACK_API_CLIENT_ID=your-timeback-client-id
TIMEBACK_API_CLIENT_SECRET=your-timeback-client-secret
```

### How It Works

#### 1. User Login

User submits email/password → Backend calls Auth0's password grant → Auth0 validates → Returns user info → Backend creates signed JWT session cookie.

#### 2. Session Management

The session cookie contains `{ sub, email, name }` signed with HS256. It's httpOnly, secure in production, and lasts 7 days.

#### 3. Timeback Integration

```typescript theme={null}
// backend/src/lib/timeback.ts
export const timeback = await createTimeback({
	identity: {
		mode: 'custom',
		getEmail: async req => {
			const session = await getSessionFromCookieHeader(req.headers.get('cookie'))
			return session?.email
		},
	},
	// ...
})
```

The SDK calls `getEmail(req)` on each request. We parse the cookie header, verify the JWT, and return the user's email. The SDK then resolves the Timeback user by email.

#### 4. Frontend Activity Tracking

```tsx theme={null}
const timeback = useTimeback()

// Start tracking
const activity = timeback.activity.start({ id: 'lesson_1', name: 'Intro to Fractions' })

// End with results
await activity.end({ xpEarned: 100, correctQuestions: 8, totalQuestions: 10 })
```

### Project Structure

```
express-auth0/
├── backend/
│   ├── src/
│   │   ├── index.ts           # Express server & routes
│   │   └── lib/
│   │       ├── auth0.ts       # Auth0 SDK wrapper
│   │       ├── session.ts     # JWT session cookie helpers
│   │       └── timeback.ts    # Timeback SDK instance
│   └── package.json
├── frontend/
│   ├── src/
│   │   ├── App.tsx            # Main app with login form
│   │   ├── main.tsx           # Entry point with TimebackProvider
│   │   └── components/
│   └── package.json
├── .env.example
├── justfile
└── README.md
```

### API Routes

| Method | Route                              | Description                |
| ------ | ---------------------------------- | -------------------------- |
| GET    | `/health`                          | Health check               |
| POST   | `/auth/login`                      | Login with email/password  |
| POST   | `/auth/logout`                     | Clear session cookie       |
| GET    | `/api/session`                     | Get current user           |
| GET    | `/api/timeback/user/me`            | Timeback user profile      |
| POST   | `/api/timeback/activity/heartbeat` | Submit time heartbeat      |
| POST   | `/api/timeback/activity/submit`    | Submit activity completion |

### Troubleshooting

#### "Invalid email or password"

* Verify the user exists in Auth0 (User Management → Users)
* Check that the Password grant type is enabled
* Ensure the database connection is enabled for your app

#### "Auth0 is not configured"

* Check `AUTH0_DOMAIN`, `AUTH0_CLIENT_ID`, `AUTH0_CLIENT_SECRET` in `.env`
* Domain should be just `your-tenant.auth0.com` (no `https://`)

#### Session not persisting

* Check browser dev tools → Application → Cookies
* In development, cookies work on `localhost`
* The Vite proxy ensures same-origin for cookie handling

#### CORS errors

* The Vite dev server proxies `/auth` and `/api` to the backend
* No CORS configuration needed in development

***

## express-auth0-launch-gate

<Info>
  **Source:** [examples/express-auth0-launch-gate](https://github.com/superbuilders/timeback-dev/tree/main/examples/express-auth0-launch-gate)
</Info>

Activity tracking demo using Auth0 Universal Login (SPA + PKCE) in the frontend and Bearer-token auth in the backend, with a **launch-gated** entry URL (`/timeback/signin`).

### Architecture

```
┌─────────────────────────────────────────────────────────────┐
│  Frontend (React + Auth0 React SDK + @timeback/sdk)          │
│  - Auth0 Universal Login (PKCE)                              │
│  - Activity tracking with useTimeback()                     │
│  - Profile viewer                                           │
└─────────────────────────────────────────────────────────────┘
                              │
                  GET  /api/user/me    (Bearer)
                  POST /api/timeback/activity/* (Bearer)
                  GET  /api/timeback/user/me  (Bearer)
                              │
                              ▼
┌─────────────────────────────────────────────────────────────┐
│  Backend (Express + Timeback SDK)                            │
│  - Validates Bearer JWTs via Auth0 JWKS                      │
│  - Custom identity mode (SDK resolves user by email claim)   │
│  - Activity tracking via Caliper                             │
└─────────────────────────────────────────────────────────────┘
                              │
                              ▼
┌─────────────────────────────────────────────────────────────┐
│  Auth0                       │  Timeback API                │
│  - User authentication       │  - User resolution by email  │
│  - Password management       │  - Activity ingestion        │
└─────────────────────────────────────────────────────────────┘
```

### How It Works

1. **Auth0 handles authentication** - Frontend uses Auth0 Universal Login (Authorization Code + PKCE)
2. **Frontend calls backend with Bearer token** - API requests include `Authorization: Bearer {'<'}access_token{'>'}`
3. **Backend validates token** - using Auth0 JWKS + issuer + audience
4. **SDK uses custom identity mode** - The `getEmail` callback reads email from the request
5. **SDK resolves Timeback user** - When submitting activity, SDK looks up the Timeback user by email

This pattern is ideal when:

* You have an existing Auth0 SPA
* Your backend is a resource server (Bearer JWT auth)
* You want a dedicated Timeback launch URL (`/timeback/signin`) without a separate "Sign in with Timeback" button

### Quick Start

#### 1. Auth0 Setup

1. Create an **API** in Auth0 (Applications → APIs) and copy its **Identifier** (this is the audience)
2. Create a **Single Page Application** in Auth0 (Applications → Applications)
3. In the SPA settings, set:
   * Allowed Callback URLs: `http://localhost:5173`
   * Allowed Logout URLs: `http://localhost:5173`
   * Allowed Web Origins: `http://localhost:5173`
4. Ensure the Database connection is enabled for the SPA (email/password hosted by Auth0)

#### 2. Environment Setup

```sh theme={null}
cd examples/express-auth0-launch-gate
cp .env.example .env
```

Edit `.env` with your credentials.

#### 3. Install and Run

```sh theme={null}
just install
just dev
```

Open [http://localhost:5173](http://localhost:5173)

#### Launch-gated URL

Visit `http://localhost:5173/timeback/signin` to simulate the Timeback launch URL.

### Commands

| Command             | Description                  |
| ------------------- | ---------------------------- |
| `just install`      | Install backend + frontend   |
| `just dev`          | Start backend + frontend     |
| `just dev-backend`  | Start backend only           |
| `just dev-frontend` | Start frontend only          |
| `just setup`        | Copy `.env.example` → `.env` |

### API Endpoints

#### Auth Endpoints

This example uses **Auth0 Universal Login (SPA + PKCE)**, so there are **no** backend
`/auth/*` routes. The backend behaves like a typical resource server: it only
validates `Authorization: Bearer {'<'}access_token{'>'}`.

#### Timeback SDK Endpoints

| Endpoint                           | Method | Description                 |
| ---------------------------------- | ------ | --------------------------- |
| `/api/timeback/activity/heartbeat` | POST   | Submit time heartbeat       |
| `/api/timeback/activity/submit`    | POST   | Submit activity completion  |
| `/api/timeback/user/me`            | GET    | Get Timeback user profile   |
| `/api/timeback/user/verify`        | GET    | Verify Timeback user status |

#### Session Endpoints

| Endpoint       | Method | Description  |
| -------------- | ------ | ------------ |
| `/api/health`  | GET    | Health check |
| `/api/user/me` | GET    | Auth0 user   |

### Project Structure

```
express-auth0-launch-gate/
├── backend/
│   ├── src/
│   │   ├── index.ts           # Express server & routes
│   │   └── lib/
│   │       ├── auth.ts        # Bearer auth middleware
│   │       └── timeback.ts    # Timeback SDK instance
│   └── package.json
├── frontend/
│   └── src/
│       ├── App.tsx            # React app (Auth0 + launch gate)
│       └── main.tsx           # Auth0Provider + TimebackProvider
├── .env.example
├── justfile
└── README.md
```

***

## express-supabase

<Info>
  **Source:** [examples/express-supabase](https://github.com/superbuilders/timeback-dev/tree/main/examples/express-supabase)
</Info>

Demonstrates using the Timeback SDK with Supabase as a custom identity provider.

### Architecture

```
┌─────────────────────────────────────────────────────────────────┐
│                         Frontend (React)                        │
│  ┌───────────────────────────────────────────────────────────┐  │
│  │  Login/Signup Form → POST /auth/login or /auth/signup     │  │
│  │  Activity Tracking → SDK React hooks                      │  │
│  └───────────────────────────────────────────────────────────┘  │
└─────────────────────────────────────────────────────────────────┘
                              │
                              ▼
┌─────────────────────────────────────────────────────────────────┐
│                      Backend (Express)                          │
│  ┌───────────────────────────────────────────────────────────┐  │
│  │  /auth/login    → Supabase signInWithPassword             │  │
│  │  /auth/signup   → Supabase signUp                         │  │
│  │  /auth/logout   → Clear session                           │  │
│  │  /api/session   → Return session user                     │  │
│  │  /api/timeback  → Timeback SDK routes                     │  │
│  └───────────────────────────────────────────────────────────┘  │
│                                                                 │
│  Session: iron-session (encrypted cookie)                       │
│                                                                 │
│  Timeback SDK:                                                  │
│    identity: { mode: 'custom', getEmail: req => ... }           │
└─────────────────────────────────────────────────────────────────┘
                              │
              ┌───────────────┴───────────────┐
              ▼                               ▼
┌──────────────────────┐         ┌──────────────────────┐
│      Supabase        │         │    Timeback API      │
│  (Authentication)    │         │  (Activity Events)   │
└──────────────────────┘         └──────────────────────┘
```

### Setup

#### 1. Install dependencies

```bash theme={null}
just install
```

#### 2. Configure environment

```bash theme={null}
just setup
```

Edit `.env` with your credentials:

* **Supabase**: Get URL and Publishable key from Supabase Dashboard > Settings > API
* **Timeback**: Get from Timeback Dashboard

#### 3. Create a Supabase user

In your Supabase Dashboard:

1. Go to Authentication > Users
2. Click "Add user" > "Create new user"
3. Enter email and password

#### 4. Start development servers

```bash theme={null}
just dev
```

* Frontend: [http://localhost:5173](http://localhost:5173)
* Backend: [http://localhost:3001](http://localhost:3001)

### Timeback Integration

The SDK is configured with custom identity mode, reading the user's email from the session cookie:

```typescript theme={null}
// backend/src/lib/timeback.ts
export const timeback = await createTimeback({
	env: 'staging',
	identity: {
		mode: 'custom',
		getEmail: req => getEmailFromCookieHeader(req.headers.get('cookie')),
	},
	api: {
		clientId: process.env.TIMEBACK_API_CLIENT_ID,
		clientSecret: process.env.TIMEBACK_API_CLIENT_SECRET,
	},
})
```

### Available Commands

| Command             | Description                 |
| ------------------- | --------------------------- |
| `just install`      | Install all dependencies    |
| `just setup`        | Create `.env` from template |
| `just dev`          | Start both servers          |
| `just dev-backend`  | Start backend only          |
| `just dev-frontend` | Start frontend only         |

***

## nextjs-app-router

<Info>
  **Source:** [examples/nextjs-app-router](https://github.com/superbuilders/timeback-dev/tree/main/examples/nextjs-app-router)
</Info>

SSO authentication and activity tracking with Next.js App Router.

### Quick Start

```sh theme={null}
cp .env.example .env
# Add your TIMEBACK_SSO_CLIENT_ID and TIMEBACK_SSO_CLIENT_SECRET
bun install
bun run dev
```

### Structure

| File                                      | Purpose                         |
| ----------------------------------------- | ------------------------------- |
| `src/app/api/timeback/[...timeback]/`     | Timeback request handler        |
| `src/app/api/auth/sso/callback/timeback/` | Custom OAuth callback           |
| `src/lib/timeback.ts`                     | SSO config + session management |
| `src/app/page.tsx`                        | SignInButton + activity demo    |

### Key Patterns

**API routes** — Handle auth routes via `toNextjsHandler`:

```typescript theme={null}
// api/timeback/[...timeback]/route.ts
import { toNextjsHandler } from '@timeback/sdk/nextjs'

import { timeback } from '@/lib/timeback'

export const { GET, POST } = toNextjsHandler(timeback)
```

**SignInButton** — Pre-styled SSO button:

```tsx theme={null}
import { SignInButton } from '@timeback/sdk/react'

;<SignInButton />
```

**Activity tracking** — Track learning time:

```tsx theme={null}
import { useTimeback } from '@timeback/sdk/react'

function MyComponent() {
	const timeback = useTimeback()

	useEffect(() => {
		const activity = timeback?.activity.start({
			id: 'lesson-1',
			name: 'Fractions',
			courseCode: 'MATH-101',
		})

		return () => activity?.end({ xpEarned: 100 })
	}, [timeback])
}
```

***

## nuxt

<Info>
  **Source:** [examples/nuxt](https://github.com/superbuilders/timeback-dev/tree/main/examples/nuxt)
</Info>

Look at the [Nuxt documentation](https://nuxt.com/docs/getting-started/introduction) to learn more.

### Setup

Make sure to install dependencies:

```bash theme={null}
# npm
npm install

# pnpm
pnpm install

# yarn
yarn install

# bun
bun install
```

### Development Server

Start the development server on `http://localhost:3000`:

```bash theme={null}
# npm
npm run dev

# pnpm
pnpm dev

# yarn
yarn dev

# bun
bun run dev
```

### Production

Build the application for production:

```bash theme={null}
# npm
npm run build

# pnpm
pnpm build

# yarn
yarn build

# bun
bun run build
```

Locally preview production build:

```bash theme={null}
# npm
npm run preview

# pnpm
pnpm preview

# yarn
yarn preview

# bun
bun run preview
```

Check out the [deployment documentation](https://nuxt.com/docs/getting-started/deployment) for more information.

***

## qti-with-powerpath

<Info>
  **Source:** [examples/qti-with-powerpath](https://github.com/superbuilders/timeback-dev/tree/main/examples/qti-with-powerpath)
</Info>

Demonstrates real PowerPath API integration for adaptive learning and standard quizzes.

**This example calls the actual PowerPath API** - no local simulation. The app only:

1. Renders questions from PowerPath
2. Submits answers to PowerPath
3. Displays results from PowerPath

### Quick Start

```sh theme={null}
# 1. Copy environment file and add your credentials
cp .env.example .env

# 2. Install dependencies
bun install

# 3. Run the setup script (creates courses, uploads questions, configures PowerPath)
bun run setup

# 4. Start the dev server
bun dev
```

Open [http://localhost:5174](http://localhost:5174) to take a quiz.

### Two Quiz Types

| Type              | Lesson Type     | Questions | Pass Threshold | Algorithm                     |
| ----------------- | --------------- | --------- | -------------- | ----------------------------- |
| **PowerPath 100** | `powerpath-100` | 30        | 80% PP score   | Adaptive - adjusts difficulty |
| **Static Quiz**   | `quiz`          | 5         | None           | Standard - sequential         |

Both use the same PowerPath API endpoints - the `lessonType` determines behavior.

#### What is PowerPath 100?

PowerPath 100 refers to the `powerpath-100` lesson type that uses PowerPath's adaptive algorithm. The "100" comes from the goal: reaching a PowerPath score of 100.

**How the algorithm works:**

* Score starts at 0 and the goal is to reach 100
* Question difficulty is selected based on current score:
  * **0-49**: Easy questions
  * **50-89**: Medium + Hard mix (75%/25%)
  * **90-99**: Hard questions only
* Correct answers increase your score; incorrect answers decrease it
* 80% PP score is the passing threshold (but the quiz continues until 100 or questions exhausted)

The PP score is weighted - harder questions have more impact. A student with 100% accuracy sees \~11 questions; 80% accuracy sees \~18 questions.

### Architecture

```
User → App → PowerPath API
         ↳ Renders question
         ↳ Submits answer
         ↳ PowerPath decides next question
```

The app does NOT implement any quiz logic. PowerPath handles:

* Which question to show next
* Difficulty adaptation (for PowerPath 100)
* Scoring and pass/fail determination
* Attempt tracking

### Project Structure

| File/Folder              | Purpose                                                       |
| ------------------------ | ------------------------------------------------------------- |
| `src/index.ts`           | Bun server entry point with route definitions                 |
| `src/routes/quiz.ts`     | API routes that call PowerPath                                |
| `src/lib/config.ts`      | Loads lesson config from OneRoster                            |
| `src/lib/timeback.ts`    | SDK initialization                                            |
| `src/components/`        | React UI (Landing, Quiz, Results, AttemptList, AttemptReview) |
| `scripts/setup-all.ts`   | Creates org, course, QTI items, and PowerPath lessons         |
| `samples/questions.json` | 30 questions in JSON format                                   |
| `samples/example.xml`    | Reference QTI 3.0 XML format                                  |

### API Endpoints

#### Quiz Flow

| Endpoint             | Method | Purpose                              |
| -------------------- | ------ | ------------------------------------ |
| `/api/quiz/start`    | POST   | Start a new quiz attempt             |
| `/api/quiz/next`     | POST   | Get the next question                |
| `/api/quiz/submit`   | POST   | Submit an answer                     |
| `/api/quiz/complete` | POST   | Finalize the attempt and get results |
| `/api/quiz/progress` | POST   | Get current progress for an attempt  |

#### Attempt History

| Endpoint                    | Method | Purpose                                     |
| --------------------------- | ------ | ------------------------------------------- |
| `/api/quiz/attempts`        | POST   | List all attempts for a lesson              |
| `/api/quiz/attempt-details` | POST   | Get detailed results for a specific attempt |

#### Configuration

| Endpoint                 | Method | Purpose                          |
| ------------------------ | ------ | -------------------------------- |
| `/api/quiz/config`       | GET    | Get lesson IDs and settings      |
| `/api/quiz/user`         | GET    | Get current user info            |
| `/api/health`            | GET    | Health check with setup status   |
| `/api/timeback/activity` | POST   | Time tracking (Timeback handler) |

#### Example: Quiz Flow

```
POST /api/quiz/start { lessonType: 'powerpath-100' }
→ PowerPath: createNewAttempt({ student, lesson })
← { lessonId, attemptId, questionCount }

POST /api/quiz/next { lessonId }
→ PowerPath: getNextQuestion({ student, lesson })
← Question data (PowerPath decides which one)

POST /api/quiz/submit { lessonId, questionId, response }
→ PowerPath: updateStudentQuestionResponse(...)
← { isCorrect, score, ... }

POST /api/quiz/complete { lessonId, lessonType }
→ PowerPath: finalStudentAssessmentResponse({ student, lesson }) (quiz only)
← Final results with PP score
```

### Environment Variables

```bash theme={null}
# Timeback API credentials (same for all services)
TIMEBACK_CLIENT_ID=your_client_id
TIMEBACK_CLIENT_SECRET=your_client_secret
TIMEBACK_ENV=staging

# User email for progress tracking
TIMEBACK_USER_EMAIL=your_email@example.com
```

### Features

#### Attempt History

Users can review past completed attempts:

* View all previous attempts with scores
* Navigate through each question
* See which answers were correct/incorrect
* Compare PP score vs raw accuracy

#### Time Tracking

Time tracking uses the Timeback client SDK in **time-only** mode:

* The client starts an activity at quiz start and calls `activity.end({})` on completion
* The server handler emits a `TimeSpentEvent` (no ActivityCompletedEvent)
* Results show a "Time tracked" indicator
* **Idle detection**: When the user switches tabs or minimizes the window, the activity is automatically paused via `activity.pause()` and resumed via `activity.resume()` on return, so idle time is excluded from the tracked duration

This is separate from PowerPath's grading - it's for learning analytics only.

### Key Points

1. **No local algorithm** - PowerPath handles all quiz logic
2. **Real API calls** - Every action goes through PowerPath
3. **Two lesson types** - Same code, different behavior based on `lessonType`
4. **Setup required** - Must run `bun run setup` before the app works
5. **PP score ≠ accuracy** - PowerPath 100 uses weighted scoring, not raw percent correct

***

## solid-start

<Info>
  **Source:** [examples/solid-start](https://github.com/superbuilders/timeback-dev/tree/main/examples/solid-start)
</Info>

SolidStart app with Timeback SSO authentication and activity tracking.

### Quick Start

```bash theme={null}
cp .env.example .env
# Add your Cognito credentials to .env
bun install
bun dev
```

### File Structure

| File                                           | Purpose                             |
| ---------------------------------------------- | ----------------------------------- |
| `src/lib/timeback.ts`                          | SDK server instance with SSO config |
| `src/routes/api/timeback/[...path].ts`         | Catch-all API route for SDK         |
| `src/routes/api/auth/sso/callback/timeback.ts` | Custom OAuth callback               |
| `src/routes/api/session.ts`                    | Session endpoint                    |
| `src/routes/api/signout.ts`                    | Sign out endpoint                   |
| `src/routes/index.tsx`                         | Main page with auth UI              |

### Key Patterns

**Server SDK** → `toSolidStartHandler(timeback)` in API routes

**Client** → `SignInButton`, `Activity` from `timeback/solid`

**Session** → Server-side store, fetched via `/api/session`

***

## svelte-kit

<Info>
  **Source:** [examples/svelte-kit](https://github.com/superbuilders/timeback-dev/tree/main/examples/svelte-kit)
</Info>

SSO authentication and activity tracking with SvelteKit.

### Quick Start

```sh theme={null}
cp .env.example .env
# Add your TIMEBACK_SSO_CLIENT_ID and TIMEBACK_SSO_CLIENT_SECRET
bun install
bun run dev
```

### Structure

| File                         | Purpose                         |
| ---------------------------- | ------------------------------- |
| `src/hooks.server.ts`        | Timeback request handler        |
| `src/lib/timeback.ts`        | SSO config + session management |
| `src/routes/+page.server.ts` | Pass session to page            |
| `src/routes/+page.svelte`    | SignInButton + activity demo    |

### Key Patterns

**Server hooks** — Handle auth routes via `svelteKitHandler`:

```typescript theme={null}
// hooks.server.ts
export const handle = ({ event, resolve }) =>
	svelteKitHandler({ timeback, event, resolve, building })
```

**SignInButton** — Pre-styled SSO button:

```svelte theme={null}
<script>
	import SignInButton from '@timeback/sdk/svelte/SignInButton.svelte'
</script>

<SignInButton />
```

**Activity tracking** — Track learning time:

```svelte theme={null}
<script>
	import { timeback } from '@timeback/sdk/svelte'
	import { onMount } from 'svelte'

	let activity = $state(undefined)

	onMount(() => {
		activity = $timeback?.activity.start({ id: 'lesson_1', name: 'Fractions', courseCode: 'MATH-101' })
	})
</script>

<button onclick={() => activity?.end({ xpEarned: 100 })}>Submit</button>
```

***

## tanstack-start

<Info>
  **Source:** [examples/tanstack-start](https://github.com/superbuilders/timeback-dev/tree/main/examples/tanstack-start)
</Info>

SSO authentication and activity tracking with TanStack Start.

### Quick Start

```sh theme={null}
cp .env.example .env
# Add your TIMEBACK_SSO_CLIENT_ID and TIMEBACK_SSO_CLIENT_SECRET
bun install
bun dev
```

### File Structure

| File                                           | Purpose                  |
| ---------------------------------------------- | ------------------------ |
| `src/lib/timeback.ts`                          | Server SDK configuration |
| `src/routes/api/timeback/$.ts`                 | Timeback API routes      |
| `src/routes/api/auth/sso/callback/timeback.ts` | Custom OAuth callback    |
| `src/routes/api/session.ts`                    | Session endpoint         |
| `src/routes/api/signout.ts`                    | Sign out endpoint        |
| `src/routes/index.tsx`                         | Main page with SSO demo  |
| `timeback.config.json`                         | Course/app configuration |

### Key Patterns

**Server config** — Configure SSO in `src/lib/timeback.ts`:

```ts theme={null}
export const timeback = await createTimeback({
	env: 'staging',
	identity: {
		mode: 'sso',
		clientId: process.env.TIMEBACK_SSO_CLIENT_ID!,
		clientSecret: process.env.TIMEBACK_SSO_CLIENT_SECRET!,
		redirectUri: 'http://localhost:5174/api/auth/sso/callback/timeback',
		onCallbackSuccess: ({ user, redirect }) => {
			setSession({ id: user.id, email: user.email })
			return redirect('/')
		},
		getUser: () => getSession(),
	},
})
```

**API routes** — Mount Timeback handlers:

```ts theme={null}
// src/routes/api/timeback/$.ts
import { toTanStackStartHandler } from '@timeback/sdk/tanstack-start'

export const Route = createFileRoute('/api/timeback/$')({
	server: { handlers: toTanStackStartHandler(timeback) },
})
```

**Client** — Use the React adapter:

```tsx theme={null}
import { SignInButton, TimebackProvider, useTimeback } from '@timeback/sdk/react'

function App() {
	return (
		<TimebackProvider>
			<SignInButton />
		</TimebackProvider>
	)
}
```

## Next Steps

<CardGroup cols={2}>
  <Card title="Quickstart" icon="rocket" href="/beta/build-on-timeback/start-building/existing-apps">
    Get started with integration
  </Card>

  <Card title="SDK Overview" icon="code" href="/beta/build-on-timeback/sdk/overview">
    Learn about SDK features
  </Card>

  <Card title="Configuration" icon="gear" href="/beta/build-on-timeback/reference/configuration">
    Full config reference
  </Card>

  <Card title="Developer Program" icon="clipboard-check" href="/beta/build-on-timeback/first-steps">
    Apply for access
  </Card>
</CardGroup>
