mirror of
https://github.com/Chocobozzz/PeerTube.git
synced 2026-09-03 20:53:09 -05:00
Use AGENTS.md
Allow contributors to use the tool they want, reducing coupling with copilot See PeerTube dev position on AI: https://joinpeertube.org/faq#what-is-the-ai-policy-for-peertube-development
This commit is contained in:
@@ -1,222 +0,0 @@
|
|||||||
# PeerTube Copilot Instructions
|
|
||||||
|
|
||||||
## Repository Overview
|
|
||||||
|
|
||||||
PeerTube is an open-source, ActivityPub-federated video streaming platform using P2P technology directly in web browsers. It's developed by Framasoft and provides a decentralized alternative to centralized video platforms like YouTube.
|
|
||||||
|
|
||||||
**Repository Stats:**
|
|
||||||
- **Size**: Large monorepo (~350MB, ~15k files)
|
|
||||||
- **Type**: Full-stack web application
|
|
||||||
- **Languages**: TypeScript (backend), Angular (frontend), Shell scripts
|
|
||||||
- **Target Runtime**: Node.js >=20.x, PostgreSQL >=10.x, Redis >=6.x
|
|
||||||
- **Package Manager**: Yarn 1.x (NOT >=2.x)
|
|
||||||
- **Architecture**: Express.js API server + Angular SPA client + P2P video delivery
|
|
||||||
|
|
||||||
## Critical: Client Directory Exclusion
|
|
||||||
|
|
||||||
**🚫 ALWAYS IGNORE `client/` directory** - it contains a separate Angular frontend project with its own build system, dependencies, and development workflow. Focus only on the server-side backend code.
|
|
||||||
|
|
||||||
## Build & Development Commands
|
|
||||||
|
|
||||||
### Prerequisites (Required)
|
|
||||||
1. **Dependencies**: Node.js >=20.x, Yarn 1.x, PostgreSQL >=10.x, Redis >=6.x, FFmpeg >=4.3, Python >=3.8
|
|
||||||
2. **PostgreSQL Setup**:
|
|
||||||
```bash
|
|
||||||
sudo -u postgres createuser -P peertube
|
|
||||||
sudo -u postgres createdb -O peertube peertube_dev
|
|
||||||
sudo -u postgres psql -c "CREATE EXTENSION pg_trgm;" peertube_dev
|
|
||||||
sudo -u postgres psql -c "CREATE EXTENSION unaccent;" peertube_dev
|
|
||||||
```
|
|
||||||
3. **Services**: Start PostgreSQL and Redis before development
|
|
||||||
|
|
||||||
### Installation & Build (Execute in Order)
|
|
||||||
```bash
|
|
||||||
# 1. ALWAYS install dependencies first (takes ~2-3 minutes)
|
|
||||||
yarn install --frozen-lockfile
|
|
||||||
|
|
||||||
# 2. Build server (required for most operations, takes ~3-5 minutes)
|
|
||||||
npm run build:server
|
|
||||||
|
|
||||||
# 3. Optional: Build full application (takes ~10-15 minutes)
|
|
||||||
npm run build
|
|
||||||
```
|
|
||||||
|
|
||||||
**⚠️ Critical Notes:**
|
|
||||||
- Always run `yarn install --frozen-lockfile` before any build operation
|
|
||||||
- Server build is prerequisite for testing and development
|
|
||||||
- Never use `npm install` - always use `yarn`
|
|
||||||
- Build failures often indicate missing PostgreSQL extensions or wrong Node.js version
|
|
||||||
|
|
||||||
### Development Commands
|
|
||||||
```bash
|
|
||||||
# Server-only development (recommended for backend work)
|
|
||||||
npm run dev:server # Starts server on localhost:9000 with hot reload
|
|
||||||
|
|
||||||
# Full stack development (NOT recommended if only working on server)
|
|
||||||
npm run dev # Starts both server (9000) and client (3000)
|
|
||||||
|
|
||||||
# Development credentials:
|
|
||||||
# Username: root
|
|
||||||
# Password: test
|
|
||||||
```
|
|
||||||
|
|
||||||
### Testing Commands (Execute in Order)
|
|
||||||
```bash
|
|
||||||
# 1. Prepare test environment (required before first test run)
|
|
||||||
sudo -u postgres createuser $(whoami) --createdb --superuser
|
|
||||||
npm run clean:server:test
|
|
||||||
|
|
||||||
# 2. Build (required before testing)
|
|
||||||
npm run build
|
|
||||||
|
|
||||||
# 3. Run specific test suites (recommended over full test)
|
|
||||||
npm run ci -- api-1 # API tests part 1
|
|
||||||
npm run ci -- api-2 # API tests part 2
|
|
||||||
npm run ci -- lint # Linting only
|
|
||||||
npm run ci -- client # Client tests
|
|
||||||
|
|
||||||
# 4. Run single test file
|
|
||||||
npm run mocha -- --exit --bail packages/tests/src/api/videos/single-server.ts
|
|
||||||
|
|
||||||
# 5. Full test suite (takes ~45-60 minutes, avoid unless necessary)
|
|
||||||
npm run test
|
|
||||||
```
|
|
||||||
|
|
||||||
**⚠️ Test Environment Notes:**
|
|
||||||
- Tests require PostgreSQL user with createdb/superuser privileges
|
|
||||||
- Some tests need Docker containers for S3/LDAP simulation
|
|
||||||
- Test failures often indicate missing system dependencies or DB permissions
|
|
||||||
- Set `DISABLE_HTTP_IMPORT_TESTS=true` to skip flaky import tests
|
|
||||||
|
|
||||||
### Validation Commands
|
|
||||||
```bash
|
|
||||||
# Lint code (runs ESLint + OpenAPI validation)
|
|
||||||
npm run lint
|
|
||||||
|
|
||||||
# Validate OpenAPI spec
|
|
||||||
npm run swagger-cli -- validate support/doc/api/openapi.yaml
|
|
||||||
|
|
||||||
# Build server
|
|
||||||
npm run build:server
|
|
||||||
```
|
|
||||||
|
|
||||||
## Project Architecture & Layout
|
|
||||||
|
|
||||||
### Server-Side Structure (Primary Focus)
|
|
||||||
```
|
|
||||||
server/core/
|
|
||||||
├── controllers/api/ # Express route handlers (add new endpoints here)
|
|
||||||
│ ├── index.ts # Main API router registration
|
|
||||||
│ ├── videos/ # Video-related endpoints
|
|
||||||
│ └── users/ # User-related endpoints
|
|
||||||
├── models/ # Sequelize database models
|
|
||||||
│ ├── video/ # Video, channel, playlist models
|
|
||||||
│ └── user/ # User, account models
|
|
||||||
├── lib/ # Business logic services
|
|
||||||
│ ├── job-queue/ # Background job processing
|
|
||||||
│ └── emailer.ts # Email service
|
|
||||||
├── middlewares/ # Express middleware
|
|
||||||
│ ├── validators/ # Input validation (always required)
|
|
||||||
│ └── auth.ts # Authentication middleware
|
|
||||||
├── helpers/ # Utility functions
|
|
||||||
└── initializers/ # App startup and constants
|
|
||||||
```
|
|
||||||
|
|
||||||
### Key Configuration Files
|
|
||||||
- `package.json` - Main dependencies and scripts
|
|
||||||
- `server/package.json` - Server-specific config
|
|
||||||
- `eslint.config.mjs` - Linting rules
|
|
||||||
- `tsconfig.base.json` - TypeScript base config
|
|
||||||
- `config/default.yaml` - Default app configuration
|
|
||||||
- `.mocharc.cjs` - Test runner configuration
|
|
||||||
|
|
||||||
### Shared Packages (`packages/`)
|
|
||||||
```
|
|
||||||
packages/
|
|
||||||
├── models/ # Shared TypeScript interfaces (modify for API changes)
|
|
||||||
├── core-utils/ # Common utilities
|
|
||||||
├── ffmpeg/ # Video processing
|
|
||||||
├── server-commands/ # Test helpers
|
|
||||||
└── tests/ # Test files
|
|
||||||
```
|
|
||||||
|
|
||||||
### Scripts Directory (`scripts/`)
|
|
||||||
- `scripts/build/` - Build automation
|
|
||||||
- `scripts/dev/` - Development helpers
|
|
||||||
- `scripts/ci.sh` - Continuous integration runner
|
|
||||||
- `scripts/test.sh` - Test runner
|
|
||||||
|
|
||||||
## Continuous Integration Pipeline
|
|
||||||
|
|
||||||
**GitHub Actions** (`.github/workflows/test.yml`):
|
|
||||||
1. **Matrix Strategy**: Tests run in parallel across different suites
|
|
||||||
2. **Required Services**: PostgreSQL, Redis, LDAP, S3, Keycloak containers
|
|
||||||
3. **Test Suites**: `types-package`, `client`, `api-1` through `api-5`, `transcription`, `cli-plugin`, `lint`, `external-plugins`
|
|
||||||
4. **Environment**: Ubuntu 22.04, Node.js 20.x
|
|
||||||
5. **Typical Runtime**: 15-30 minutes per suite
|
|
||||||
|
|
||||||
**Pre-commit Checks**: ESLint, TypeScript compilation, OpenAPI validation
|
|
||||||
|
|
||||||
## Making Code Changes
|
|
||||||
|
|
||||||
### Adding New API Endpoint
|
|
||||||
1. Create controller in `server/core/controllers/api/`
|
|
||||||
2. Add validation middleware in `server/core/middlewares/validators/`
|
|
||||||
3. Register route in `server/core/controllers/api/index.ts`
|
|
||||||
4. Update shared types in `packages/models/`
|
|
||||||
5. Add OpenAPI documentation tags
|
|
||||||
6. Write tests in `packages/tests/src/api/`
|
|
||||||
|
|
||||||
### Common Patterns to Follow
|
|
||||||
```typescript
|
|
||||||
// Controller pattern
|
|
||||||
import express from 'express'
|
|
||||||
import { apiRateLimiter, asyncMiddleware } from '../../middlewares/index.js'
|
|
||||||
|
|
||||||
const router = express.Router()
|
|
||||||
router.use(apiRateLimiter) // ALWAYS include rate limiting
|
|
||||||
|
|
||||||
router.get('/:id',
|
|
||||||
validationMiddleware, // ALWAYS validate inputs
|
|
||||||
asyncMiddleware(handler) // ALWAYS wrap async handlers
|
|
||||||
)
|
|
||||||
```
|
|
||||||
|
|
||||||
### Database Changes
|
|
||||||
1. Create/modify Sequelize model in `server/core/models/`
|
|
||||||
2. Generate migration in `server/core/initializers/migrations/`
|
|
||||||
3. Update shared types in `packages/models/`
|
|
||||||
4. Run `npm run build:server` to compile
|
|
||||||
|
|
||||||
## Validation Steps Before PR
|
|
||||||
|
|
||||||
1. **Build**: `npm run build` (must succeed)
|
|
||||||
2. **Lint**: `npm run lint` (must pass without errors)
|
|
||||||
5. **OpenAPI**: Validate if API changes made
|
|
||||||
|
|
||||||
## Common Error Solutions
|
|
||||||
|
|
||||||
**Build Errors:**
|
|
||||||
- "Cannot find module": Run `yarn install --frozen-lockfile`
|
|
||||||
- "PostgreSQL connection": Check PostgreSQL is running and extensions installed
|
|
||||||
- TypeScript errors: Check Node.js version (must be >=20.x)
|
|
||||||
|
|
||||||
**Test Errors:**
|
|
||||||
- Permission denied: Ensure PostgreSQL user has createdb/superuser rights
|
|
||||||
- Port conflicts: Stop other PeerTube instances
|
|
||||||
- Import test failures: Set `DISABLE_HTTP_IMPORT_TESTS=true`
|
|
||||||
|
|
||||||
**Development Issues:**
|
|
||||||
- "Client dist not found": Run `npm run build:client` (only if working on client features)
|
|
||||||
- Redis connection: Ensure Redis server is running
|
|
||||||
- Hot reload not working: Kill all Node processes and restart
|
|
||||||
|
|
||||||
## Trust These Instructions
|
|
||||||
|
|
||||||
These instructions have been validated against the current codebase. Only search for additional information if:
|
|
||||||
- Commands fail with updated error messages
|
|
||||||
- New dependencies are added to package.json
|
|
||||||
- Build system changes are detected
|
|
||||||
- You need specific implementation details not covered here
|
|
||||||
|
|
||||||
Focus on server-side TypeScript development in `server/core/` and ignore the `client/` directory unless explicitly working on frontend integration.
|
|
||||||
@@ -0,0 +1,406 @@
|
|||||||
|
# Project Overview
|
||||||
|
|
||||||
|
PeerTube is an open-source, ActivityPub-federated video streaming platform
|
||||||
|
that uses P2P technology directly in web browsers. Developed by Framasoft
|
||||||
|
under the AGPL-3.0 license, it provides a decentralized alternative to
|
||||||
|
centralized video platforms. The server is a Node.js/Express API with a
|
||||||
|
Sequelize ORM (PostgreSQL), background job processing (BullMQ/Redis),
|
||||||
|
ActivityPub federation, and an Angular SPA client. Video transcoding is
|
||||||
|
handled via FFmpeg, with optional distributed runners.
|
||||||
|
|
||||||
|
## Repository Structure
|
||||||
|
|
||||||
|
- **apps/** — Standalone CLI applications (`peertube-cli`, `peertube-runner`)
|
||||||
|
- **client/** — Angular frontend SPA (separate build system; ignore for
|
||||||
|
backend work)
|
||||||
|
- **config/** — YAML configuration files for dev, test, and production
|
||||||
|
- **packages/** — Shared workspace packages (monorepo):
|
||||||
|
- `core-utils/` — Shared pure-JS utilities
|
||||||
|
- `ffmpeg/` — FFmpeg wrapper library
|
||||||
|
- `models/` — Shared TypeScript interfaces and API types
|
||||||
|
- `node-utils/` — Node.js-specific helpers
|
||||||
|
- `server-commands/` — HTTP client helpers used by tests
|
||||||
|
- `tests/` — Full test suite (API, CLI, plugins, feeds, etc.)
|
||||||
|
- `transcription/` — Speech-to-text engine integration
|
||||||
|
- `transcription-devtools/` — Transcription benchmarking tools
|
||||||
|
- `types-generator/` — Generates the public `@peertube/peertube-types`
|
||||||
|
package
|
||||||
|
- `typescript-utils/` — Generic TypeScript helpers
|
||||||
|
- **scripts/** — Build, CI, dev, release, and i18n shell scripts
|
||||||
|
- **server/** — Backend entry point and core application code
|
||||||
|
- `server.ts` — Process entry point
|
||||||
|
- `core/controllers/` — Express route handlers (API, ActivityPub,
|
||||||
|
feeds, tracker)
|
||||||
|
- `core/models/` — Sequelize database models (14 categories)
|
||||||
|
- `core/lib/` — Business logic (transcoding, live, job queue,
|
||||||
|
ActivityPub, plugins, runners, notifications, etc.)
|
||||||
|
- `core/middlewares/` — Auth, rate-limiting, validation, caching, CSP
|
||||||
|
- `core/helpers/` — Utility functions and custom validators
|
||||||
|
- `core/initializers/` — App bootstrap, constants, DB migrations,
|
||||||
|
config loading
|
||||||
|
- `core/types/` — Internal TypeScript type augmentations
|
||||||
|
- **support/** — Documentation, Docker, Nginx configs, OpenAPI spec
|
||||||
|
|
||||||
|
## Build & Development Commands
|
||||||
|
|
||||||
|
### Prerequisites
|
||||||
|
|
||||||
|
- Node.js >= 20.x
|
||||||
|
- pnpm >= 10.9 (do **not** use npm or yarn for install)
|
||||||
|
- PostgreSQL >= 10 with `pg_trgm` and `unaccent` extensions
|
||||||
|
- Redis >= 6.x
|
||||||
|
- FFmpeg >= 4.3
|
||||||
|
- Python >= 3.8 (for some test tooling)
|
||||||
|
|
||||||
|
### Install dependencies
|
||||||
|
|
||||||
|
```bash
|
||||||
|
pnpm install --frozen-lockfile
|
||||||
|
```
|
||||||
|
|
||||||
|
### Build
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Build server only (backend work)
|
||||||
|
npm run build:server
|
||||||
|
|
||||||
|
# Build full application (server + client)
|
||||||
|
npm run build
|
||||||
|
|
||||||
|
# Build tests
|
||||||
|
npm run build:tests
|
||||||
|
|
||||||
|
# Build individual apps
|
||||||
|
npm run build:peertube-cli
|
||||||
|
npm run build:peertube-runner
|
||||||
|
```
|
||||||
|
|
||||||
|
### Development
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Server-only with hot reload (recommended for backend work)
|
||||||
|
npm run dev:server # http://localhost:9000
|
||||||
|
|
||||||
|
# Full stack (server + Angular client)
|
||||||
|
npm run dev # server :9000, client :3000
|
||||||
|
|
||||||
|
# Dev credentials: root / test
|
||||||
|
```
|
||||||
|
|
||||||
|
### Lint & type-check
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Full lint (ESLint + OpenAPI validation)
|
||||||
|
npm run lint
|
||||||
|
|
||||||
|
# ESLint only
|
||||||
|
npm run eslint
|
||||||
|
|
||||||
|
# Validate OpenAPI spec
|
||||||
|
npm run swagger-cli -- validate support/doc/api/openapi.yaml
|
||||||
|
|
||||||
|
# TypeScript compilation check
|
||||||
|
npm run tsc -b server/tsconfig.json
|
||||||
|
```
|
||||||
|
|
||||||
|
### Run in production
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npm run start # server + client
|
||||||
|
npm run start:server # server only (--no-client)
|
||||||
|
```
|
||||||
|
|
||||||
|
## Code Style & Conventions
|
||||||
|
|
||||||
|
### Formatting (enforced by ESLint)
|
||||||
|
|
||||||
|
| Rule | Value |
|
||||||
|
|---------------------|---------------------------------------|
|
||||||
|
| Semicolons | **never** (`@stylistic/semi`) |
|
||||||
|
| Max line length | 140 characters |
|
||||||
|
| Quotes | Single quotes (TypeScript default) |
|
||||||
|
| Array brackets | Spaces inside `[ 'a', 'b' ]` |
|
||||||
|
| Trailing newline | Required (`eol-last`) |
|
||||||
|
| Indentation | 2 spaces (TypeScript convention) |
|
||||||
|
|
||||||
|
### Naming patterns
|
||||||
|
|
||||||
|
- Database models: `VideoModel`, `UserModel` — PascalCase + `Model` suffix
|
||||||
|
- Internal type aliases: `MVideo`, `MVideoWithChannel` — `M` prefix for
|
||||||
|
Sequelize model types with specific association requirements
|
||||||
|
- Controllers: one file per resource, registered in parent `index.ts`
|
||||||
|
- Validators: mirror controller structure under
|
||||||
|
`server/core/middlewares/validators/`
|
||||||
|
|
||||||
|
### Controller pattern
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
import express from 'express'
|
||||||
|
import { apiRateLimiter, asyncMiddleware } from '../../middlewares/index.js'
|
||||||
|
|
||||||
|
const router = express.Router()
|
||||||
|
router.use(apiRateLimiter) // always include rate limiting
|
||||||
|
|
||||||
|
router.get('/:id',
|
||||||
|
validationMiddleware, // always validate inputs
|
||||||
|
asyncMiddleware(handler) // always wrap async handlers
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
### Commit messages
|
||||||
|
|
||||||
|
No formal commit-message template.
|
||||||
|
|
||||||
|
### ESLint config
|
||||||
|
|
||||||
|
Defined in `eslint.config.mjs`. Extends `eslint-config-love` with
|
||||||
|
`@stylistic/eslint-plugin`. Applies to `server/**/*.ts`,
|
||||||
|
`scripts/**/*.ts`, `packages/**/*.ts`, `apps/**/*.ts`. The `client/`
|
||||||
|
directory has its own lint config.
|
||||||
|
|
||||||
|
## Architecture Notes
|
||||||
|
|
||||||
|
```
|
||||||
|
┌──────────────────────────────────────────┐
|
||||||
|
│ Reverse Proxy (Nginx) │
|
||||||
|
└──────────────┬───────────────────────────┘
|
||||||
|
│
|
||||||
|
┌──────────────────▼──────────────────────┐
|
||||||
|
│ Express.js API Server │
|
||||||
|
│ (server/server.ts → core/controllers/) │
|
||||||
|
│ │
|
||||||
|
│ ┌─────────┐ ┌──────────┐ ┌──────────┐ │
|
||||||
|
│ │ REST │ │Activity- │ │ Feeds/ │ │
|
||||||
|
│ │ API │ │ Pub │ │ oEmbed │ │
|
||||||
|
│ │ /api/* │ │ /inbox │ │ /feeds │ │
|
||||||
|
│ └────┬────┘ └────┬─────┘ └────┬─────┘ │
|
||||||
|
│ │ │ │ │
|
||||||
|
│ ┌────▼───────────▼─────────────▼────┐ │
|
||||||
|
│ │ Middleware Pipeline │ │
|
||||||
|
│ │ (auth, validators, rate-limit) │ │
|
||||||
|
│ └────────────────┬───────────────────┘ │
|
||||||
|
│ │ │
|
||||||
|
│ ┌────────────────▼───────────────────┐ │
|
||||||
|
│ │ Business Logic (lib/) │ │
|
||||||
|
│ │ videos, live, transcoding, │ │
|
||||||
|
│ │ federation, notifications, │ │
|
||||||
|
│ │ plugins, runners │ │
|
||||||
|
│ └──┬──────────┬──────────────┬───┘ │
|
||||||
|
└─────┼──────────┼──────────────┼───────┘
|
||||||
|
│ │ │
|
||||||
|
┌────────▼──┐ ┌─────▼─────┐ ┌──────▼──────┐
|
||||||
|
│PostgreSQL │ │ Redis │ │ FFmpeg / │
|
||||||
|
│(Sequelize)│ │ (BullMQ │ │ Runners │
|
||||||
|
│ │ │ + cache) │ │ │
|
||||||
|
└───────────┘ └───────────┘ └─────────────┘
|
||||||
|
```
|
||||||
|
|
||||||
|
**Startup sequence** (`server/server.ts`):
|
||||||
|
|
||||||
|
1. Register OpenTelemetry tracing
|
||||||
|
2. Pre-init checks (config, FFmpeg, Node.js version)
|
||||||
|
3. Connect to PostgreSQL, run migrations
|
||||||
|
4. Initialize Sequelize models and load i18n
|
||||||
|
5. Configure Express middleware stack (proxy trust, CSP, CORS,
|
||||||
|
rate-limiting, OAuth2 auth, express-validator)
|
||||||
|
6. Mount route controllers and start listening
|
||||||
|
|
||||||
|
**Key data flows**:
|
||||||
|
|
||||||
|
- **Video upload**: REST API → validator middleware → `lib/video.ts` →
|
||||||
|
job queue → FFmpeg transcoding → HLS/web-video files → object
|
||||||
|
storage or local filesystem
|
||||||
|
- **Federation**: Incoming ActivityPub requests → signature
|
||||||
|
verification → `lib/activitypub/` processors → local DB updates +
|
||||||
|
outgoing fan-out
|
||||||
|
- **Live streaming**: RTMP ingest → FFmpeg segmenter → HLS manifest →
|
||||||
|
P2P delivery via WebSocket tracker
|
||||||
|
|
||||||
|
## Testing Strategy
|
||||||
|
|
||||||
|
### Test framework
|
||||||
|
|
||||||
|
- **Mocha** for all server/API tests
|
||||||
|
- **GNU Parallel** for running test files concurrently in CI
|
||||||
|
- Tests live in `packages/tests/src/` (TypeScript source) and are
|
||||||
|
compiled to `packages/tests/dist/`
|
||||||
|
|
||||||
|
### Preparation
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Create PostgreSQL superuser for test DB management
|
||||||
|
sudo -u postgres createuser $(whoami) --createdb --superuser
|
||||||
|
|
||||||
|
# Clean test databases
|
||||||
|
npm run clean:server:test
|
||||||
|
|
||||||
|
# Build server + tests
|
||||||
|
npm run build:server
|
||||||
|
npm run build:tests
|
||||||
|
```
|
||||||
|
|
||||||
|
### Running tests
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Full suite (slow, ~45-60 min)
|
||||||
|
npm run test
|
||||||
|
|
||||||
|
# Run a specific CI suite
|
||||||
|
npm run ci -- api-1 # check-params, notifications, search
|
||||||
|
npm run ci -- api-2 # live, server plugins, users
|
||||||
|
npm run ci -- api-3 # videos, stats
|
||||||
|
npm run ci -- api-4 # moderation, redundancy, object-storage,
|
||||||
|
# activitypub
|
||||||
|
npm run ci -- api-5 # transcoding, runners
|
||||||
|
npm run ci -- client # feeds, client, misc-endpoints, plugins
|
||||||
|
npm run ci -- cli-plugin # CLI and plugin tests
|
||||||
|
npm run ci -- lint # ESLint + OpenAPI validation + client lint
|
||||||
|
npm run ci -- transcription
|
||||||
|
npm run ci -- external-plugins
|
||||||
|
|
||||||
|
# Run a single test file
|
||||||
|
npm run mocha -- --timeout 30000 --exit --bail \
|
||||||
|
packages/tests/src/api/videos/single-server.ts
|
||||||
|
```
|
||||||
|
|
||||||
|
### External test dependencies (Docker)
|
||||||
|
|
||||||
|
Some tests require these containers:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker run -p 9444:9000 chocobozzz/s3-ninja
|
||||||
|
docker run -p 10389:10389 chocobozzz/docker-test-openldap
|
||||||
|
docker run -p 8082:8080 \
|
||||||
|
-e KC_BOOTSTRAP_ADMIN_USERNAME=admin \
|
||||||
|
-e KC_BOOTSTRAP_ADMIN_PASSWORD=admin \
|
||||||
|
chocobozzz/peertube-tests-keycloak
|
||||||
|
```
|
||||||
|
|
||||||
|
### CI pipeline
|
||||||
|
|
||||||
|
GitHub Actions (`.github/workflows/test.yml`), Ubuntu 22.04, Node.js
|
||||||
|
20.x. Matrix strategy runs suites in parallel: `types-package`,
|
||||||
|
`client`, `api-1`–`api-5`, `cli-plugin`, `lint`, `transcription`,
|
||||||
|
`external-plugins`.
|
||||||
|
|
||||||
|
Services provisioned per job: PostgreSQL 10, Redis, LDAP, S3 Ninja,
|
||||||
|
Keycloak.
|
||||||
|
|
||||||
|
### Environment variables for tests
|
||||||
|
|
||||||
|
| Variable | Purpose |
|
||||||
|
|--------------------------------------------|-----------------------------|
|
||||||
|
| `DISABLE_HTTP_IMPORT_TESTS=true` | Skip flaky HTTP import tests|
|
||||||
|
| `DISABLE_HTTP_YOUTUBE_IMPORT_TESTS=true` | Skip YouTube import tests |
|
||||||
|
| `ENABLE_OBJECT_STORAGE_TESTS=true` | Enable S3 tests |
|
||||||
|
|
||||||
|
## Security & Compliance
|
||||||
|
|
||||||
|
- **License**: AGPL-3.0 — all network-facing modifications must be
|
||||||
|
published under the same license.
|
||||||
|
- **Secrets**: The `secrets.peertube` key in `config/*.yaml` must be
|
||||||
|
generated via `openssl rand -hex 32`. Never commit secrets; use
|
||||||
|
`config/local-*.json` overrides (gitignored) or environment variables.
|
||||||
|
- **OAuth2**: Access tokens expire in 1 day; refresh tokens in 2 weeks
|
||||||
|
(configurable in `config/default.yaml`).
|
||||||
|
- **Rate limiting**: All API endpoints are rate-limited by default
|
||||||
|
(`apiRateLimiter` middleware). Specific limits per category (login,
|
||||||
|
signup, ActivityPub, etc.) are configured in `config/default.yaml`.
|
||||||
|
- **CSP**: Content-Security-Policy headers are configurable and applied
|
||||||
|
via `server/core/middlewares/csp.ts`.
|
||||||
|
- **Input validation**: Every controller uses express-validator
|
||||||
|
middleware defined in `server/core/middlewares/validators/`.
|
||||||
|
- **Vulnerability reporting**: `peertube-security@framasoft.org` —
|
||||||
|
see `SECURITY.md`.
|
||||||
|
- **Dependency scanning**: No automated scanner configuration found in
|
||||||
|
the repo.
|
||||||
|
|
||||||
|
## Agent Guardrails
|
||||||
|
|
||||||
|
### Files and directories agents must NOT modify
|
||||||
|
|
||||||
|
- `config/local-*.json` — User-local config overrides (gitignored)
|
||||||
|
- `config/production.yaml.example` — Template; changes need release
|
||||||
|
coordination
|
||||||
|
- `server/core/initializers/migrations/` — Existing migration files are
|
||||||
|
immutable once released; only append new ones
|
||||||
|
- `pnpm-lock.yaml` — Regenerated by `pnpm install`; never edit manually
|
||||||
|
- `support/doc/api/openapi.yaml` — Must stay in sync with controllers;
|
||||||
|
validate with `npm run swagger-cli -- validate`
|
||||||
|
|
||||||
|
### Required checks before pushing
|
||||||
|
|
||||||
|
1. `npm run build:server` must succeed
|
||||||
|
2. `npm run lint` must pass
|
||||||
|
3. If API surface changed: `npm run swagger-cli -- validate
|
||||||
|
support/doc/api/openapi.yaml`
|
||||||
|
4. If database schema changed: create a new migration file **and**
|
||||||
|
increment `LAST_MIGRATION_VERSION` in
|
||||||
|
`server/core/initializers/constants.ts`
|
||||||
|
|
||||||
|
### Boundaries
|
||||||
|
|
||||||
|
- Do not run `pnpm install` without `--frozen-lockfile`
|
||||||
|
- Do not use `npm install` or `yarn` — this project uses **pnpm**
|
||||||
|
- Do not add dependencies without explicit approval
|
||||||
|
- Do not modify test Docker images or CI service definitions without
|
||||||
|
review
|
||||||
|
- Maximum concurrency for background jobs is configured in constants;
|
||||||
|
do not change without benchmarking
|
||||||
|
|
||||||
|
## Extensibility Hooks
|
||||||
|
|
||||||
|
### Plugin system
|
||||||
|
|
||||||
|
PeerTube supports server and client plugins via a hook-based
|
||||||
|
architecture. Plugins register `filter`, `action`, and `static`
|
||||||
|
hooks—see `support/doc/plugins/guide.md`.
|
||||||
|
|
||||||
|
- Plugin names follow `peertube-plugin-*` (themes: `peertube-theme-*`)
|
||||||
|
- Server hooks are registered in `server/core/lib/plugins/`
|
||||||
|
- Plugin management API: `/api/v1/plugins`
|
||||||
|
- Install/uninstall scripts: `npm run plugin:install`,
|
||||||
|
`npm run plugin:uninstall`
|
||||||
|
|
||||||
|
### Configuration
|
||||||
|
|
||||||
|
All runtime configuration is in YAML under `config/`. Local overrides
|
||||||
|
use `config/local-*.json` files (gitignored). Key env vars:
|
||||||
|
|
||||||
|
| Variable | Purpose |
|
||||||
|
|-----------------------|--------------------------------------|
|
||||||
|
| `NODE_ENV` | `production`, `development`, `test` |
|
||||||
|
| `NODE_CONFIG_DIR` | Override config directory |
|
||||||
|
| `LOGGER_LEVEL` | `debug`, `info`, `warn`, `error` |
|
||||||
|
| `PT_INITIAL_ROOT_PASSWORD` | Set root password on first run |
|
||||||
|
|
||||||
|
### Runners (distributed transcoding)
|
||||||
|
|
||||||
|
External `peertube-runner` processes poll the API for transcoding jobs.
|
||||||
|
Configured in `server/core/lib/runners/` and managed through the
|
||||||
|
`/api/v1/runners` endpoints.
|
||||||
|
|
||||||
|
### OpenTelemetry
|
||||||
|
|
||||||
|
Tracing and metrics are instrumented via `@opentelemetry/*` packages.
|
||||||
|
Export to Jaeger (tracing) or Prometheus (metrics) is configurable in
|
||||||
|
`config/default.yaml` under the `open_telemetry` key.
|
||||||
|
|
||||||
|
## Further Reading
|
||||||
|
|
||||||
|
- [support/doc/development/server.md](support/doc/development/server.md)
|
||||||
|
— Server code conventions and new-feature walkthrough
|
||||||
|
- [support/doc/development/tests.md](support/doc/development/tests.md)
|
||||||
|
— Test setup and execution guide
|
||||||
|
- [support/doc/plugins/guide.md](support/doc/plugins/guide.md)
|
||||||
|
— Plugin & theme development guide
|
||||||
|
- [support/doc/api/openapi.yaml](support/doc/api/openapi.yaml)
|
||||||
|
— OpenAPI 3.0 specification
|
||||||
|
- [support/doc/production.md](support/doc/production.md)
|
||||||
|
— Production deployment guide
|
||||||
|
- [support/doc/docker.md](support/doc/docker.md)
|
||||||
|
— Docker deployment guide
|
||||||
|
- [support/doc/development/lib.md](support/doc/development/lib.md)
|
||||||
|
— Library / business-logic documentation
|
||||||
|
- [SECURITY.md](SECURITY.md) — Vulnerability disclosure policy
|
||||||
|
- [FAQ.md](FAQ.md) — Frequently asked questions
|
||||||
@@ -0,0 +1,240 @@
|
|||||||
|
# Client — Angular Frontend SPA
|
||||||
|
|
||||||
|
PeerTube's web client is an Angular single-page application served
|
||||||
|
under `/client/`. It communicates with the backend exclusively through
|
||||||
|
the REST API (`/api/v1/`). A separate Vite-built embed player lives
|
||||||
|
in `src/standalone/` for third-party iframe embedding.
|
||||||
|
|
||||||
|
## Directory Structure
|
||||||
|
|
||||||
|
- **src/app/** — Main Angular application
|
||||||
|
- `+about/`, `+admin/`, `+home/`, `+login/`, `+signup/`, etc. —
|
||||||
|
Lazy-loaded route modules (prefixed with `+`)
|
||||||
|
- `core/` — Singleton services: auth, routing, plugins, theme,
|
||||||
|
server config, notifications, screen-size helpers
|
||||||
|
- `shared/` — Reusable components & directives organized by domain
|
||||||
|
(`shared-video/`, `shared-forms/`, `shared-moderation/`, etc.)
|
||||||
|
- `header/`, `menu/`, `modal/` — App shell layout components
|
||||||
|
- `helpers/` — Client-side utility functions
|
||||||
|
- `hotkeys/` — Keyboard shortcut definitions
|
||||||
|
- `app.routes.ts` — Top-level route definitions (lazy-loaded)
|
||||||
|
- `app.component.ts` — Root component
|
||||||
|
- **src/root-helpers/** — Framework-agnostic helpers (logger, storage,
|
||||||
|
theme manager, translations, plugin manager) shared between the
|
||||||
|
main app and standalone builds
|
||||||
|
- **src/standalone/** — Independently built artifacts:
|
||||||
|
- `player/` — PeerTube video player (Vite build, HLS.js + P2P)
|
||||||
|
- `embed-player-api/` — Public npm package for programmatic
|
||||||
|
embed control (`@peertube/embed-api`)
|
||||||
|
- `videos/` — Embed page (`embed.html`) and test harness
|
||||||
|
- **src/sass/** — Global SCSS: Bootstrap overrides, PrimeNG theme,
|
||||||
|
utility classes, z-index scale, fonts
|
||||||
|
- **src/locale/** — Angular XLIFF translation files
|
||||||
|
- **src/assets/** — Static images and assets
|
||||||
|
- **src/environments/** — Angular environment configs
|
||||||
|
- **e2e/** — End-to-end tests (WebdriverIO + Mocha)
|
||||||
|
- **proxy.config.json** — Dev-server proxy to backend (:9000)
|
||||||
|
|
||||||
|
## Build & Development Commands
|
||||||
|
|
||||||
|
All commands run from the **repository root** unless noted.
|
||||||
|
|
||||||
|
### Development
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Full stack: server (:9000) + Angular dev server (:3000)
|
||||||
|
npm run dev
|
||||||
|
|
||||||
|
# Client only (requires a running backend on :9000)
|
||||||
|
npm run dev:client
|
||||||
|
|
||||||
|
# Embed player only
|
||||||
|
npm run dev:embed
|
||||||
|
```
|
||||||
|
|
||||||
|
The Angular dev server proxies `/api`, `/plugins`, `/themes`,
|
||||||
|
`/static`, `/lazy-static`, `/socket.io`, and `/client/assets` to the
|
||||||
|
backend at `http://127.0.0.1:9000` (see `proxy.config.json`).
|
||||||
|
|
||||||
|
### Build
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Full client build (production)
|
||||||
|
npm run build:client
|
||||||
|
|
||||||
|
# Embed player build
|
||||||
|
npm run build:embed
|
||||||
|
```
|
||||||
|
|
||||||
|
Output goes to `client/dist/` with per-locale sub-directories
|
||||||
|
(e.g. `client/dist/en-US/`, `client/dist/fr-FR/`).
|
||||||
|
|
||||||
|
### Lint
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# From repository root
|
||||||
|
cd client
|
||||||
|
|
||||||
|
# TypeScript + Angular templates (ESLint)
|
||||||
|
npm run lint-ts
|
||||||
|
|
||||||
|
# SCSS (Stylelint)
|
||||||
|
npm run lint-scss
|
||||||
|
|
||||||
|
# Both
|
||||||
|
npm run lint
|
||||||
|
```
|
||||||
|
|
||||||
|
### E2E tests
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Local browser (from repo root)
|
||||||
|
npm run e2e:local
|
||||||
|
|
||||||
|
# BrowserStack
|
||||||
|
npm run e2e:browserstack
|
||||||
|
```
|
||||||
|
|
||||||
|
E2E uses **WebdriverIO** with a **Mocha** framework. Config files are
|
||||||
|
in `e2e/` (`wdio.local.conf.ts`, `wdio.browserstack.conf.ts`).
|
||||||
|
|
||||||
|
## Code Style & Conventions
|
||||||
|
|
||||||
|
### TypeScript / ESLint
|
||||||
|
|
||||||
|
The client has its own `eslint.config.mjs` extending
|
||||||
|
`eslint-config-love` and `angular-eslint`. Key rules match the
|
||||||
|
server:
|
||||||
|
|
||||||
|
| Rule | Value |
|
||||||
|
|---------------------|-----------------------------------|
|
||||||
|
| Semicolons | **never** (`@stylistic/semi`) |
|
||||||
|
| Max line length | 140 characters |
|
||||||
|
| Array brackets | Spaces inside `[ 'a', 'b' ]` |
|
||||||
|
| Trailing newline | Required (`eol-last`) |
|
||||||
|
| Indentation | 2 spaces |
|
||||||
|
|
||||||
|
### Angular-specific rules
|
||||||
|
|
||||||
|
| Rule | Value |
|
||||||
|
|------------------------------------------|--------------------------|
|
||||||
|
| Component selector prefix | `my-` (kebab-case) |
|
||||||
|
| Directive selector prefix | `my` (camelCase) |
|
||||||
|
| View encapsulation | Required (enforced) |
|
||||||
|
|
||||||
|
### SCSS / Stylelint
|
||||||
|
|
||||||
|
Configured in `.stylelintrc.json`, extends
|
||||||
|
`stylelint-config-sass-guidelines` with `stylelint-order`. Key rules:
|
||||||
|
|
||||||
|
- Declaration order: custom properties → declarations → `@include`
|
||||||
|
- Max nesting depth: 8
|
||||||
|
- Max compound selectors: 9
|
||||||
|
- `::ng-deep` pseudo-element allowed
|
||||||
|
|
||||||
|
### Naming patterns
|
||||||
|
|
||||||
|
- Lazy-loaded route folders: `+feature-name/` (e.g. `+admin/`,
|
||||||
|
`+video-watch/`)
|
||||||
|
- Shared modules: `shared-domain/` (e.g. `shared-video/`,
|
||||||
|
`shared-forms/`)
|
||||||
|
- Services: PascalCase with `Service` suffix
|
||||||
|
(`AuthService`, `ServerService`)
|
||||||
|
- Components: PascalCase with `Component` suffix, selector prefixed
|
||||||
|
`my-` (`my-video-miniature`)
|
||||||
|
- Path aliases: `@app/*` → `src/app/*`,
|
||||||
|
`@root-helpers/*` → `src/root-helpers/*`
|
||||||
|
|
||||||
|
### Internationalization
|
||||||
|
|
||||||
|
- Source locale: `en` (base href `/client/en-US/`)
|
||||||
|
- Translation files: XLIFF format in `src/locale/`
|
||||||
|
- Merge tool: `@peertube/xliffmerge` (config: `.xliffmerge.json`)
|
||||||
|
- Use Angular `$localize` / `i18n` attributes; do NOT use raw strings
|
||||||
|
for user-visible text
|
||||||
|
|
||||||
|
## Architecture Notes
|
||||||
|
|
||||||
|
```
|
||||||
|
┌────────────────────────────────────────────────────────┐
|
||||||
|
│ Angular SPA (client/) │
|
||||||
|
│ │
|
||||||
|
│ ┌──────────┐ ┌──────────────┐ ┌──────────────────┐ │
|
||||||
|
│ │ Routes │ │ Core │ │ Shared │ │
|
||||||
|
│ │ (+about, │ │ (auth, REST, │ │ (forms, video │ │
|
||||||
|
│ │ +admin, │──│ plugins, │──│ miniature, │ │
|
||||||
|
│ │ +videos) │ │ server, │ │ moderation...) │ │
|
||||||
|
│ │ │ │ theme) │ │ │ │
|
||||||
|
│ └──────────┘ └──────┬───────┘ └──────────────────┘ │
|
||||||
|
│ │ │
|
||||||
|
│ ┌─────────────────────▼────────────────────────────┐ │
|
||||||
|
│ │ root-helpers (no Angular dep) │ │
|
||||||
|
│ │ logger, storage, plugins-manager, theme, i18n │ │
|
||||||
|
│ └──────────────────────────────────────────────────┘ │
|
||||||
|
│ │
|
||||||
|
│ ┌─────────────────────────────────────────────────┐ │
|
||||||
|
│ │ standalone/ (Vite builds) │ │
|
||||||
|
│ │ player/ │ embed-player-api/ │ videos/embed │ │
|
||||||
|
│ └─────────────────────────────────────────────────┘ │
|
||||||
|
└────────────────────────┬────────────────────────────────┘
|
||||||
|
│ HTTP (REST API)
|
||||||
|
▼
|
||||||
|
┌──────────────────────┐
|
||||||
|
│ Express Backend │
|
||||||
|
│ (:9000 /api/v1/*) │
|
||||||
|
└──────────────────────┘
|
||||||
|
```
|
||||||
|
|
||||||
|
- **Lazy loading**: Each `+feature/` folder exports route configs
|
||||||
|
loaded via `loadChildren` in `app.routes.ts`
|
||||||
|
- **Core services**: Singletons bootstrapped in `main.ts` via
|
||||||
|
`getCoreProviders()` — auth, REST client, server config polling,
|
||||||
|
plugin hooks, theme manager
|
||||||
|
- **Plugin hooks**: Client-side plugins register via
|
||||||
|
`HooksService` / `PluginService` in `core/plugins/`
|
||||||
|
- **State management**: No dedicated store library; services hold
|
||||||
|
state, components subscribe via RxJS observables
|
||||||
|
- **UI framework**: Bootstrap 5 + PrimeNG + ng-bootstrap;
|
||||||
|
global SCSS in `src/sass/`
|
||||||
|
- **Video player**: Custom build in `standalone/player/` using
|
||||||
|
Video.js + HLS.js + P2P Media Loader; embedded via
|
||||||
|
`standalone/videos/embed.html`
|
||||||
|
|
||||||
|
## Agent Guardrails
|
||||||
|
|
||||||
|
### Files agents must NOT modify
|
||||||
|
|
||||||
|
- `src/locale/*.xlf` — Generated translation files; updated via
|
||||||
|
`npm run i18n:update` only
|
||||||
|
- `dist/` — Build output; never edit manually
|
||||||
|
- `node_modules/` — Managed by pnpm
|
||||||
|
- `.angular/` — Angular build cache
|
||||||
|
|
||||||
|
### Required checks before pushing
|
||||||
|
|
||||||
|
1. `cd client && npm run lint` must pass (TS + SCSS)
|
||||||
|
2. Production build must succeed: `npm run build:client`
|
||||||
|
(from repo root)
|
||||||
|
3. If new user-visible strings added: extract with
|
||||||
|
`npm run i18n:create-custom-files` and verify XLIFF
|
||||||
|
|
||||||
|
### Boundaries
|
||||||
|
|
||||||
|
- Do not import from `server/` — the client communicates with the
|
||||||
|
backend exclusively via the REST API
|
||||||
|
- Do not import Angular-specific code in `root-helpers/` or
|
||||||
|
`standalone/` — these must remain framework-agnostic
|
||||||
|
- Shared API types come from `@peertube/peertube-models` and
|
||||||
|
`@peertube/peertube-core-utils` (workspace packages)
|
||||||
|
- Do not add new npm dependencies without explicit approval
|
||||||
|
|
||||||
|
## Further Reading
|
||||||
|
|
||||||
|
- [../support/doc/plugins/guide.md](../support/doc/plugins/guide.md)
|
||||||
|
— Plugin & theme development (client hooks)
|
||||||
|
- [src/standalone/embed-player-api/README.md](src/standalone/embed-player-api/README.md)
|
||||||
|
— Embed player API documentation
|
||||||
|
- [../support/doc/api/embeds.md](../support/doc/api/embeds.md)
|
||||||
|
— Embed integration guide
|
||||||
|
- [../AGENTS.md](../AGENTS.md)
|
||||||
|
— Root project AGENTS.md (server, build, CI, testing)
|
||||||
Reference in New Issue
Block a user