# @playcademy/sandbox

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

The Playcademy sandbox provides a complete local simulation of the Playcademy platform, including API services and a real-time server, 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.
- **Integrated Real-time Server**: Built-in WebSocket server for multiplayer features.
- **Fast Development Cycle**: Quick startup with an in-memory database.

## How It Works

The sandbox runs two local servers 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)"];
        B --> D["Real-time Server (localhost:4322)"];
        C --> E["In-Memory Database"];
        D --> E;
    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 both the API and real-time servers are running:

```
VITE v6.3.5

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

PLAYCADEMY v0.1.0

➜  Game:      playground
➜  API:       http://localhost:4321/api
➜  Realtime:  ws://localhost:4322
```

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

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

export default defineConfig({
    plugins: [
        playcademy({
            sandbox: {
                autoStart: true,
                url: 'http://localhost:4321/api',
                realtime: {
                    enabled: true,
                    port: 4322,
                },
            },
        }),
    ],
})
```

### 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 ports and verbose logging
bunx @playcademy/sandbox --port 8080 --realtime --realtime-port 8081 --verbose
```

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

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

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

:::

#### Command-Line Options

| Option                     | Alias | Description                              | Default      |
| :------------------------- | :---- | :--------------------------------------- | :----------- |
| `--port <number>`          | `-p`  | Port for the main API server.            | `4321`       |
| `--realtime`               |       | Enables the real-time WebSocket server.  | `false`      |
| `--realtime-port <number>` |       | Port for the real-time WebSocket server. | API port + 1 |
| `--verbose`                | `-v`  | Enables verbose logging for debugging.   | `false`      |
| `--no-seed`                |       | Disables seeding of demo data.           | `false`      |
| `--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',
    realtimeUrl: 'ws://localhost:4322',
    // 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.                  |
| **Real-time Server** | Provides WebSocket-based real-time channels for multiplayer communication.                    |
| **Data Persistence** | Uses an in-memory database. Data persists until the sandbox is restarted.                     |
| **Mock Data**        | Automatically seeds with a mock user (`developer@example.com`) and other demo data.           |
| **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`
- **Real-time URL**: `ws://localhost:{realtimePort}`

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

## TimeBack Integration Testing

The sandbox supports three TimeBack modes for flexible development and testing.

### Mode 1: Local TimeBack (Recommended for Development)

**Use local TimeBack Docker instance for offline development:**

```bash
# Enable local mode
TIMEBACK_LOCAL=true

# Set local TimeBack URLs (different ports)
TIMEBACK_ONEROSTER_API_URL=http://localhost:9000
TIMEBACK_CALIPER_API_URL=http://localhost:9001

# Optional: pre-seed with course/student IDs
SANDBOX_TIMEBACK_COURSE_ID=local-dev-course
SANDBOX_TIMEBACK_STUDENT_ID=local-dev-student
```

**Benefits:**

- ✅ No external API dependencies
- ✅ Works offline
- ✅ Fast iteration
- ✅ No real credentials needed

**Requirements:**

- Install and run `@superbuilders/timeback-local` Docker container

### Mode 2: Remote TimeBack (Staging/Production)

**Connect to real TimeBack for end-to-end testing:**

```bash
# Required: TimeBack API credentials
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

# Optional: pre-seed with existing course/student
SANDBOX_TIMEBACK_COURSE_ID=your-existing-course-id
SANDBOX_TIMEBACK_STUDENT_ID=your-student-sourcedId
```

**Benefits:**

- ✅ Tests against real TimeBack
- ✅ See actual events in TimeBack dashboard
- ✅ Full production simulation

**Pre-Seeding (Required for Local Testing):**

```bash
SANDBOX_TIMEBACK_COURSE_ID=your-existing-course-id
SANDBOX_TIMEBACK_STUDENT_ID=your-existing-student-sourcedId
```

These are **required** (not optional) for local TimeBack testing because the sandbox uses mock authentication. CLI commands like `playcademy timeback setup` won't work against the sandbox - you must use existing TimeBack resources.

**How to get these IDs:**

1. Run `playcademy timeback setup` against the **platform** once (not sandbox)
2. Get `courseId` from the output or your TimeBack dashboard
3. Get `studentId` (sourcedId) from your TimeBack student roster
4. Set them in `.env` for future local development

What they do:

- `SANDBOX_TIMEBACK_COURSE_ID` - Links your game to an existing TimeBack course
- `SANDBOX_TIMEBACK_STUDENT_ID` - Links the sandbox demo user to a real TimeBack student

### Mode 3: Disabled (Default)

No TimeBack integration. TimeBack routes return errors. This is the default when no TimeBack environment variables are set.

### Runtime Testing Workflow

Once you have TimeBack credentials and IDs configured:

```bash
# 1. Start dev server
bun dev

# 2. Test in your game - TimeBack just works!
client.timeback.endActivity({
    activityData: { activityId: 'test-1' },
    scoreData: { correctQuestions: 8, totalQuestions: 10 },
    timingData: { durationSeconds: 300 }
})

# 3. Check your TimeBack dashboard - events appear in real-time!
```

**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. Once you have a course/student ID from the platform, set them in your `.env` for local testing.

### 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.                                                |
| **WebSocket connection fails** | Verify the real-time server is enabled (`--realtime` flag or Vite config) and check its port in the console output.                                           |
| **Port conflicts**             | Use the `--port` and `--realtime-port` options to choose different ports. The sandbox will automatically try the next available port if its default is taken. |
| **Data doesn't persist**       | This is expected. The sandbox uses an in-memory database that resets on every restart to ensure a clean state for development.                                |

## 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**    | Session only    | Permanent             |

## Contributing

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