diff options
Diffstat (limited to 'docs/phase-0-setup.md')
| -rw-r--r-- | docs/phase-0-setup.md | 338 |
1 files changed, 338 insertions, 0 deletions
diff --git a/docs/phase-0-setup.md b/docs/phase-0-setup.md new file mode 100644 index 0000000..09ed772 --- /dev/null +++ b/docs/phase-0-setup.md @@ -0,0 +1,338 @@ +# Phase 0 — Project Setup & Installation + +> **Goal:** Initialize the project, install every dependency, configure all tooling, and create every non-code file. After this phase completes, the project is fully scaffolded and ready for Phase 1 (code). **No packages may be installed after this phase.** + +--- + +## 0.1 — Initialize the Project + +```bash +cd /home/tradam/projects/music-bot +git init +npm init -y +``` + +Edit `package.json` to set these fields: + +```jsonc +{ + "name": "music-bot", + "version": "1.0.0", + "description": "Personal Discord music bot — streams YouTube audio to voice channels", + "main": "dist/index.js", + "type": "commonjs", + "engines": { + "node": ">=20.0.0" + }, + "scripts": { + "build": "tsup", + "start": "node dist/index.js", + "dev": "ts-node src/index.ts", + "test": "vitest run", + "test:watch": "vitest", + "test:coverage": "vitest run --coverage", + "lint": "tsc --noEmit", + "deploy-commands": "ts-node src/deploy-commands.ts" + } +} +``` + +--- + +## 0.2 — Install Production Dependencies + +```bash +npm install discord.js @discordjs/voice discord-player @discord-player/extractor discord-player-youtubei mediaplex sodium-native dotenv +``` + +| Package | Purpose | +|---|---| +| `discord.js` v14 | Discord API client — gateway, REST, slash commands, intents | +| `@discordjs/voice` | Low-level voice connections, audio players, audio resources | +| `discord-player` v6+ | High-level music framework — queue, events, search, filters | +| `@discord-player/extractor` | Default extractors bundled with discord-player | +| `discord-player-youtubei` | YouTube extraction backend via youtubei.js (InnerTube API) | +| `mediaplex` | Opus codec binding — recommended by discord-player over `@discordjs/opus` | +| `sodium-native` | Voice data encryption — required by `@discordjs/voice` | +| `dotenv` | Loads `.env` file into `process.env` for local development | + +--- + +## 0.3 — Install Dev Dependencies + +```bash +npm install -D typescript @types/node ts-node tsup vitest @vitest/coverage-v8 +``` + +| Package | Purpose | +|---|---| +| `typescript` | TypeScript compiler | +| `@types/node` | Node.js type declarations | +| `ts-node` | Execute `.ts` files directly during development | +| `tsup` | Fast zero-config TypeScript bundler for production builds | +| `vitest` | Test runner (fast, native TypeScript, Vite-powered) | +| `@vitest/coverage-v8` | Code coverage reporting via V8 engine | + +--- + +## 0.4 — Create TypeScript Configuration + +Create `tsconfig.json`: + +```json +{ + "compilerOptions": { + "target": "ES2022", + "module": "commonjs", + "lib": ["ES2022"], + "outDir": "./dist", + "rootDir": "./src", + "strict": true, + "noUncheckedIndexedAccess": true, + "noImplicitReturns": true, + "noFallthroughCasesInSwitch": true, + "forceConsistentCasingInFileNames": true, + "esModuleInterop": true, + "skipLibCheck": true, + "resolveJsonModule": true, + "declaration": true, + "declarationMap": true, + "sourceMap": true, + "isolatedModules": true + }, + "include": ["src/**/*"], + "exclude": ["node_modules", "dist"] +} +``` + +--- + +## 0.5 — Create Build Configuration + +Create `tsup.config.ts`: + +```typescript +import { defineConfig } from 'tsup'; + +export default defineConfig({ + entry: ['src/index.ts'], + format: ['cjs'], + target: 'es2022', + outDir: 'dist', + clean: true, + sourcemap: true, + splitting: false, +}); +``` + +--- + +## 0.6 — Create Test Configuration + +Create `vitest.config.ts`: + +```typescript +import { defineConfig } from 'vitest/config'; + +export default defineConfig({ + test: { + globals: true, + environment: 'node', + include: ['src/**/*.test.ts', 'tests/**/*.test.ts'], + coverage: { + provider: 'v8', + include: ['src/**/*.ts'], + exclude: [ + 'src/**/*.test.ts', + 'src/index.ts', + 'src/deploy-commands.ts', + ], + }, + }, +}); +``` + +--- + +## 0.7 — Create Environment File Templates + +### `.env.example` (committed — documents required variables) + +```env +DISCORD_TOKEN=your_bot_token_here +CLIENT_ID=your_application_id_here +GUILD_ID=optional_test_guild_id_for_dev +PREFIX=! +``` + +### `.env` (never committed — actual secrets, fill in manually) + +```env +DISCORD_TOKEN= +CLIENT_ID= +GUILD_ID= +PREFIX=! +``` + +--- + +## 0.8 — Create `.gitignore` + +```gitignore +node_modules/ +dist/ +.env +*.log +coverage/ +``` + +--- + +## 0.9 — Create `.dockerignore` + +```dockerignore +node_modules/ +dist/ +.env +.git/ +coverage/ +docs/ +*.md +.gitignore +``` + +--- + +## 0.10 — Create Dockerfile (Multi-Stage) + +The multi-stage build lets Dokploy build everything from the GitHub repo with no external CI step. + +```dockerfile +# ── Stage 1: Build ── +FROM node:20-alpine AS builder + +WORKDIR /app + +COPY package.json package-lock.json ./ +RUN npm ci + +COPY tsup.config.ts tsconfig.json ./ +COPY src/ ./src/ + +RUN npm run build + +# ── Stage 2: Production ── +FROM node:20-alpine + +WORKDIR /app + +RUN apk add --no-cache ffmpeg + +COPY package.json package-lock.json ./ +RUN npm ci --omit=dev + +COPY --from=builder /app/dist ./dist + +ENV NODE_ENV=production + +CMD ["node", "dist/index.js"] +``` + +> **Note:** The bot connects outbound to Discord's WebSocket gateway. It does not listen on any HTTP port. No domain or port mapping is needed in Dokploy. + +--- + +## 0.11 — Create Directory Structure + +```bash +mkdir -p src/commands src/events src/player src/utils tests +``` + +--- + +## 0.12 — Dokploy Deployment Notes + +When deploying on Dokploy: + +1. **Create a Project** → **Create an Application** (not Compose — single container, no database) +2. **Provider:** GitHub → select the repo → branch `main` +3. **Build Type:** Dockerfile (at repo root, named `Dockerfile`) +4. **Environment Variables** (set in Dokploy's Environment tab): + ``` + DISCORD_TOKEN=<actual token> + CLIENT_ID=<actual client id> + GUILD_ID=<actual guild id> + PREFIX=! + ``` +5. **Domains:** Leave empty — the bot is not a web server +6. **Auto-Deploy:** Enabled by default — push to `main` triggers rebuild + +--- + +## 0.13 — Verify Setup + +```bash +# TypeScript type-checks (will fail until src/index.ts exists — expected) +npx tsc --noEmit + +# Vitest runs (0 tests found — expected) +npm test + +# tsup builds (will fail until src/index.ts exists — expected) +npm run build +``` + +--- + +## 0.14 — Initial Commit + +```bash +git add -A +git commit -m "chore: project scaffold — deps, tooling, dockerfile" +``` + +--- + +## Final Directory Tree After Phase 0 + +``` +music-bot/ +├── docs/ +│ ├── phase-0-setup.md +│ └── phase-1-implementation.md +├── src/ +│ ├── commands/ +│ ├── events/ +│ ├── player/ +│ └── utils/ +├── tests/ +├── .dockerignore +├── .env +├── .env.example +├── .gitignore +├── Dockerfile +├── package.json +├── package-lock.json +├── tsconfig.json +├── tsup.config.ts +└── vitest.config.ts +``` + +--- + +## Phase 0 Checklist + +- [ ] `git init` +- [ ] `npm init -y` → edit `package.json` (scripts, engines, type) +- [ ] `npm install` production dependencies (8 packages) +- [ ] `npm install -D` dev dependencies (6 packages) +- [ ] Create `tsconfig.json` +- [ ] Create `tsup.config.ts` +- [ ] Create `vitest.config.ts` +- [ ] Create `.env.example` and `.env` +- [ ] Create `.gitignore` +- [ ] Create `.dockerignore` +- [ ] Create `Dockerfile` (multi-stage) +- [ ] Create directories: `src/commands`, `src/events`, `src/player`, `src/utils`, `tests` +- [ ] Verify commands run +- [ ] Initial git commit |
