Files
job-tracker/docs/implementation-issue-1-monorepo-scaffold.md
T
Marko (Hermes Implementer) b91b7c364e feat: set up monorepo scaffold with Yarn workspaces, Django API, React/Vite web, and Docker Compose
- Root package.json with Yarn workspaces (web, api)
- /web: React 19 + Vite 6 + @vitejs/plugin-react
  - index.html, src/main.jsx, src/App.jsx, vite.config.js
- /api: Django 5.x managed with uv
  - pyproject.toml with Django + psycopg2-binary
  - project/settings.py with PostgreSQL config from DATABASE_URL
  - project/urls.py, project/wsgi.py, manage.py
- docker-compose.yml with db (postgres:15), api, web services
  - Health check for db, live code volumes, dependency ordering
- Dockerfiles for both web (node:20-alpine) and api (python:3.12-slim)
- .gitignore updated for Python build artifacts and venv
- docs/implementation-issue-1-monorepo-scaffold.md
2026-05-24 07:38:14 +00:00

8.4 KiB

Monorepo Scaffold — Implementation Document

Issue: #1 — Set up monorepo scaffold with Yarn workspaces for Web and API

Branch: feature/setup-monorepo-scaffold

Status: Implemented

Project Structure

job-tracker/
├── package.json              # Yarn workspaces root ("web", "api")
├── docker-compose.yml        # PostgreSQL 15 + Django API + React/Vite web
├── README.md
├── .gitignore
│
├── api/                      # Django REST API (Python 3.12)
│   ├── Dockerfile
│   ├── pyproject.toml        # uv-managed Python dependencies
│   ├── uv.lock
│   ├── manage.py             # Django management CLI entrypoint
│   └── project/
│       ├── __init__.py
│       ├── settings.py       # PostgreSQL config via DATABASE_URL
│       ├── urls.py           # Root URL configuration
│       └── wsgi.py           # WSGI application
│
└── web/                      # React 19 + Vite frontend
    ├── Dockerfile
    ├── package.json          # React 19, Vite 6, @vitejs/plugin-react
    ├── vite.config.js        # Dev server on 0.0.0.0:3000, polling
    ├── index.html            # HTML entry point
    └── src/
        ├── main.jsx          # ReactDOM.createRoot mount
        └── App.jsx           # Basic App component

1. Root package.json — Yarn Workspaces

File: package.json

{
  "name": "job-tracker",
  "private": true,
  "workspaces": ["web", "api"]
}
  • Declares web and api as Yarn workspace members.
  • Dependencies from each workspace are hoisted to the root node_modules/ where possible.

Note: "api" is listed as a workspace member purely for the monorepo structure. The actual Python/Django dependencies are managed via uv (see Section 3).


2. Docker Compose — Development Environment

File: docker-compose.yml

Three services orchestrated for local development:

db (PostgreSQL 15)

Setting Value
Image postgres:15
DB Name jobtracker
User / Password jobtracker / jobtracker
Port 5432
Volume postgres_data:/var/lib/postgresql/data
Health Check pg_isready -U jobtracker -d jobtracker (5s interval, 10 retries)

api (Django)

Setting Value
Build Context ./api
Port 8000
Env Vars DATABASE_URL=postgres://jobtracker:...@db:5432/jobtracker
Volumes ./api:/app (live code reload)
Command python manage.py migrate && python manage.py runserver 0.0.0.0:8000
Depends On dbcondition: service_healthy

web (React + Vite)

Setting Value
Build Context ./web
Port 3000
Env Vars REACT_APP_API_URL=http://localhost:8000
Volumes ./web:/app + /app/node_modules (live reload)
Depends On dbcondition: service_healthy

How to start

docker compose up

3. Django API (/api)

Dependency Management with uv

File: api/pyproject.toml

[project]
name = "api"
version = "1.0.0"
requires-python = ">=3.12"
dependencies = [
    "django>=5.1,<6.0",
    "psycopg2-binary>=2.9",
]

Install and verify:

cd api
uv sync
uv run python manage.py check
# → System check identified no issues (0 silenced).

Database Configuration (settings.py)

The DATABASES setting is built dynamically from the DATABASE_URL environment variable:

DATABASE_URL = "postgres://user:password@host:port/dbname"

Parsed into the standard Django DATABASES dict with:

  • ENGINE: django.db.backends.postgresql
  • NAME, USER, PASSWORD, HOST, PORT — all extracted from the URL

Default value when DATABASE_URL is unset: postgres://jobtracker:jobtracker@localhost:5432/jobtracker

Installed Apps (Minimal)

INSTALLED_APPS = [
    "django.contrib.contenttypes",
    "django.contrib.auth",
]

Files Created

File Purpose
api/Dockerfile Python 3.12-slim + uv + libpq → Django dev
api/manage.py Django CLI entrypoint
api/pyproject.toml uv project config with Django + psycopg2
api/project/__init__.py Python package marker
api/project/settings.py Django settings with PostgreSQL
api/project/urls.py Root URL configuration
api/project/wsgi.py WSGI application

4. React Frontend (/web)

Dependencies

Package Version Type
react ^19.0.0 dependency
react-dom ^19.0.0 dependency
vite ^6.0.0 devDependency
@vitejs/plugin-react ^4.3.0 devDependency

Vite Configuration

File: web/vite.config.js

export default defineConfig({
  plugins: [react()],
  server: {
    host: "0.0.0.0",
    port: 3000,
    watch: { usePolling: true },  // required for Docker volume mounts
  },
});

Entry Point

File: web/src/main.jsx — mounts <App /> inside React.StrictMode on the #root element.

Component

File: web/src/App.jsx — minimal functional component:

function App() {
  return (
    <div>
      <h1>Job Tracker</h1>
      <p>Welcome to the Job Tracker application.</p>
    </div>
  );
}

Files Created

File Purpose
web/Dockerfile Node 20-alpine + yarn → dev server on :3000
web/package.json React 19 + Vite 6 dependencies
web/vite.config.js Vite dev server config with polling
web/index.html HTML shell loading /src/main.jsx
web/src/main.jsx React entry point
web/src/App.jsx Basic App component

5. Dockerfiles

api/Dockerfile

FROM python:3.12-slim
WORKDIR /app
RUN apt-get update && apt-get install -y libpq-dev gcc && rm -rf /var/lib/apt/lists/*
COPY pyproject.toml ./
RUN pip install uv && uv sync --frozen
COPY . .
EXPOSE 8000
CMD ["python", "manage.py", "runserver", "0.0.0.0:8000"]

web/Dockerfile

FROM node:20-alpine
WORKDIR /app
COPY package.json ./
RUN yarn install --frozen-lockfile
COPY . .
EXPOSE 3000
CMD ["yarn", "dev"]

Verification

Django (standalone)

cd api
uv sync
uv run python manage.py check
# → System check identified no issues (0 silenced).

Frontend (standalone)

cd web
yarn install
yarn dev
# → Vite dev server running on http://localhost:3000

Full stack (Docker)

docker compose up --build

Environment Variables Summary

Variable Default Used By
DATABASE_URL postgres://jobtracker:jobtracker@localhost:5432/jobtracker API
REACT_APP_API_URL http://localhost:8000 Web
DJANGO_SECRET_KEY django-insecure-change-me-in-production API
DJANGO_DEBUG True API