6.3 KiB
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).
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 — 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.
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/:
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:
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/)
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/)
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)
- Open
http://localhost:3000/fa/login. - Enter an Iranian mobile number (e.g.
09120000001) and request the code. - 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.
- Read the server console (Terminal 1) — SMS is mocked, so the code is logged:
- Enter the code and submit → you land on the customer home.
- Verify in DevTools → Network:
POST /api/v1/auth/request_otp,POST /api/v1/auth/verify_otp, andGET /api/v1/meall return 200 with theApiResultenvelope, 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, sofetchjust works; forcurladd--http2. - Only
authis 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.
- Allowed browser origins are configuration-driven (
Cors:AllowedOrigins), defaulting tohttp://localhost:3000in Development. A deployed environment lists its real web origin(s).
Stopping / resetting
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 <UserSecretsId>). |