# @playcademy/sandbox

**Local development server for isolated Playcademy game development.**

The Playcademy sandbox provides a complete local simulation of the Playcademy platform API for development and testing.

## What is the Sandbox?

The sandbox is a local development server that lets you:

- **Develop games locally** with full platform integration.
- **Test SDK functionality** without needing the live platform.
- **Simulate user accounts** and game data in a controlled environment.
- **Work offline** without an internet connection.

It's a "mock Playcademy platform" running on your machine that behaves just like the real thing.

### Key Benefits

- **Isolated Environment**: Completely local execution with no external dependencies.
- **Zero Configuration**: Automatic database setup and seeding.
- **Full API Compatibility**: All Playcademy APIs available locally.
- **Fast Development Cycle**: Quick startup with persistent local database.

## How It Works

The sandbox runs a local API server to provide a complete development environment. When using our Vite templates, this is handled automatically.

```mermaid
graph TD
    subgraph "Your Machine"
        A["Your Game (in browser)"] --> B["@playcademy/sdk"];
        B --> C["API Server (localhost:4321)"];
        C --> D["Local PGlite Database"];
    end
```

## Usage

The easiest way to use the sandbox is with our official Vite templates, which handle everything automatically via the `@playcademy/vite-plugin`. You can also run it manually as a standalone CLI for advanced use cases.

### Automatic Setup (Recommended)

When you start your development server with `bun dev`, the Vite plugin will launch the sandbox in the background.

::: code-group

```bash [bun]
bun dev
```

```bash [pnpm]
pnpm dev
```

```bash [yarn]
yarn dev
```

```bash [npm]
npm run dev
```

:::

You'll see output confirming that the sandbox is running:

```
VITE v6.3.5

➜  Local:   http://localhost:5173/
➜  Network: use --host to expose

PLAYCADEMY v0.1.0

➜  Game:      playground
➜  Sandbox:   http://localhost:4321/api
```

```typescript
// vite.config.ts
import { defineConfig } from 'vite'

import { playcademy } from '@playcademy/vite-plugin'

export default defineConfig({
    plugins: [
        playcademy({
            sandbox: {
                autoStart: true,
            },
        }),
    ],
})
```

### Manual Setup

You can run the sandbox as a standalone process from the command line.

::: code-group

```bash [bun]
# Run with defaults
bunx @playcademy/sandbox

# Run with custom port and verbose logging
bunx @playcademy/sandbox --port 8080 --verbose
```

```bash [pnpm]
pnpm dlx @playcademy/sandbox --port 8080 --verbose
```

```bash [yarn]
yarn dlx @playcademy/sandbox --port 8080 --verbose
```

```bash [npm]
npx @playcademy/sandbox --port 8080 --verbose
```

:::

#### Command-Line Options

| Option                  | Alias | Description                              | Default     |
| :---------------------- | :---- | :--------------------------------------- | :---------- |
| `--port <number>`       | `-p`  | Port for the API server.                 | `4321`      |
| `--verbose`             | `-v`  | Enables verbose logging for debugging.   | `false`     |
| `--quiet`               | `-q`  | Quiet mode (suppress interactive output) | `false`     |
| `--no-seed`             |       | Disables seeding of demo data.           | seeds       |
| `--recreate-db`         |       | Recreate the on-disk database on start.  | `false`     |
| `--memory`              |       | Use in-memory database (no persistence). | `false`     |
| `--db-path <path>`      |       | Custom path for the database file.       | `undefined` |
| `--config-path <path>`  |       | Path to playcademy.config.json.          | `cwd`       |
| `--project-name <name>` |       | Sets the project name for game seeding.  | `undefined` |
| `--project-slug <slug>` |       | Sets the project slug for game seeding.  | `undefined` |

#### Manual SDK Configuration

If you run the sandbox manually, you'll need to configure the SDK client to point to it.

```typescript
import { PlaycademyClient } from '@playcademy/sdk'

const client = await PlaycademyClient.init({
    baseUrl: 'http://localhost:4321/api',
    // In manual mode, you must provide a mock token
    token: 'mock-dev-token',
})
```

## Sandbox Features

| Feature              | Description                                                                                                                                            |
| :------------------- | :----------------------------------------------------------------------------------------------------------------------------------------------------- |
| **API Simulation**   | Emulates the entire Playcademy backend API for users, games, inventory, etc.                                                                           |
| **Data Persistence** | Persists data to disk by default (survives restarts). Use `--recreate-db` to reset, `--memory` for in-memory only, or `--db-path` for custom location. |
| **Mock Data**        | Automatically seeds with demo users and data on first run or when database is empty.                                                                   |
| **Game Context**     | When run via the Vite plugin, it automatically registers your current project as a mock game.                                                          |

## Server Endpoints

Once running, the sandbox provides several key endpoints:

- **Health Check**: `GET /health`
- **API Base URL**: `/api`

All production Playcademy APIs are available under the `/api` prefix, including `/users`, `/games`, `/inventory`, and more.

## TimeBack Integration Testing

The sandbox supports TimeBack integration testing in three modes: mock (offline), local (Docker), and remote (real TimeBack API).

### TimeBack Modes

| Mode         | Description                                                           |
| :----------- | :-------------------------------------------------------------------- |
| **Mock**     | No external dependencies, works offline. Uses generated mock data.    |
| **Local**    | Connect to a local TimeBack instance (Docker).                        |
| **Remote**   | Real course IDs + API credentials. Tests against actual TimeBack API. |
| **Disabled** | No TimeBack config. TimeBack routes return errors.                    |

