diff --git a/docs/LIVE_SERVER_RUNBOOK.md b/docs/LIVE_SERVER_RUNBOOK.md new file mode 100644 index 0000000..0a0cc7b --- /dev/null +++ b/docs/LIVE_SERVER_RUNBOOK.md @@ -0,0 +1,229 @@ +# Nxtgauge — Live Server Runbook + +Steps that **require a running database and/or server** to complete. +Run these on the server where Postgres + Redis are already up. + +--- + +## 1. Deploy the backend changes + +```bash +cd nxtgauge-backend-rust +cargo build --release +``` + +Then restart the affected services: + +```bash +# Restart all profession services (they all got the wallet/me/holds route) +systemctl restart nxtgauge-photographers nxtgauge-developers nxtgauge-tutors \ + nxtgauge-makeup_artists nxtgauge-fitness_trainers nxtgauge-catering_services \ + nxtgauge-video_editors nxtgauge-graphic_designers nxtgauge-social_media_managers + +# Restart job_seekers (got the printpdf upgrade) +systemctl restart nxtgauge-job_seekers +``` + +--- + +## 2. Verify the new wallet/me/holds endpoint + +Pick any professional user's JWT and run: + +```bash +TOKEN="" +PREFIX="photographer" # or developer, tutor, etc. + +# Should return { "data": [...], "pagination": {...} } +curl -s -H "Authorization: Bearer $TOKEN" \ + https://api.nxtgauge.com/api/${PREFIX}/wallet/me/holds | jq . + +# To test the release endpoint, grab a hold ID from above, then: +HOLD_ID="" +curl -s -X POST -H "Authorization: Bearer $TOKEN" \ + https://api.nxtgauge.com/api/${PREFIX}/wallet/me/holds/${HOLD_ID}/release | jq . +``` + +Expected responses: +- `GET /holds` → `200 { "data": [], "pagination": { "page": 1, "limit": 50 } }` +- `POST /holds/{id}/release` → `200 { "message": "Hold released..." }` or `409` if not ACTIVE + +--- + +## 3. Run security checks (no DB needed, but run on the server build) + +```bash +cd nxtgauge-backend-rust + +# CVE scan +cargo audit + +# Policy check (licenses, bans, CVE with acknowledged ignores) +cargo deny check advisories bans +``` + +Both should exit 0. If a new CVE appears, add it to `deny.toml` under `[advisories] ignore` with a comment explaining the risk. + +--- + +## 4. Set up schemathesis API fuzzing + +Schemathesis fuzzes your real API from an OpenAPI spec. It needs: +- The server running (with DB connected) +- An OpenAPI spec (`openapi.json`) + +### 4a. Install schemathesis + +```bash +pip install schemathesis +``` + +Or with `uv`: + +```bash +uv tool install schemathesis +``` + +### 4b. Generate the OpenAPI spec + +> **Note:** The axum services don't yet have utoipa annotations (OpenAPI generation +> is the next backend dev task). Until then, you can use a manually maintained spec +> or skip to step 4c. +> +> To add utoipa: add `utoipa` and `utoipa-axum` to each service's `Cargo.toml`, +> annotate handlers with `#[utoipa::path]`, and mount a `/openapi.json` endpoint. +> See https://github.com/juhaku/utoipa for examples. + +Once you have `openapi.json`: + +### 4c. Run the fuzzer + +```bash +# Run against the gateway (port 3000 by default) +# Schemathesis will generate and send hundreds of property-based requests. + +schemathesis run openapi.json \ + --base-url http://localhost:3000 \ + --auth "Bearer " \ + --checks all \ + --hypothesis-settings max_examples=200 + +# For a quick smoke-check (fewer examples): +schemathesis run openapi.json \ + --base-url http://localhost:3000 \ + --auth "Bearer " \ + --checks not_a_server_error +``` + +Schemathesis will report any 5xx responses, schema violations, or auth bypasses. + +--- + +## 5. Run Playwright end-to-end tests + +Playwright tests live in `nxtgauge-frontend-solid/tests/`. They need the full stack +running (gateway → services → Postgres → frontend). + +### 5a. Install browsers (one-time) + +```bash +cd nxtgauge-frontend-solid +npx playwright install --with-deps chromium +``` + +### 5b. Set the base URL + +```bash +export PLAYWRIGHT_BASE_URL=https://your-staging-domain.com +# or for local: +export PLAYWRIGHT_BASE_URL=http://localhost:3001 +``` + +### 5c. Run the tests + +```bash +# Run all e2e tests headlessly +npx playwright test + +# Run only the smoke tests +npx playwright test --grep @smoke + +# Watch a test run visually (useful for debugging) +npx playwright test --headed + +# See the HTML report after a run +npx playwright show-report +``` + +--- + +## 6. Wire backend integration tests to CI + +The 7 ai_credits integration tests in +`crates/db/tests/ai_credits.rs` need a real Postgres connection. + +### 6a. On the CI server / GitHub Actions + +Add a `TEST_DATABASE_URL` secret in your GitHub repo settings, then +add this to `.github/workflows/ci.yml`: + +```yaml +- name: Run backend integration tests + env: + TEST_DATABASE_URL: ${{ secrets.TEST_DATABASE_URL }} + run: | + cd nxtgauge-backend-rust + cargo test --test ai_credits -- --test-threads=1 +``` + +The `--test-threads=1` keeps the DB state predictable between tests. + +### 6b. Locally + +```bash +export TEST_DATABASE_URL=postgres://user:pass@localhost:5432/nxtgauge_test +cd nxtgauge-backend-rust +cargo test --test ai_credits -- --test-threads=1 +``` + +--- + +## 7. Run the frontend linter (catches SolidJS reactivity bugs) + +```bash +cd nxtgauge-frontend-solid +npm run lint +``` + +This runs `eslint-plugin-solid` which catches: +- Signals called outside reactive context (`solid/reactivity`) +- `.map()` in JSX instead of `` (`solid/prefer-for`) +- React-specific patterns used in Solid (`solid/no-react-specific-props`) + +All errors should be fixed before deploying. Warnings can be tracked. + +--- + +## 8. TypeScript check (zero errors currently) + +```bash +cd nxtgauge-frontend-solid +npx tsc --noEmit --skipLibCheck +``` + +Should exit 0. Fix any errors before pushing to production. + +--- + +## Summary — what's needed where + +| Task | Needs DB | Needs server | Where to run | +|---|---|---|---| +| Build + deploy backend | — | — | Server | +| Verify `/wallet/me/holds` | ✅ | ✅ | Server | +| `cargo audit` / `cargo deny` | — | — | Anywhere | +| Schemathesis fuzzing | ✅ | ✅ | Server / staging | +| Playwright e2e | ✅ | ✅ | Server / staging | +| Backend integration tests | ✅ | — | Server / CI | +| `npm run lint` | — | — | Anywhere | +| `tsc --noEmit` | — | — | Anywhere |