Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ web_modules/
# dotenv environment variable files
.env
.env.*
!.env.local.*.example
!.env.example

# parcel-bundler cache (https://parceljs.org/)
Expand Down
235 changes: 235 additions & 0 deletions DOCKER.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,235 @@
# 🐳 Docker — Local Development Guide

This guide covers everything you need to run any part of the Call of Code platform locally using Docker Compose.

---

## Overview

The repository ships with **four Docker Compose configurations**:

| File | Purpose | Services |
|------|---------|----------|
| `docker-compose.yml` | **API-only** dev (standalone) | `coc-api` |
| `docker/coc-member/docker-compose.yml` | Full **COC Member** stack | `coc-api` + `server` + `web` |
| `docker/coc-admin/docker-compose.yml` | Full **COC Admin** stack | `coc-api` + `server` + `web` |
| `docker/callofcode.in/docker-compose.yml` | Full **callofcode.in** website stack | `coc-api` + `frontend` |

> All platform stacks build `coc-api` locally from the repo root `Dockerfile` and pull their respective frontend/backend images from Docker Hub.

---

## Prerequisites

- [Docker Desktop](https://docs.docker.com/get-docker/) or Docker Engine + Docker Compose plugin (v2.22+)
- Git

No need to install Bun, Node, or any other runtime locally — everything runs inside containers.

---

## Environment Setup

### 1. API environment (required by all stacks)

Copy the example and fill in your Supabase credentials:

```bash
cp .env.example .env.local
```

| Variable | Description |
|----------|-------------|
| `DATABASE_URL` | Supabase connection-pooling URL (Prisma runtime) |
| `DIRECT_URL` | Direct DB connection URL (Prisma Migrate) |
| `SUPABASE_URL` | Your Supabase project URL |
| `SUPABASE_SERVICE_ROLE_KEY` | Supabase service-role secret key |

### 2. Platform-specific environments

Each platform directory ships **example files** with all variables documented and placeholder values. Copy and fill in only the secrets you need:

```bash
# COC Member
cp docker/coc-member/.env.local.backend.example docker/coc-member/.env.local.backend
cp docker/coc-member/.env.local.frontend.example docker/coc-member/.env.local.frontend

# COC Admin
cp docker/coc-admin/.env.local.backend.example docker/coc-admin/.env.local.backend
cp docker/coc-admin/.env.local.frontend.example docker/coc-admin/.env.local.frontend

# callofcode.in
cp docker/callofcode.in/.env.local.frontend.example docker/callofcode.in/.env.local.frontend
```

| Platform | File | Key Variables |
|----------|------|---------------|
| All backends | `.env.local.backend` | `JWT_SECRET`, `REFRESH_SECRET`, `RESEND_API_KEY` |
| `coc-admin` backend | `.env.local.backend` | + `WHATSAPP_LINK`, `DISCORD_LINK` |
| `coc-member` frontend | `.env.local.frontend` | `VITE_API_URL` |
| `coc-admin` frontend | `.env.local.frontend` | `VITE_API_URL`, `VITE_GIF_URL` |
| `callofcode.in` frontend | `.env.local.frontend` | `API_BASE_URL`, `GITHUB_TOKEN` (optional) |

> **Never commit real secrets.** All `*.env.local*` files are git-ignored by default.

---

## Running the Stacks

### API-only (standalone development)

Use this when you're only working on the `coc-api` itself:

```bash
# Standard mode
docker compose up --build

# Watch mode — Docker syncs src/ changes and restarts bun automatically
docker compose watch
```

The API will be available at **http://localhost:3000**

Health check: **http://localhost:3000/health**

---

### COC Member stack

```bash
cd docker/coc-member
docker compose up --build
```

| Service | URL |
|---------|-----|
| `coc-api` | http://localhost:3000 |
| `server` (member backend) | http://localhost:8000 |
| `web` (member frontend) | http://localhost:5173 |

---

### COC Admin stack

```bash
cd docker/coc-admin
docker compose up --build
```

| Service | URL |
|---------|-----|
| `coc-api` | http://localhost:3000 |
| `server` (admin backend) | http://localhost:8000 |
| `web` (admin frontend) | http://localhost:5173 |

---

### callofcode.in website

```bash
cd docker/callofcode.in
docker compose up --build
```

| Service | URL |
|---------|-----|
| `coc-api` | http://localhost:3000 |
| `frontend` | http://localhost:3001 |

---

## Startup Order & Health Checks

All stacks use health-checked `depends_on` to ensure correct startup ordering:

```
coc-api (healthy) → server/backend (healthy) → web/frontend
```
Comment on lines +145 to +147

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Add a language to the fenced code block.

Line 145 uses an untyped fenced block, which triggers MD040 and can break markdown lint in CI.

Proposed fix
-```
+```text
 coc-api (healthy) → server/backend (healthy) → web/frontend
</details>

<!-- suggestion_start -->

<details>
<summary>📝 Committable suggestion</summary>

> ‼️ **IMPORTANT**
> Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

```suggestion

🧰 Tools
🪛 markdownlint-cli2 (0.22.1)

[warning] 145-145: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@DOCKER.md` around lines 145 - 147, The fenced diagram block in DOCKER.md is
missing a language tag, causing the markdown lint issue. Update the untyped
fenced block that contains the coc-api → server/backend → web/frontend flow to
use a text language label, and keep the content unchanged so the block remains
readable and lint-compliant.

Source: Linters/SAST tools


The `coc-api` health check polls `GET /health` every 30 seconds with a 15-second grace period on startup. Downstream services only start once `coc-api` reports healthy.

---

## Hot Reload (API-only stack)

The root `docker-compose.yml` supports `docker compose watch` with the following rules:

| Path changed | Action |
|---|---|
| `src/**` | **Sync** — files copied into container instantly; `bun --watch` picks up the change |
| `package.json` / `bun.lock` | **Rebuild** — full image rebuild to reinstall dependencies |
| `prisma/**` | **Rebuild** — triggers `prisma generate` on next container start |

```bash
# Start in watch mode (preferred for API development)
docker compose watch
```

---

## Common Commands

```bash
# Start in the background (detached)
docker compose up -d --build

# Follow logs
docker compose logs -f

# Follow logs for a specific service
docker compose logs -f coc-api

# Stop all containers
docker compose down

# Stop and remove volumes (clean slate)
docker compose down -v

# Rebuild a single service without restarting others
docker compose build coc-api

# Open a shell inside a running container
docker compose exec coc-api sh

# Run Prisma Studio (from inside the coc-api container)
docker compose exec coc-api bunx prisma studio
```

---

## Dockerfile Stages

The root `Dockerfile` uses a multi-stage build:

| Stage | Target | Purpose |
|-------|--------|---------|
| `deps` | — | Installs production dependencies only |
| `builder` | `target: builder` | Installs all deps + generates Prisma client; **used by all dev compose files** |
| `runner` | — | Lean production image; runs as non-root `cocuser` |

The dev compose files use `target: builder` so that devDependencies and the Prisma CLI are available inside the container.

---

## Troubleshooting

**`open Dockerfile: no such file or directory`**
The `dockerfile:` path in compose is relative to the `context`, not the compose file. Our configs set `context: ../..` (repo root) so `dockerfile: Dockerfile` resolves correctly.

**Port already in use**
Set a custom port via the `PORT` env variable before running:
```bash
PORT=3001 docker compose up
```

**Prisma migration errors on startup**
The `coc-api` container runs `prisma migrate deploy` on every start. If the DB is unreachable, the container will exit. Verify your `DATABASE_URL` and `DIRECT_URL` in `.env.local`.

**Container exits immediately after `healthy`**
Check logs with `docker compose logs coc-api`. Common causes: missing env vars or a failed migration.

**Stale node_modules in container**
The anonymous volume `/app/node_modules` is intentionally excluded from the host mount to avoid cross-OS binary conflicts. If you change `package.json`, let Docker rebuild:
```bash
docker compose build --no-cache coc-api
```
90 changes: 63 additions & 27 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,11 @@ This repository contains the shared Express.js API for the backends of our Codin
## 📂 Folder Structure

```
/
COC-API/
├── prisma/ # Prisma schema and migration files
│ ├── schema.prisma
│ └── migrations/ # auto-generated by `bun run migrate`
├── seed/
│ └── dump.sql # local seed file loaded by the setup script
├── scripts/
│ └── setup-local.sh # automates local environment bring-up
├── src/
│ ├── config/ # environment/configuration loaders
│ │
Expand Down Expand Up @@ -75,7 +69,21 @@ This repository contains the shared Express.js API for the backends of our Codin
│ ├── SiteContent.test.ts
│ └── imageUtils.test.ts
├── .env.example # template for environment variables
├── docker/ # Platform-specific Docker Compose stacks
│ ├── coc-member/ # Full COC Member platform stack
│ │ ├── docker-compose.yml
│ │ ├── .env.local.backend.example
│ │ └── .env.local.frontend.example
│ ├── coc-admin/ # Full COC Admin platform stack
│ │ ├── docker-compose.yml
│ │ ├── .env.local.backend.example
│ │ └── .env.local.frontend.example
│ └── callofcode.in/ # Full callofcode.in website stack
│ ├── docker-compose.yml
│ └── .env.local.frontend.example
├── .env.example # API environment variable template
├── docker-compose.yml # API-only dev stack (standalone)
├── package.json
└── tsconfig.json
```
Expand All @@ -84,8 +92,8 @@ This repository contains the shared Express.js API for the backends of our Codin

### Prerequisites

- Install [Bun](https://bun.sh/) on your machine.
- Install [Docker & Docker Compose](https://docs.docker.com/get-docker/) for the local database.
- [Docker Desktop](https://docs.docker.com/get-docker/) or Docker Engine + Compose plugin v2.22+ — **required for all workflows**
- [Bun](https://bun.sh/) — only needed if you want to run the API outside Docker

### 1. Clone the repo

Expand All @@ -94,40 +102,68 @@ git clone https://github.com/call-0f-code/COC-API.git
cd COC-API
```

### 2. Install dependencies
### 2. Configure environment

**API credentials** (required by all stacks):

```bash
bun install
cp .env.example .env.local
```

### 3. Configure environment
| Variable | Description |
|----------|-------------|
| `DATABASE_URL` | Supabase connection-pooling URL (Prisma runtime) |
| `DIRECT_URL` | Direct DB connection URL (Prisma Migrate) |
| `SUPABASE_URL` | Your Supabase project URL |
| `SUPABASE_SERVICE_ROLE_KEY` | Supabase service-role secret key |
| `NODE_ENV` | `development` \| `production` |

Copy `.env.example` to `.env` and fill in the required values:
**Platform-specific credentials** (only needed for the stack you're running):

```bash
cp .env.example .env
# COC Member
cp docker/coc-member/.env.local.backend.example docker/coc-member/.env.local.backend
cp docker/coc-member/.env.local.frontend.example docker/coc-member/.env.local.frontend

# COC Admin
cp docker/coc-admin/.env.local.backend.example docker/coc-admin/.env.local.backend
cp docker/coc-admin/.env.local.frontend.example docker/coc-admin/.env.local.frontend

# callofcode.in
cp docker/callofcode.in/.env.local.frontend.example docker/callofcode.in/.env.local.frontend
```

Key variables:
Edit each file and replace the `change_me_*` and `your_*` placeholders with real values. See [DOCKER.md](DOCKER.md) for a full variable reference.

### 3. Install dependencies (local dev only)

| Variable | Description |
| ------------------------- | --------------------------------------------------------------------------- |
| `DATABASE_URL` | Supabase connection-pooling URL (used by Prisma at runtime) |
| `DIRECT_URL` | Direct DB connection URL (used by Prisma Migrate) |
| `SUPABASE_URL` | Your Supabase project URL |
| `SUPABASE_SERVICE_ROLE_KEY` | Supabase service-role secret key |
| `SESSION_POOLER` | Session-mode pooler URL — used by `setup-local.sh` for `pg_dump` (IPv4) |
| `NODE_ENV` | `development` \| `production` |
Only needed if you are running the API outside Docker:

```bash
bun install
```

### 4. Local development (Docker)

The setup script starts a local Postgres container and seeds it automatically:
The project ships **four Docker Compose stacks**. Choose the one you need:

```bash
bun run local
# API only (for coc-api development)
docker compose up --build

# Full COC Member platform
cd docker/coc-member && docker compose up --build

# Full COC Admin platform
cd docker/coc-admin && docker compose up --build

# Full callofcode.in website
cd docker/callofcode.in && docker compose up --build
```

> See [LOCAL_DEVELOPMENT.md](LOCAL_DEVELOPMENT.md) for full details, flags, and troubleshooting.
All stacks automatically run Prisma migrations on startup and use health checks to ensure correct service startup order.

> 📖 See [DOCKER.md](DOCKER.md) for full details — environment files, watch mode, port mappings, common commands, and troubleshooting.

### 5. Initialize / run migrations

Expand Down
Loading
Loading