# Run the whole app locally — Balinyaar bring-up runbook The one copy-pasteable procedure for standing up **both** projects on one machine and watching a real, authenticated request cross the wire. Established by **Refinement Phase 0** ([refinement-phase-0-bring-up.md](refinement-phase-0-bring-up.md)). After this you have: the API on `https://localhost:5002` (against a local SQL Server), the web client on `http://localhost:3000`, and a working phone-OTP login backed by the real backend. **Auth is the only real domain** until [Refinement Phase 4](refinement-phase-4-frontend-de-mock.md) — everything else in the UI is still an in-browser mock. --- ## Prerequisites - **.NET 10 SDK** (`dotnet --version`) — preview is fine. - **Node.js 20+** and **npm** (`node --version`). - **Docker** (Desktop or engine) for the local database — or your own SQL Server on `localhost:1433`. --- ## One-time setup ### 1. Trust the ASP.NET Core HTTPS dev certificate Without this the browser (and `fetch`) rejects `https://localhost:5002` and every call fails with an opaque network error. ```bash dotnet dev-certs https --trust ``` Accept the OS prompt. (macOS/Windows trust the cert; on Linux see the .NET docs for the per-distro step.) ### 2. Start a local SQL Server From `server/`: ```bash cd server docker compose up -d ``` This runs SQL Server 2022 (Developer edition) on `localhost:1433` with a **dev-only** SA password (`Balinyaar_Dev1433`, defined in `server/docker-compose.yml` — not a secret, never used in production). Give it ~20–30s on first start (`docker compose ps` shows `healthy`). > Already have a SQL Server? Skip this and point the connection string in step 3 at it instead. ### 3. Point the API at the local database (via user-secrets — never a committed file) The committed `appsettings*.json` carry a **placeholder** connection string on purpose. Supply the real local one through `dotnet user-secrets` so no working credential ever lands in git. From the API project: ```bash cd server/src/API/Baya.Web.Api dotnet user-secrets set "ConnectionStrings:SqlServer" "Server=localhost,1433;Database=Baya;User Id=sa;Password=Balinyaar_Dev1433;TrustServerCertificate=True;Encrypt=False;" ``` The `Password` must match `MSSQL_SA_PASSWORD` in `docker-compose.yml`. User-secrets auto-load only in the Development environment, so this never affects a deployed build. > **Env-var alternative** (e.g. for CI/containers): set `ConnectionStrings__SqlServer` (double underscore = > the `:` config separator) instead of using user-secrets. > PowerShell: `$env:ConnectionStrings__SqlServer = "Server=localhost,1433;Database=Baya;User Id=sa;Password=Balinyaar_Dev1433;TrustServerCertificate=True;Encrypt=False;"` > bash: `export ConnectionStrings__SqlServer="Server=localhost,1433;Database=Baya;User Id=sa;Password=Balinyaar_Dev1433;TrustServerCertificate=True;Encrypt=False;"` --- ## Run it (two terminals) ### Terminal 1 — backend (from `server/`) ```bash dotnet run --project src/API/Baya.Web.Api/Baya.Web.Api.csproj ``` On boot the API applies all EF migrations and seeds roles + an admin user + a sandbox payment gateway against the (empty) local DB, then listens on **`https://localhost:5002`** — Swagger at `https://localhost:5002/swagger`. ### Terminal 2 — frontend (from `client/`) ```bash cd client npm install # first time only npm run dev ``` Serves **`http://localhost:3000`**. It reads the API base URL from `client/.env.development` (`NEXT_PUBLIC_API_URL = https://localhost:5002`). If you run the API on a different port/scheme, create `client/.env.local` with your `NEXT_PUBLIC_API_URL=…` (it overrides `.env.development`, is git-ignored). --- ## Log in (the real round-trip) 1. Open **`http://localhost:3000/fa/login`**. 2. Enter an Iranian mobile number (e.g. `09120000001`) and request the code. 3. Get the 6-digit OTP one of two ways: - **Read the server console** (Terminal 1) — SMS is mocked, so the code is logged: `MOCK SMS — OTP code 123456 for phone ending in 0001`. - **Or hit the Development-only helper** (handy for scripts/e2e): `GET https://localhost:5002/api/v1/dev/last_otp/09120000001` → `{ "data": { "phone": "09120000001", "code": "123456" }, ... }`. This endpoint returns **404 outside Development** and is superseded by real SMS in [Refinement Phase 8](refinement-phase-8-external-rails.md). 4. Enter the code and submit → you land on the customer home. 5. **Verify in DevTools → Network:** `POST /api/v1/auth/request_otp`, `POST /api/v1/auth/verify_otp`, and `GET /api/v1/me` all return **200** with the `ApiResult` envelope, and there is **no CORS error** in the console. That is the first real authenticated request between the two projects. --- ## Good to know - **The API speaks HTTP/2** (Kestrel `Protocols: Http2`, for gRPC). Browsers negotiate h2-over-TLS automatically, so `fetch` just works; for `curl` add `--http2`. - **Only `auth` is real by default.** 21 of 22 client service domains default to an in-browser mock (`USE_*_MOCK = true`); the home, search, bookings, etc. are fake in-memory data until Refinement Phase 4. - **The DB self-migrates + self-seeds**, so pointing at an empty local instance is enough. Rich demo data (nurses, variants, search rows) arrives in [Refinement Phase 1](refinement-phase-1-database-and-seed.md). - **Allowed browser origins** are configuration-driven (`Cors:AllowedOrigins`), defaulting to `http://localhost:3000` in Development. A deployed environment lists its real web origin(s). ## Stopping / resetting ```bash docker compose down # stop the DB, keep its data docker compose down -v # stop the DB and wipe the volume (fresh migrate + seed next run) ``` ## Troubleshooting | Symptom | Fix | | --- | --- | | Browser: `net::ERR_CERT_AUTHORITY_INVALID` on `:5002` | Run `dotnet dev-certs https --trust` (setup step 1). | | API startup: `Login failed for user 'sa'` / connect timeout | DB not up or wrong password — check `docker compose ps` and that the user-secrets password matches `docker-compose.yml`. | | Console: `...has been blocked by CORS policy` | `UseCors` missing/mis-ordered, or the browser origin isn't in `Cors:AllowedOrigins`. It must sit after `UseRouting` and before the rate limiter. | | `dotnet user-secrets` errors with "could not find UserSecretsId" | Run it from `server/src/API/Baya.Web.Api` (the project with ``). |