# Swagger UI Setup for Rclone Service

**Date**: 2025-10-06
**Status**: Implementation record; deployment URLs below reflect the current VM model

## Overview

The rclone service now provides interactive API documentation via Swagger UI at http://localhost:3001/docs.

## Implementation Details

### Endpoints Added

1. **`/openapi.json`** - Serves the OpenAPI 3.0 specification
   - Generated from JSDoc comments in source files.
   - Updated via `pnpm gen:openapi` script.

2. **`/docs`** - Swagger UI interface
   - Custom HTML page with Swagger UI components.
   - Loads OpenAPI spec from `/openapi.json`.
   - Interactive API testing and documentation.

3. **`/docs/assets/*`** - Static assets
   - Swagger UI CSS, JavaScript, and images.
   - Served from `swagger-ui-dist` package.

### Content Security Policy Configuration

**Issue**: Helmet's default CSP blocked inline scripts required by Swagger UI.

**Solution**: Configured Helmet with relaxed CSP directives:

```javascript
app.use(
  helmet({
    contentSecurityPolicy: {
      directives: {
        defaultSrc: ["'self'"],
        scriptSrc: ["'self'", "'unsafe-inline'"], // Allow inline scripts for Swagger UI
        styleSrc: ["'self'", "'unsafe-inline'"], // Allow inline styles for Swagger UI
        imgSrc: ["'self'", "data:", "https:"],
      },
    },
  })
);
```

**Security Note**: The `'unsafe-inline'` directive is only needed for the Swagger UI page. All other API endpoints maintain strict CSP. In production, consider using nonces or hashes for better security.

## Files Modified

1. **`fly-rclone/server.js`**
   - Added `readFileSync` import (line 12).
   - Configured Helmet with relaxed CSP (lines 121-140).
   - Added `/openapi.json` endpoint (lines 154-164).
   - Added `/docs/assets/*` static middleware (line 168).
   - Added `/docs` HTML endpoint (lines 171-213).

## Usage

### Local Development

1. Start the rclone service:
   ```bash
   cd fly-rclone
   pnpm dev
   ```

2. Access Swagger UI:
   - **Swagger UI**: http://localhost:3001/docs.
   - **OpenAPI Spec**: http://localhost:3001/openapi.json.

### Current Deployment

- Prefer the local Swagger UI and specification during development.
- The authoritative worker runs at `https://rclone.stratofusion.io`; access its
  docs only when an operator workflow requires it.
- Legacy Fly apps are stopped. Do not probe or start them to view Swagger UI.

## Updating API Documentation

The OpenAPI specification is generated from JSDoc comments in the source code.

### Generate Updated Spec

```bash
cd fly-rclone
pnpm gen:openapi
```

This will:
1. Scan all `src/**/*.js` and `server.js` files for JSDoc comments
2. Generate `openapi.json` with the latest API documentation
3. The Swagger UI will automatically load the updated spec

### JSDoc Example

```javascript
/**
 * @swagger
 * /api/copy:
 *   post:
 *     summary: Copy a single file
 *     requestBody:
 *       required: true
 *       content:
 *         application/json:
 *           schema:
 *             type: object
 *             properties:
 *               sourceRemote:
 *                 type: string
 *               sourcePath:
 *                 type: string
 *     responses:
 *       200:
 *         description: Copy operation started
 */
app.post('/api/copy', async (req, res) => {
  // Implementation
});
```

## Features

The Swagger UI provides:

- ✅ **Complete API Documentation** - All endpoints with descriptions.
- ✅ **Request/Response Schemas** - Data models and examples.
- ✅ **Interactive Testing** - Try API calls directly from the browser.
- ✅ **Authentication** - Configure API keys or tokens.
- ✅ **Model Definitions** - Detailed data type information.
- ✅ **Example Requests** - Sample payloads for each endpoint.

## Available Endpoints

The Swagger UI documents all rclone service endpoints:

### Health & Testing
- `GET /health` - Health check.
- `POST /test/progress` - Test progress parsing.

### File Operations
- `POST /api/copy` - Copy single file.
- `POST /api/batch-copy` - Copy multiple files.
- `POST /api/copy-folder` - Copy entire folder.
- `POST /api/move` - Move single file.
- `POST /api/batch-move` - Move multiple files.
- `POST /api/move-folder` - Move entire folder.
- `POST /api/download` - Download files as ZIP.

### Operation Management
- `GET /api/operations/:id` - Get operation status.
- `GET /api/operations` - List all operations.
- `DELETE /api/operations/:id` - Cancel operation.

### Server-Sent Events
- `GET /api/progress/:operationId` - Real-time progress updates.

## Troubleshooting

### CSP Errors in Browser Console

If you see Content Security Policy errors:

```
Refused to execute inline script because it violates the following Content Security Policy directive
```

**Solution**: Ensure Helmet is configured with the relaxed CSP directives as shown above.

### Swagger UI Not Loading

1. **Check server is running**: Visit http://localhost:3001/health
2. **Verify OpenAPI spec**: Visit http://localhost:3001/openapi.json
3. **Check browser console**: Look for JavaScript errors
4. **Clear browser cache**: Hard refresh with Ctrl+Shift+R

### OpenAPI Spec Not Updated

If changes to JSDoc comments don't appear:

1. Regenerate the spec: `pnpm gen:openapi`
2. Restart the server: `rs` in nodemon or restart manually
3. Hard refresh the browser: Ctrl+Shift+R

## Security Considerations

### Development vs Production

**Development** (current setup):
- Allows `'unsafe-inline'` for scripts and styles.
- Suitable for local development and testing.

**Production** (recommended):
- Use nonces or hashes instead of `'unsafe-inline'`.
- Implement stricter CSP for non-documentation endpoints.
- Consider authentication for API documentation access.

### Example Production CSP

```javascript
// Generate a nonce for each request
app.use((req, res, next) => {
  res.locals.nonce = crypto.randomBytes(16).toString('base64');
  next();
});

// Use nonce in Helmet
app.use(
  helmet({
    contentSecurityPolicy: {
      directives: {
        defaultSrc: ["'self'"],
        scriptSrc: ["'self'", (req, res) => `'nonce-${res.locals.nonce}'`],
        styleSrc: ["'self'", (req, res) => `'nonce-${res.locals.nonce}'`],
        imgSrc: ["'self'", "data:", "https:"],
      },
    },
  })
);

// Include nonce in Swagger UI HTML
app.get("/docs", (req, res) => {
  const nonce = res.locals.nonce;
  res.send(`
    <script nonce="${nonce}">
      // Swagger UI initialization
    </script>
  `);
});
```

## Related Documentation

- [Rclone Usage Guide](RCLONE_USAGE.md) - Command patterns and defaults.
- [Deployment Guide](DEPLOYMENT.md) - Fly.io deployment instructions.
- [Rclone Transfer Service](RCLONE_SERVICE.md) - Service API documentation.
- [Main README](../../README.md) - Project overview and setup.

---

**Setup Complete**: 2025-10-06
**Status**: ✅ Working
**Access**: http://localhost:3001/docs

