Skip to content

Development Setup

Set up your local environment to contribute to Discord Forum API.

Prerequisites

ToolVersionInstall
Node.js20.x+nodejs.org
pnpm9.x+npm install -g pnpm
GitAnygit-scm.com
Discord Bot-Discord Setup

Quick Setup

  1. Fork the repository

    Click “Fork” on GitHub

  2. Clone your fork

    Terminal window
    git clone https://github.com/YOUR_USERNAME/discord-forum-api.git
    cd discord-forum-api
  3. Install dependencies

    Terminal window
    pnpm install
  4. Configure environment

    Terminal window
    cp .env.example .env
    # Edit .env with your Discord credentials
  5. Initialize database

    Terminal window
    pnpm db:push
  6. Start development

    Terminal window
    pnpm dev

Project Structure

discord-forum-api/
├── packages/
│ ├── api/ # REST API (Hono.js)
│ │ ├── src/
│ │ │ ├── routes/ # API endpoints
│ │ │ ├── middleware/
│ │ │ └── lib/
│ │ └── package.json
│ │
│ ├── bot/ # Discord bot (discord.js)
│ │ ├── src/
│ │ │ ├── events/ # Discord event handlers
│ │ │ ├── commands/ # Slash commands
│ │ │ ├── sync/ # Sync logic
│ │ │ └── lib/
│ │ └── package.json
│ │
│ ├── db/ # Database (Drizzle ORM)
│ │ ├── src/
│ │ │ ├── schema.ts # Database schema
│ │ │ ├── client.ts # DB client
│ │ │ └── helpers.ts
│ │ └── package.json
│ │
│ └── docs/ # Documentation (Starlight)
│ ├── src/
│ │ └── content/docs/
│ └── package.json
├── docs/ # Legacy markdown docs
├── turbo.json # Turborepo config
├── tsconfig.json # Base TypeScript config
└── package.json # Root workspace

Development Commands

All Packages

CommandDescription
pnpm devStart all packages in watch mode
pnpm buildBuild all packages
pnpm lintRun ESLint
pnpm lint:fixFix auto-fixable lint issues
pnpm typecheckRun TypeScript type checking
pnpm testRun all tests

Database

CommandDescription
pnpm db:pushPush schema to database
pnpm db:generateGenerate migrations
pnpm db:migrateRun migrations
pnpm db:studioOpen Drizzle Studio GUI

Documentation

CommandDescription
pnpm docs:devStart docs dev server
pnpm docs:buildBuild docs site
pnpm docs:previewPreview built docs

Single Package

Terminal window
# Run command in specific package
pnpm --filter @discolink/api dev
pnpm --filter @discolink/bot build
pnpm --filter @discolink/db test

IDE Setup

VS Code

Recommended extensions:

.vscode/extensions.json
{
"recommendations": [
"dbaeumer.vscode-eslint",
"esbenp.prettier-vscode",
"astro-build.astro-vscode",
"bradlc.vscode-tailwindcss"
]
}

Settings:

.vscode/settings.json
{
"editor.formatOnSave": true,
"editor.defaultFormatter": "esbenp.prettier-vscode",
"editor.codeActionsOnSave": {
"source.fixAll.eslint": "explicit"
},
"typescript.tsdk": "node_modules/typescript/lib"
}

Other Editors

  • WebStorm: Built-in TypeScript support
  • Neovim: Use typescript-language-server
  • Sublime Text: LSP + TypeScript plugin

Testing

Run All Tests

Terminal window
pnpm test

Run Specific Tests

Terminal window
# By package
pnpm --filter @discolink/api test
# By pattern
pnpm test -- --grep "threads"
# Watch mode
pnpm test -- --watch

Test Coverage

Terminal window
pnpm test:cov

Writing Tests

Tests use Vitest. Example:

packages/api/src/routes/threads.test.ts
import { describe, it, expect, beforeEach } from 'vitest';
import { app } from '../index';
describe('GET /api/threads', () => {
it('returns threads list', async () => {
const res = await app.request('/api/threads?serverId=123');
expect(res.status).toBe(200);
const data = await res.json();
expect(data).toHaveProperty('threads');
expect(Array.isArray(data.threads)).toBe(true);
});
it('requires serverId parameter', async () => {
const res = await app.request('/api/threads');
expect(res.status).toBe(400);
});
});