### CLI Options

When running the sandbox standalone, configure TimeBack via CLI flags:

```bash
# Local TimeBack (Docker)
bunx @playcademy/sandbox \
  --timeback-local \
  --timeback-oneroster-url http://localhost:8080/ims/oneroster \
  --timeback-caliper-url http://localhost:8080/caliper \
  --timeback-student-id your-student-id

# Remote TimeBack (requires env vars for credentials)
bunx @playcademy/sandbox \
  --timeback-student-id your-student-sourcedId
```

| Option                           | Description                                            |
| :------------------------------- | :----------------------------------------------------- |
| `--timeback-local`               | Enable local TimeBack mode (Docker)                    |
| `--timeback-oneroster-url <url>` | OneRoster API URL                                      |
| `--timeback-caliper-url <url>`   | Caliper API URL                                        |
| `--timeback-course-id <id>`      | Course ID for enrollments                              |
| `--timeback-student-id <id>`     | Student ID to link to demo user                        |
| `--timeback-role <role>`         | User role (student, parent, teacher, administrator)    |
| `--timeback-org-id <id>`         | Organization ID                                        |
| `--timeback-org-name <name>`     | Organization display name                              |
| `--timeback-org-type <type>`     | Organization type (school, district, department, etc.) |

### Environment Variables

For remote TimeBack (or as alternative to CLI flags):

```bash
# TimeBack API credentials (required for remote mode)
TIMEBACK_ONEROSTER_API_URL=https://api.timeback.org/ims/oneroster
TIMEBACK_API_CLIENT_ID=your-client-id
TIMEBACK_API_CLIENT_SECRET=your-client-secret
TIMEBACK_API_AUTH_URL=https://auth.timeback.org

# Link sandbox demo user to a real TimeBack student
SANDBOX_TIMEBACK_STUDENT_ID=your-student-sourcedId
SANDBOX_TIMEBACK_COURSE_ID=your-course-id
```

### With Vite Plugin

When using `@playcademy/vite-plugin`, TimeBack enrollments and roles can be configured directly in `vite.config.ts` for a streamlined experience. See the [Vite plugin documentation](../vite-plugin/README.md#timeback-options-timeback) for details.

The Vite plugin also provides a `t` hotkey to cycle through TimeBack roles during development.

### Runtime Testing

Once configured, your game can use the SDK to submit activities:

```typescript
await client.timeback.endActivity({
    correctQuestions: 8,
    totalQuestions: 10,
})
```

**Note on CLI Commands:**
The sandbox provides TimeBack management endpoints, but CLI commands (`playcademy timeback setup`, `verify`) require Better Auth authentication and won't work against the sandbox. These commands should be run against the platform.

### Available TimeBack Endpoints

The sandbox provides these TimeBack endpoints (matching production platform):

**Management:**

- `GET /api/timeback/integrations/:gameId` - Get integration details
- `POST /api/timeback/setup` - Create TimeBack integration
- `DELETE /api/timeback/integrations/:gameId` - Delete integration
- `GET /api/timeback/verify/:gameId` - Verify OneRoster resources
- `GET /api/timeback/config/:gameId` - Get TimeBack configuration

**Runtime:**

- `POST /api/timeback/end-activity` - Submit activity results

**XP Queries:**

- `GET /api/timeback/xp/today` - Get today's XP
- `PUT /api/timeback/xp/today` - Update today's XP
- `GET /api/timeback/xp/total` - Get total XP
- `GET /api/timeback/xp/history` - Get XP history

These use the same api-core handlers as the production platform, ensuring consistency.

When properly configured, your game can call `client.timeback.endActivity()` during local development and see real events appear in your TimeBack dashboard.

## Debugging

### Health Check

You can verify the sandbox API server is running by sending a request to its `/health` endpoint.

```bash
curl -sSL http://localhost:4321/health | jq
```

This should return a JSON object with the status:

```json
{
    "status": "ok",
    "timestamp": "2023-10-27T00:00:00.000Z"
}
```

### Common Issues

| Issue                          | Solution                                                                                                                                            |
| :----------------------------- | :-------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Sandbox doesn't start**      | When using Vite, check that `autoStart: true` in `vite.config.ts` and `@playcademy/vite-plugin` is installed. Check terminal for errors.            |
| **API calls return HTML**      | This indicates the API server isn't running or is on a different port. Check your sandbox `url` configuration.                                      |
| **Port conflicts**             | The sandbox uses port 4321 by default. If another process is using this port, stop it or use `--port` to specify a different port.                  |
| **Data persists unexpectedly** | By default, the sandbox persists data to disk. Use `--recreate-db` to reset the database, or `--memory` for session-only data that doesn't persist. |

## Production vs. Sandbox

The SDK is designed to work seamlessly in both environments. `PlaycademyClient.init()` automatically detects whether it's running in a production environment or against a local sandbox.

| Feature            | Sandbox                                           | Production               |
| :----------------- | :------------------------------------------------ | :----------------------- |
| **Data**           | Mock, temporary                                   | Real user data           |
| **Authentication** | Mock tokens                                       | Secure authentication    |
| **Persistence**    | Local disk (default) or session-only (`--memory`) | Permanent cloud database |

## Contributing

The sandbox is a crucial development tool for the Playcademy ecosystem. For contribution guidelines, see the [monorepo CONTRIBUTING.md](../../CONTRIBUTING.md).
