|
| 1 | +# Getting Started |
| 2 | + |
| 3 | +Run the full CCE platform on your laptop in ~10 minutes — infra (SQL, Redis, Meilisearch, MailDev, ClamAV) + two .NET 8 APIs + two Angular 19 apps. |
| 4 | + |
| 5 | +> **TL;DR:** clone → `cp .env.example .env && cp .env.local.example .env.local` → `docker compose up -d` → `dotnet run --project backend/src/CCE.Seeder -- --migrate --demo` → start the 4 apps below → open **http://localhost:4200** (public portal) and **http://localhost:4201** (admin console). |
| 6 | +
|
| 7 | +--- |
| 8 | + |
| 9 | +## What you'll be running |
| 10 | + |
| 11 | +| # | Component | Stack | URL | Port | |
| 12 | +|---|---|---|---|---| |
| 13 | +| 1 | SQL Server 2022 | Azure SQL Edge (arm64) / SQL Server (x64) | `localhost,1433` | 1433 | |
| 14 | +| 2 | Redis 7 | distributed cache + rate limiter | `localhost:6379` | 6379 | |
| 15 | +| 3 | Meilisearch | full-text search | `http://localhost:7700` | 7700 | |
| 16 | +| 4 | MailDev | local SMTP inbox | `http://localhost:1080` | 1080 / 1025 | |
| 17 | +| 5 | ClamAV | antivirus daemon for uploads | `localhost:3310` | 3310 | |
| 18 | +| 6 | **External API** | .NET 8 minimal-API (BFF for public portal) | `http://localhost:5001` | 5001 | |
| 19 | +| 7 | **Internal API** | .NET 8 minimal-API (admin) | `http://localhost:5002` | 5002 | |
| 20 | +| 8 | **Web portal** | Angular 19 (public) | `http://localhost:4200` | 4200 | |
| 21 | +| 9 | **Admin CMS** | Angular 19 (back-office) | `http://localhost:4201` | 4201 | |
| 22 | + |
| 23 | +Services 1–5 run in Docker. Services 6–9 run on the host so hot-reload works. |
| 24 | + |
| 25 | +--- |
| 26 | + |
| 27 | +## Prerequisites |
| 28 | + |
| 29 | +- **Docker** v26+ (OrbStack, Docker Desktop, or Colima) with **Docker Compose v2** |
| 30 | +- **.NET 8 SDK** (`dotnet --version` ≥ 8.0) |
| 31 | +- **Node.js** 20+ (`node -v` ≥ 20) |
| 32 | +- **pnpm** 9+ (`npm install -g pnpm` or `corepack enable`) |
| 33 | +- **`curl`** + **`nc`** for healthchecks (pre-installed on macOS/Linux) |
| 34 | + |
| 35 | +> **Apple Silicon note:** Docker uses Azure SQL Edge instead of SQL Server 2022 on arm64 — handled automatically, see [ADR-0016](adr/0016-azure-sql-edge-for-arm64-dev.md). |
| 36 | +
|
| 37 | +--- |
| 38 | + |
| 39 | +## One-time setup |
| 40 | + |
| 41 | +```bash |
| 42 | +# 1. Clone |
| 43 | +git clone https://github.com/Azm-Tech/cce-platform.git |
| 44 | +cd cce-platform |
| 45 | + |
| 46 | +# 2. Bootstrap env files |
| 47 | +cp .env.example .env |
| 48 | +cp .env.local.example .env.local |
| 49 | + |
| 50 | +# 3. Install frontend deps (≈90 s) |
| 51 | +pnpm install --frozen-lockfile |
| 52 | + |
| 53 | +# 4. Restore backend NuGet packages |
| 54 | +dotnet restore backend/CCE.sln |
| 55 | +``` |
| 56 | + |
| 57 | +The `.env.local` ships with **safe dev defaults** — `Strong!Passw0rd` for SQL, dev placeholders for Entra ID, etc. Real secrets (production Entra ID client secret, Sentry DSN) are never committed. |
| 58 | + |
| 59 | +--- |
| 60 | + |
| 61 | +## Running the stack |
| 62 | + |
| 63 | +You'll need **four terminals** open (or use a multiplexer like tmux / iTerm panes). |
| 64 | + |
| 65 | +### Terminal 1 — infra |
| 66 | + |
| 67 | +```bash |
| 68 | +docker compose up -d |
| 69 | +docker compose ps # wait until all are "(healthy)" — ~90 seconds |
| 70 | +``` |
| 71 | + |
| 72 | +If a service shows `unhealthy`, run `docker compose logs <service>` to see why. |
| 73 | + |
| 74 | +### Terminal 2 — migrations + seed (one-shot) |
| 75 | + |
| 76 | +```bash |
| 77 | +dotnet run --project backend/src/CCE.Seeder -- --migrate --demo |
| 78 | +``` |
| 79 | + |
| 80 | +This: |
| 81 | + |
| 82 | +1. Applies all EF Core migrations (creates schemas + tables). |
| 83 | +2. Seeds roles + permissions. |
| 84 | +3. Seeds 5 dev users (one per role: admin / editor / reviewer / expert / user) with deterministic GUIDs. |
| 85 | +4. Seeds demo data — topics, posts, replies, knowledge maps, news, events, country profiles, resources. |
| 86 | + |
| 87 | +You only need to re-run this if you reset the database or pull new migrations. Use `--migrate` (no `--demo`) to skip demo data. |
| 88 | + |
| 89 | +### Terminal 3 — External API (public BFF, port 5001) |
| 90 | + |
| 91 | +```bash |
| 92 | +cd backend/src/CCE.Api.External |
| 93 | +ASPNETCORE_ENVIRONMENT=Development dotnet run --urls=http://localhost:5001 |
| 94 | +``` |
| 95 | + |
| 96 | +This is the **public-facing API** consumed by the web portal. Implements BFF cookie auth + public-only endpoints. |
| 97 | + |
| 98 | +### Terminal 4 — Internal API (admin, port 5002) |
| 99 | + |
| 100 | +```bash |
| 101 | +cd backend/src/CCE.Api.Internal |
| 102 | +ASPNETCORE_ENVIRONMENT=Development dotnet run --urls=http://localhost:5002 |
| 103 | +``` |
| 104 | + |
| 105 | +This is the **admin API** consumed by admin-cms. Exposes moderation + CMS endpoints with permission checks. |
| 106 | + |
| 107 | +### Terminal 5 (or 3 again) — Frontend apps |
| 108 | + |
| 109 | +```bash |
| 110 | +# from the repo root |
| 111 | +pnpm nx serve web-portal --port 4200 # public site |
| 112 | +pnpm nx serve admin-cms --port 4201 # admin console |
| 113 | +``` |
| 114 | + |
| 115 | +You can run both at once with: |
| 116 | + |
| 117 | +```bash |
| 118 | +pnpm nx run-many -t serve -p web-portal,admin-cms |
| 119 | +``` |
| 120 | + |
| 121 | +Each app proxies `/api/*` requests to its respective backend (web-portal → 5001, admin-cms → 5002), so cookies stay first-party. |
| 122 | + |
| 123 | +--- |
| 124 | + |
| 125 | +## Accessing the apps |
| 126 | + |
| 127 | +### Public portal — http://localhost:4200 |
| 128 | + |
| 129 | +Browse the homepage, knowledge center, community, world map, interactive city, country profiles, news, events. No login needed for read access. |
| 130 | + |
| 131 | +To **sign in as a regular user** during dev: |
| 132 | + |
| 133 | +``` |
| 134 | +http://localhost:5001/dev/sign-in?role=cce-user |
| 135 | +``` |
| 136 | + |
| 137 | +This sets a `cce-dev-role=cce-user` cookie that the dev auth shim (active when `Auth:DevMode=true`) recognizes as the seeded user `cce-user@cce.local`. Reload the portal — you're signed in. |
| 138 | + |
| 139 | +### Admin console — http://localhost:4201 |
| 140 | + |
| 141 | +Same dev auth flow against the **internal** API: |
| 142 | + |
| 143 | +``` |
| 144 | +http://localhost:5002/dev/sign-in?role=cce-admin |
| 145 | +``` |
| 146 | + |
| 147 | +Then open http://localhost:4201 — you'll see all admin features: users, content, community moderation, knowledge maps, etc. |
| 148 | + |
| 149 | +Available dev roles: |
| 150 | + |
| 151 | +| Role | Capability | |
| 152 | +|---|---| |
| 153 | +| `cce-admin` | Full admin — all permissions | |
| 154 | +| `cce-editor` | Author + edit content | |
| 155 | +| `cce-reviewer` | Review-only | |
| 156 | +| `cce-expert` | Community expert (gold badge on replies) | |
| 157 | +| `cce-user` | Regular member | |
| 158 | + |
| 159 | +### Calling APIs directly (curl / Postman) |
| 160 | + |
| 161 | +Skip the cookie dance and pass the role in the `Authorization` header: |
| 162 | + |
| 163 | +```bash |
| 164 | +curl -H 'Authorization: Bearer dev:cce-admin' \ |
| 165 | + 'http://localhost:5002/api/admin/community/posts?status=all' |
| 166 | +``` |
| 167 | + |
| 168 | +> The dev auth shim is **only registered when `Auth:DevMode=true`** in `appsettings.Development.json`. Production deployments use real Entra ID and never expose this path — see [Sub-11 Entra ID migration](../project-plan/specs/2026-05-04-sub-11-design.md). |
| 169 | +
|
| 170 | +--- |
| 171 | + |
| 172 | +## Tests |
| 173 | + |
| 174 | +```bash |
| 175 | +# Backend (≈30 s) |
| 176 | +dotnet test backend/CCE.sln |
| 177 | + |
| 178 | +# Frontend unit tests (≈30 s) |
| 179 | +pnpm nx run-many -t test |
| 180 | + |
| 181 | +# Frontend lint (≈10 s) |
| 182 | +pnpm nx run-many -t lint |
| 183 | + |
| 184 | +# E2E with Playwright + axe-core (≈3 min — needs the stack running) |
| 185 | +pnpm nx run-many -t e2e |
| 186 | + |
| 187 | +# Contract drift check (OpenAPI ↔ generated TS clients) |
| 188 | +./scripts/check-contracts-clean.sh |
| 189 | +``` |
| 190 | + |
| 191 | +--- |
| 192 | + |
| 193 | +## Common issues |
| 194 | + |
| 195 | +### Port already in use |
| 196 | + |
| 197 | +``` |
| 198 | +Error: listen EADDRINUSE: address already in use :::4200 |
| 199 | +``` |
| 200 | + |
| 201 | +Find and kill the process: |
| 202 | + |
| 203 | +```bash |
| 204 | +lsof -nP -iTCP:4200 -sTCP:LISTEN |
| 205 | +kill -9 <pid> |
| 206 | +``` |
| 207 | + |
| 208 | +### Stale Vite optimized-deps (web-portal blank, "Failed to fetch dynamically imported module") |
| 209 | + |
| 210 | +Vite's dependency cache went out of sync with the running server. Clear it and restart: |
| 211 | + |
| 212 | +```bash |
| 213 | +rm -rf frontend/.angular frontend/node_modules/.vite |
| 214 | +# then restart `pnpm nx serve web-portal` and hard-reload your browser (⌘⇧R) |
| 215 | +``` |
| 216 | + |
| 217 | +### Backend crash: `Infrastructure:SqlConnectionString missing` |
| 218 | + |
| 219 | +You launched `dotnet run` without `ASPNETCORE_ENVIRONMENT=Development`. Either prefix the env var (as shown above) or remove `--no-launch-profile` if you added it. |
| 220 | + |
| 221 | +### SQL connection refused |
| 222 | + |
| 223 | +```bash |
| 224 | +docker compose ps sqlserver # is it healthy? |
| 225 | +docker compose logs sqlserver # what's it complaining about? |
| 226 | +``` |
| 227 | + |
| 228 | +On low-memory machines (< 4 GB free), SQL Server / Azure SQL Edge can fail to start. Bump Docker's memory allocation. |
| 229 | + |
| 230 | +### Migrations failed |
| 231 | + |
| 232 | +Most often `Login failed for user 'sa'` — the SQL password in `.env.local` doesn't match the seeded SA password. Tear down with `docker compose down -v` (destroys data) and start fresh. |
| 233 | + |
| 234 | +--- |
| 235 | + |
| 236 | +## Tearing down |
| 237 | + |
| 238 | +```bash |
| 239 | +# Stop services, keep data volumes |
| 240 | +docker compose down |
| 241 | + |
| 242 | +# Stop services AND destroy all SQL/Redis/Meilisearch data |
| 243 | +docker compose down -v |
| 244 | +``` |
| 245 | + |
| 246 | +--- |
| 247 | + |
| 248 | +## Next steps |
| 249 | + |
| 250 | +- **[`project-plan/README.md`](../project-plan/README.md)** — sub-project index (specs, plans, completion reports) |
| 251 | +- **[`docs/adr/`](adr/)** — 60+ architecture decisions explaining why things are built this way |
| 252 | +- **[`docs/runbooks/`](runbooks/)** — production operational procedures (DR, backup/restore, secret rotation) |
| 253 | +- **[`docs/subprojects/`](subprojects/)** — one-page brief per sub-project |
| 254 | +- **[`CONTRIBUTING.md`](../CONTRIBUTING.md)** — branch model, commit format, PR checklist |
0 commit comments