Database Development

Drizzle Studio

Explore your database visually:

Terminal window
pnpm db:studio

Opens at http://localhost:4983

Schema Changes

  1. Modify packages/db/src/schema.ts

  2. Generate migration:

    Terminal window
    pnpm db:generate
  3. Review generated SQL in packages/db/drizzle/

  4. Apply migration:

    Terminal window
    pnpm db:migrate

    Or for development, push directly:

    Terminal window
    pnpm db:push

Seeding Data

Create test data for development:

packages/db/src/seed.ts
import { db } from './client';
import { servers, threads, messages } from './schema';
async function seed() {
// Insert test server
await db.insert(servers).values({
id: '123456789',
name: 'Test Server',
icon: null,
});
// Insert test thread
await db.insert(threads).values({
id: '111222333',
serverId: '123456789',
title: 'Test Thread',
// ...
});
console.log('Seed complete!');
}
seed();

Run with:

Terminal window
pnpm --filter @discolink/db tsx src/seed.ts

Environment Variables

Required

DISCORD_TOKEN=your_bot_token
DISCORD_CLIENT_ID=your_client_id

Optional

# Database (default: sqlite)
DATABASE_TYPE=sqlite
DATABASE_PATH=./data/discord-forum.db
# For Turso
DATABASE_TYPE=turso
TURSO_DATABASE_URL=libsql://...
TURSO_AUTH_TOKEN=...
# API
API_PORT=3000
CORS_ORIGIN=http://localhost:3000
# Development
LOG_LEVEL=debug
SYNC_BOT_MESSAGES=true

Debugging

VS Code Debugger

Create .vscode/launch.json:

{
"version": "0.2.0",
"configurations": [
{
"name": "Debug API",
"type": "node",
"request": "launch",
"runtimeExecutable": "pnpm",
"runtimeArgs": ["--filter", "@discolink/api", "dev"],
"cwd": "${workspaceFolder}",
"console": "integratedTerminal"
},
{
"name": "Debug Bot",
"type": "node",
"request": "launch",
"runtimeExecutable": "pnpm",
"runtimeArgs": ["--filter", "@discolink/bot", "dev"],
"cwd": "${workspaceFolder}",
"console": "integratedTerminal"
}
]
}

Console Logging

// Use structured logging
console.log('[DEBUG]', { action: 'sync', threadId: '123' });

Inspecting Requests

Terminal window
# Use curl to test API
curl -v http://localhost:3000/api/threads?serverId=123
# Use httpie for nicer output
http localhost:3000/api/threads serverId==123

Common Tasks

Adding a New Endpoint

  1. Create route file:

    packages/api/src/routes/my-route.ts
    import { Hono } from 'hono';
    export const myRoute = new Hono();
    myRoute.get('/', async (c) => {
    return c.json({ hello: 'world' });
    });
  2. Register in main app:

    packages/api/src/index.ts
    import { myRoute } from './routes/my-route';
    app.route('/api/my-route', myRoute);
  3. Add tests:

    packages/api/src/routes/my-route.test.ts

Adding a Discord Event Handler

  1. Create event file:

    packages/bot/src/events/myEvent.ts
    import { Events } from 'discord.js';
    import type { Client } from 'discord.js';
    export function register(client: Client) {
    client.on(Events.MessageCreate, async (message) => {
    // Handle event
    });
    }
  2. Register in bot:

    packages/bot/src/index.ts
    import * as myEvent from './events/myEvent';
    myEvent.register(client);

Troubleshooting

”Module not found” Errors

Terminal window
# Rebuild packages
pnpm build
# Or clean and reinstall
rm -rf node_modules packages/*/node_modules
pnpm install

TypeScript Errors

Terminal window
# Check types across all packages
pnpm typecheck

Database Issues

Terminal window
# Reset database (development only!)
rm -f data/discord-forum.db
pnpm db:push

Bot Not Connecting

  1. Verify token in .env
  2. Check intents in Discord Developer Portal
  3. Review console output for errors