Install:
- Git
- Docker Desktop with Docker Compose v2
- VS Code with the Dev Containers extension
- uv for host-side Python checks
- Node.js and npm for JavaScript checks
You also need access to the tCF Google Drive if you need a database dump.
Clone the repository and create the local environment file:
git clone https://github.com/thecourseforum/theCourseForum2.git
cd theCourseForum2
cp .env.example .envPostgreSQL reads the values in .env when its data directory is initialized.
.env is local-only and is excluded from Docker build contexts. Never put
production credentials in it.
The Compose project is named tcf.
Services without a profile provide the shared local infrastructure:
| Service | Purpose | Local address |
|---|---|---|
db |
PostgreSQL 18.1 | internal only |
valkey |
Cache, sessions, and Cachalot | internal only |
minio |
S3-compatible media/static storage | API localhost:9000, console localhost:9001 |
minio-init |
Creates the MinIO buckets, then exits | none |
cdn |
Serves the MinIO static bucket through Caddy | http://localhost:8081 |
The full profile adds the production-shaped application services:
| Service | Purpose |
|---|---|
release |
Migrations, static collection, Cachalot invalidation, and session cleanup |
web |
Bundled Django application served by Gunicorn on localhost:8000 |
The dev profile adds the VS Code development container:
| Service | Purpose |
|---|---|
devcontainer |
Development tools, Node.js, uv, and Docker-outside-of-Docker access |
The Compose profile controls which containers run; it does not select Django
settings. Local containers use TCF_ENV=local by default. ECS production tasks
set TCF_ENV=prod and use AWS RDS, ElastiCache, and S3.
Open the repository in VS Code and run Dev Containers: Reopen in Container.
If the container was previously created, use Dev Containers: Rebuild and
Reopen in Container after changing the Compose or devcontainer setup. The
devcontainer uses the dev profile, bind-mounts the repository at /app, and
installs the development dependencies.
For a first-time setup, restore the database from a host terminal before opening or rebuilding the devcontainer:
cp .env.example .env
# Copy the private db/latest.dump backup into db/latest.dump first.
./scripts/reset-db.shThe reset script is destructive: use it only for initial setup or when you intentionally want to replace the local database. Migrations create the schema but do not populate course data. It may stop or remove the existing devcontainer, so run it from the host rather than a devcontainer terminal.
Inside the devcontainer terminal, start the infrastructure, apply migrations,
collect static files, and run Django. The release command is a one-off task;
it does not start the web service, so the final command starts Django:
docker compose up -d
docker compose --profile full run --rm release
uv run python manage.py runserver 0.0.0.0:8000The devcontainer does not permanently forward port 8000. Use VS Code's Ports panel to forward port 8000, then open http://localhost:8000.
The devcontainer controls sibling Compose services through the mounted Docker
socket. Do not run a full docker compose down from inside the devcontainer;
run destructive lifecycle commands from a host terminal instead.
To run the complete local stack with Gunicorn:
docker compose --profile full up --buildThe release task waits for PostgreSQL, Valkey, and MinIO bucket initialization,
then web starts only after release succeeds.
The plain command below starts infrastructure/CDN only and does not start Django:
docker compose upOnce the full stack is running:
- Website: http://localhost:8000
- Static CDN: http://localhost:8081
- MinIO console: http://localhost:9001
Do not run the devcontainer server and bundled web service on port 8000 at
the same time.
Download the latest custom-format backup manually from the database backup
folder and save it as db/latest.dump.
From a host terminal, reset the local database and restore the dump with:
./scripts/reset-db.shThe script stops Compose services without deleting named volumes, clears the
public schema, and restores the dump through docker compose exec. Start the
chosen local workflow again afterward.
Create a custom-format local backup with:
./scripts/local_dump.sh [filename.dump]To remove all local database and object-storage data:
docker compose --profile full down -vIn the running bundled web service:
docker compose --profile full exec web python manage.py shell
docker compose --profile full exec web python manage.py fetch_clubs
docker compose --profile full exec web python manage.py load_grades ALL_DANGEROUSIn the devcontainer:
uv run python manage.py shell
uv run python manage.py fetch_clubs
uv run python manage.py load_grades ALL_DANGEROUSFor a one-off bundled-container command:
docker compose --profile full run --rm web python manage.py <command>TCF_ENV selects the Django runtime mode:
local: local development settings and debug tools; uses Postgres, Valkey, and MinIOci: debug disabled; uses the same Compose-backed services in GitHub Actionsprod: production settings; uses AWS RDS, ElastiCache, and S3; ECS must set this explicitly
The Compose full profile does not automatically set TCF_ENV=prod.
The development dependencies include prek, a compatible replacement for
pre-commit. Inside the devcontainer, install the hooks once per checkout:
uv run prek installThe hooks run automatically before commits. Run them manually with:
uv run prek run --all-filesRun the same host-side checks used by CI:
uv sync --frozen --group dev --no-install-project
uv run ruff check .
uv run ruff format --check .
uv run djlint tcf_website/templates --check --lint
uv run ty check
npm ci
npx eslint -c .config/.eslintrc.yml tcf_website/static/Run the Compose-backed Django tests with:
docker compose --profile full run --rm --build web python manage.py testGitHub Actions runs these tests with coverage against the same PostgreSQL, Valkey, and MinIO services.
Login, logout, and profile functionality requires additional Cognito credentials. Consult the project maintainers if you need access.