summaryrefslogtreecommitdiffhomepage
path: root/docs/phase-0-setup.md
blob: 09ed772ddae4172b9c35524f2b7845398167f2b3 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
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