--- type: guide title: Local Development Workflow description: How to run the backend and frontend together in development, including the root dev script, Angular dev-server proxy, and project-local data directory. tags: [guide, dev, dev-server, proxy, concurrently, setup, tester] timestamp: 2026-07-22T19:54:00Z --- # Overview The HIPCTF monorepo ships a single root command — `npm run dev` — that boots the NestJS backend and the Angular dev server in parallel, with the Angular dev server proxying `/api` and `/uploads` calls to the backend on port 3000. All persistent runtime files (SQLite database, uploaded icons / attachments / logos) live under the project-local `./data/` directory. # How to start the full stack (tester steps) 1. From the repository root, install workspace dependencies once: ``` npm ci ``` 2. Start both servers in parallel: ``` npm run dev ``` This uses `concurrently` to run: * `npm --workspace backend run start:dev` (NestJS watch mode on `http://localhost:3000`) * `npm --workspace frontend run start` (Angular dev server on `http://localhost:4200`) Process names `backend` and `frontend` are prefixed per output line. If either process exits with a non-zero status, the other is killed (`--kill-others-on-fail`). 3. Open the browser: * **Frontend (preferred for app work):** `http://localhost:4200/` * **Backend (single-port mode, serves built SPA later):** `http://localhost:3000/` 4. To run them individually during debugging: ``` npm run dev:backend npm run dev:frontend ``` # Project-local data directory | Path | Purpose | Backed by env var | |-------------------|-------------------------------------------------------|---------------------| | `./data/` | Root runtime data directory (gitignored). | — | | `./data/db.sqlite`| SQLite database file (created on first boot). | `DATABASE_PATH` | | `./data/uploads/` | Uploaded category icons, challenge files, site logos. | `UPLOAD_DIR` | Both defaults are declared in `backend/src/config/env.schema.ts` and re-declared as fallbacks in every backend code path that calls `ConfigService.get` so direct/unit construction cannot silently revert to the legacy absolute paths. Relative paths are resolved with `path.resolve` against the process working directory — when launched via the root scripts, that is the repository root. The legacy absolute defaults (`/data/hipctf/db.sqlite`, `/data/hipctf/uploads`) have been removed; set `DATABASE_PATH` and `UPLOAD_DIR` explicitly if you need to point at an external location (e.g. a mounted volume in production). The data directory is created automatically: * `DatabaseModule` ensures the parent directory of `DATABASE_PATH` exists before connecting. * `main.ts`, `UploadsController`, `buildMulter`, and `UploadsStaticMiddleware` all `mkdir -p` the upload directory on startup. * `setup.sh` creates `./data/uploads` before any build so first-boot Multer writes never fail. # Angular dev-server proxy `frontend/proxy.conf.json` is wired into the `serve` target in `frontend/angular.json` so relative URLs from the SPA hit the backend without CORS prompts: | Origin path | Target | Notes | |-------------|-------------------------|--------------------------------------------------------| | `/api` | `http://localhost:3000` | All REST controllers + SSE endpoints. `changeOrigin: true`. | | `/uploads` | `http://localhost:3000` | Static files served by `UploadsStaticMiddleware`. | The proxy is **development-only.** In production (`npm start` / `backend/dist/main.js`) the backend serves the built SPA directly and no proxy is involved. # Root scripts | Script | What it does | |---------------------|--------------------------------------------------------------------| | `npm run dev` | Start backend + frontend together via `concurrently`. | | `npm run dev:backend` | Start only the NestJS backend in watch mode. | | `npm run dev:frontend` | Start only the Angular dev server. | | `npm start` | Run the **production** backend (`node backend/dist/main.js`). | | `npm run build` | Build both workspaces (frontend first, then backend). | | `npm run start:dev` | Alias for `npm run dev` (kept for backwards compatibility). | | `npm test` | Run the full Jest project (backend + frontend). | # Expected behavior (tester) * `npm run dev` displays interleaved backend and frontend logs, each prefixed with the process name and a color. * The Angular dev server prints `Application bundle generation complete` within a few seconds and the page is reachable at `http://localhost:4200/`. * Visiting `http://localhost:4200/` triggers `GET /api/v1/bootstrap` (proxied to port 3000) and shows the appropriate public, login, or bootstrap page. * Uploads (e.g. category icons via the admin UI) land under `./data/uploads/` and are immediately readable from the dev frontend via `/uploads/...` (proxied). * Pressing `Ctrl+C` once terminates both processes cleanly. # See also - [System Overview](/architecture/overview.md) - [Database Schema Overview](/database/schema.md) - [Uploads Endpoints](/api/uploads.md) - [Key Files Index](/architecture/key-files.md)