2026-08-12 13:39:36 +02:00
# 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.
---
2026-08-13 21:32:48 +02:00
## ✅ Completed — Database migrations (applied to prod, 2026-08-13)
All four DB tasks below are done and confirmed against the live production DB.
| Migration | What | Status |
|---|---|---|
| `20260627030000_wallet_full.up.sql` | Re-enabled (was mistakenly `.skip` -ed); `tracecoin_holds` + `tracecoin_buckets` now live | ✅ Applied |
| `20260703210000_ai_credits_wallet.up.sql` | Rewrote as idempotent (`IF NOT EXISTS` ); `ai_reservation_holds` + `ai_credit_ledger` now live | ✅ Applied |
| `20260813000000_fix_ai_credits_timestamp_types.up.sql` | 9 TIMESTAMP → TIMESTAMPTZ columns across AI tables; data intact and UTC-correct | ✅ Applied |
| `nxtgauge_test` DB | Dedicated test database created, schema mirrored from prod, wired into Forgejo CI via `TEST_DATABASE_URL` secret | ✅ Done |
`/wallet/me/holds` returns real data. All 8 backend integration tests pass in CI.
---
fix(db): 4 fresh-bootstrap migration chain bugs found + verified today
Reconciling the local dev DB (63 migrations behind) surfaced 4 genuine
bugs in the migration chain itself -- not just this DB's legacy
scripts/init-db.sql seeding -- confirmed by replaying the full chain
against a brand new, completely empty database from scratch:
- 20260318235959: customer_profiles.status is UPDATEd by
20260319090000's backfill 4 months before it's ever ADDed
(20260721020000). Adds it early (IF NOT EXISTS).
- 20260401235959: 20260317190000 creates the old users-linked
`employees` shape; 20260402030000's CREATE TABLE IF NOT EXISTS no-ops
against it and fails creating an index on a column that was never
added. Conditionally drops the old shape first (only if it's still
pre-transition -- gated on the missing `email` column), restoring
20260402030000's own documented original intent.
- 20260419235959: the schema `20260420000003_external_role_modules`
needs (persona_types, modules, role_module_access, ...) was only ever
defined in a disabled .up.sql.skip (its version slot was taken by
...seed.sql); the seed data that depends on it was never skipped.
Creates that schema early -- verbatim content, purely additive.
- 20260421235959: same disabled-migration pattern for the
role_permissions -> role_admin_permissions / dashboard_configs ->
role_sidebar_configs / runtime_configs -> role_runtime_configs /
user_roles -> user_role_assignments renames that 20260422000000's
widget seed needs. Conditionally renames each pair (only if old name
exists and new name doesn't), verified against live Rust code that
already queries the new names exclusively.
payments/invoices were NOT chain bugs -- confirmed clean on the fresh
bootstrap test -- so no fix needed for those; they only conflicted on
this one DB because of its scripts/init-db.sql legacy seed, which is
already a documented, known gap.
Verified twice: applied cleanly as no-ops against the now-fully-migrated
local dev DB, and applied successfully end-to-end (0 manual steps)
against a brand new empty database created from scratch.
Runbook updated with the full pending-migration list and today's
findings.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-14 18:30:42 +05:30
## ⏳ Pending — DB migrations for AI credit purchases + coupons + fresh-bootstrap fixes (2026-08-14)
2026-08-13 23:10:40 +02:00
fix(db): 4 fresh-bootstrap migration chain bugs found + verified today
Reconciling the local dev DB (63 migrations behind) surfaced 4 genuine
bugs in the migration chain itself -- not just this DB's legacy
scripts/init-db.sql seeding -- confirmed by replaying the full chain
against a brand new, completely empty database from scratch:
- 20260318235959: customer_profiles.status is UPDATEd by
20260319090000's backfill 4 months before it's ever ADDed
(20260721020000). Adds it early (IF NOT EXISTS).
- 20260401235959: 20260317190000 creates the old users-linked
`employees` shape; 20260402030000's CREATE TABLE IF NOT EXISTS no-ops
against it and fails creating an index on a column that was never
added. Conditionally drops the old shape first (only if it's still
pre-transition -- gated on the missing `email` column), restoring
20260402030000's own documented original intent.
- 20260419235959: the schema `20260420000003_external_role_modules`
needs (persona_types, modules, role_module_access, ...) was only ever
defined in a disabled .up.sql.skip (its version slot was taken by
...seed.sql); the seed data that depends on it was never skipped.
Creates that schema early -- verbatim content, purely additive.
- 20260421235959: same disabled-migration pattern for the
role_permissions -> role_admin_permissions / dashboard_configs ->
role_sidebar_configs / runtime_configs -> role_runtime_configs /
user_roles -> user_role_assignments renames that 20260422000000's
widget seed needs. Conditionally renames each pair (only if old name
exists and new name doesn't), verified against live Rust code that
already queries the new names exclusively.
payments/invoices were NOT chain bugs -- confirmed clean on the fresh
bootstrap test -- so no fix needed for those; they only conflicted on
this one DB because of its scripts/init-db.sql legacy seed, which is
already a documented, known gap.
Verified twice: applied cleanly as no-ops against the now-fully-migrated
local dev DB, and applied successfully end-to-end (0 manual steps)
against a brand new empty database created from scratch.
Runbook updated with the full pending-migration list and today's
findings.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-14 18:30:42 +05:30
Eight new migrations need to be applied to prod. Run **in order** (sqlx-migrate handles this, but listed explicitly so you can verify):
2026-08-13 23:10:40 +02:00
```bash
# On the live server, inside nxtgauge-backend-rust:
git pull origin high-performance
sqlx migrate run --database-url "$DATABASE_URL"
```
fix(db): 4 fresh-bootstrap migration chain bugs found + verified today
Reconciling the local dev DB (63 migrations behind) surfaced 4 genuine
bugs in the migration chain itself -- not just this DB's legacy
scripts/init-db.sql seeding -- confirmed by replaying the full chain
against a brand new, completely empty database from scratch:
- 20260318235959: customer_profiles.status is UPDATEd by
20260319090000's backfill 4 months before it's ever ADDed
(20260721020000). Adds it early (IF NOT EXISTS).
- 20260401235959: 20260317190000 creates the old users-linked
`employees` shape; 20260402030000's CREATE TABLE IF NOT EXISTS no-ops
against it and fails creating an index on a column that was never
added. Conditionally drops the old shape first (only if it's still
pre-transition -- gated on the missing `email` column), restoring
20260402030000's own documented original intent.
- 20260419235959: the schema `20260420000003_external_role_modules`
needs (persona_types, modules, role_module_access, ...) was only ever
defined in a disabled .up.sql.skip (its version slot was taken by
...seed.sql); the seed data that depends on it was never skipped.
Creates that schema early -- verbatim content, purely additive.
- 20260421235959: same disabled-migration pattern for the
role_permissions -> role_admin_permissions / dashboard_configs ->
role_sidebar_configs / runtime_configs -> role_runtime_configs /
user_roles -> user_role_assignments renames that 20260422000000's
widget seed needs. Conditionally renames each pair (only if old name
exists and new name doesn't), verified against live Rust code that
already queries the new names exclusively.
payments/invoices were NOT chain bugs -- confirmed clean on the fresh
bootstrap test -- so no fix needed for those; they only conflicted on
this one DB because of its scripts/init-db.sql legacy seed, which is
already a documented, known gap.
Verified twice: applied cleanly as no-ops against the now-fully-migrated
local dev DB, and applied successfully end-to-end (0 manual steps)
against a brand new empty database created from scratch.
Runbook updated with the full pending-migration list and today's
findings.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-14 18:30:42 +05:30
That single command applies all eight in chronological order. Verify after:
2026-08-13 23:10:40 +02:00
```bash
sqlx migrate info --database-url "$DATABASE_URL"
```
fix(db): 4 fresh-bootstrap migration chain bugs found + verified today
Reconciling the local dev DB (63 migrations behind) surfaced 4 genuine
bugs in the migration chain itself -- not just this DB's legacy
scripts/init-db.sql seeding -- confirmed by replaying the full chain
against a brand new, completely empty database from scratch:
- 20260318235959: customer_profiles.status is UPDATEd by
20260319090000's backfill 4 months before it's ever ADDed
(20260721020000). Adds it early (IF NOT EXISTS).
- 20260401235959: 20260317190000 creates the old users-linked
`employees` shape; 20260402030000's CREATE TABLE IF NOT EXISTS no-ops
against it and fails creating an index on a column that was never
added. Conditionally drops the old shape first (only if it's still
pre-transition -- gated on the missing `email` column), restoring
20260402030000's own documented original intent.
- 20260419235959: the schema `20260420000003_external_role_modules`
needs (persona_types, modules, role_module_access, ...) was only ever
defined in a disabled .up.sql.skip (its version slot was taken by
...seed.sql); the seed data that depends on it was never skipped.
Creates that schema early -- verbatim content, purely additive.
- 20260421235959: same disabled-migration pattern for the
role_permissions -> role_admin_permissions / dashboard_configs ->
role_sidebar_configs / runtime_configs -> role_runtime_configs /
user_roles -> user_role_assignments renames that 20260422000000's
widget seed needs. Conditionally renames each pair (only if old name
exists and new name doesn't), verified against live Rust code that
already queries the new names exclusively.
payments/invoices were NOT chain bugs -- confirmed clean on the fresh
bootstrap test -- so no fix needed for those; they only conflicted on
this one DB because of its scripts/init-db.sql legacy seed, which is
already a documented, known gap.
Verified twice: applied cleanly as no-ops against the now-fully-migrated
local dev DB, and applied successfully end-to-end (0 manual steps)
against a brand new empty database created from scratch.
Runbook updated with the full pending-migration list and today's
findings.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-14 18:30:42 +05:30
All eight should show `applied` . On prod specifically, the four "early" fixes
below should all apply as **no-ops** — prod already has the target schema
(that's how their gating conditions were derived and verified). If any of
them actually *does* something on prod (i.e. its `Applied` log line isn't
near-instant), stop and check `\d <table>` before continuing — it means
prod's schema differs from what this runbook assumed.
2026-08-13 23:10:40 +02:00
| Migration | What | Why |
|---|---|---|
fix(db): 4 fresh-bootstrap migration chain bugs found + verified today
Reconciling the local dev DB (63 migrations behind) surfaced 4 genuine
bugs in the migration chain itself -- not just this DB's legacy
scripts/init-db.sql seeding -- confirmed by replaying the full chain
against a brand new, completely empty database from scratch:
- 20260318235959: customer_profiles.status is UPDATEd by
20260319090000's backfill 4 months before it's ever ADDed
(20260721020000). Adds it early (IF NOT EXISTS).
- 20260401235959: 20260317190000 creates the old users-linked
`employees` shape; 20260402030000's CREATE TABLE IF NOT EXISTS no-ops
against it and fails creating an index on a column that was never
added. Conditionally drops the old shape first (only if it's still
pre-transition -- gated on the missing `email` column), restoring
20260402030000's own documented original intent.
- 20260419235959: the schema `20260420000003_external_role_modules`
needs (persona_types, modules, role_module_access, ...) was only ever
defined in a disabled .up.sql.skip (its version slot was taken by
...seed.sql); the seed data that depends on it was never skipped.
Creates that schema early -- verbatim content, purely additive.
- 20260421235959: same disabled-migration pattern for the
role_permissions -> role_admin_permissions / dashboard_configs ->
role_sidebar_configs / runtime_configs -> role_runtime_configs /
user_roles -> user_role_assignments renames that 20260422000000's
widget seed needs. Conditionally renames each pair (only if old name
exists and new name doesn't), verified against live Rust code that
already queries the new names exclusively.
payments/invoices were NOT chain bugs -- confirmed clean on the fresh
bootstrap test -- so no fix needed for those; they only conflicted on
this one DB because of its scripts/init-db.sql legacy seed, which is
already a documented, known gap.
Verified twice: applied cleanly as no-ops against the now-fully-migrated
local dev DB, and applied successfully end-to-end (0 manual steps)
against a brand new empty database created from scratch.
Runbook updated with the full pending-migration list and today's
findings.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-14 18:30:42 +05:30
| `20260318235959_customer_profiles_status_early.up.sql` | Adds `customer_profiles.status` early (`IF NOT EXISTS` ) | `20260319090000` 's backfill UPDATEs this column 4 months before `20260721020000` used to add it — broke any fresh bootstrap |
| `20260401235959_drop_old_employees_table_early.up.sql` | Conditionally drops the old `users` -linked `employees` table (only if it still has the pre-transition shape — no `email` column) | `20260402030000` no-ops its `CREATE TABLE IF NOT EXISTS` against the old shape, then fails creating an index on a column that was never added |
| `20260419235959_external_role_module_tables_early.up.sql` | Creates `persona_types` /`modules` /`role_module_access` /`module_actions` /etc. (the disabled `20260420000003_external_role_modules.up.sql.skip` 's content, purely additive) | The seed migration that depends on these (`20260420000003...seed.sql` ) has no active migration that creates them |
| `20260421235959_role_config_table_renames_early.up.sql` | Conditionally renames `role_permissions→role_admin_permissions` , `dashboard_configs→role_sidebar_configs` , `runtime_configs→role_runtime_configs` , `user_roles→user_role_assignments` (only fires per-table if old name exists and new name doesn't) | `20260422000000` 's widget seed needs `role_sidebar_configs` ; the rename that creates it (`20260420000002...skip` ) was disabled |
2026-08-13 23:10:40 +02:00
| `20260814000000_fix_ai_credit_packages_pricing_and_orders.up.sql` | Fixes prices (99→9900 paise etc.) + creates `ai_credit_orders` with `coupon_code` + `discount_applied` columns | AI credit purchase flow was completely broken: no orders table, wrong prices |
| `20260814010000_ai_credit_packages_role_scoping.up.sql` | Adds `applicable_roles TEXT[]` column to `ai_credit_packages` | Admin UI now supports restricting packages to specific roles |
| `20260814020000_ai_coupons.up.sql` | Creates `ai_coupons` + `ai_coupon_redemptions` tables | Backend `create_order` /`verify_order` reference these tables |
fix(db): 4 fresh-bootstrap migration chain bugs found + verified today
Reconciling the local dev DB (63 migrations behind) surfaced 4 genuine
bugs in the migration chain itself -- not just this DB's legacy
scripts/init-db.sql seeding -- confirmed by replaying the full chain
against a brand new, completely empty database from scratch:
- 20260318235959: customer_profiles.status is UPDATEd by
20260319090000's backfill 4 months before it's ever ADDed
(20260721020000). Adds it early (IF NOT EXISTS).
- 20260401235959: 20260317190000 creates the old users-linked
`employees` shape; 20260402030000's CREATE TABLE IF NOT EXISTS no-ops
against it and fails creating an index on a column that was never
added. Conditionally drops the old shape first (only if it's still
pre-transition -- gated on the missing `email` column), restoring
20260402030000's own documented original intent.
- 20260419235959: the schema `20260420000003_external_role_modules`
needs (persona_types, modules, role_module_access, ...) was only ever
defined in a disabled .up.sql.skip (its version slot was taken by
...seed.sql); the seed data that depends on it was never skipped.
Creates that schema early -- verbatim content, purely additive.
- 20260421235959: same disabled-migration pattern for the
role_permissions -> role_admin_permissions / dashboard_configs ->
role_sidebar_configs / runtime_configs -> role_runtime_configs /
user_roles -> user_role_assignments renames that 20260422000000's
widget seed needs. Conditionally renames each pair (only if old name
exists and new name doesn't), verified against live Rust code that
already queries the new names exclusively.
payments/invoices were NOT chain bugs -- confirmed clean on the fresh
bootstrap test -- so no fix needed for those; they only conflicted on
this one DB because of its scripts/init-db.sql legacy seed, which is
already a documented, known gap.
Verified twice: applied cleanly as no-ops against the now-fully-migrated
local dev DB, and applied successfully end-to-end (0 manual steps)
against a brand new empty database created from scratch.
Runbook updated with the full pending-migration list and today's
findings.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-14 18:30:42 +05:30
| `20260814030000_invoices_payment_id_polymorphic.up.sql` + `20260814050000_invoices_payment_id_polymorphic_check.up.sql` | Drops the hard FK on `invoices.payment_id` (needed for `AI_CREDIT_PURCHASE` invoices, which point at `ai_credit_orders` not `payments` ), then replaces it with a `BEFORE INSERT/UPDATE` trigger that validates `payment_id` against the right table per `invoice_type` | Postgres has no native polymorphic FK; the first migration alone left `payment_id` completely unvalidated |
| `20260814040000_waitlist_signups.up.sql` | Creates the `nxtgauge.com` coming-soon waitlist table | Backs `POST /api/waitlist` |
2026-08-13 23:10:40 +02:00
After applying, redeploy the payments service:
```bash
systemctl restart nxtgauge-payments
```
fix(db): 4 fresh-bootstrap migration chain bugs found + verified today
Reconciling the local dev DB (63 migrations behind) surfaced 4 genuine
bugs in the migration chain itself -- not just this DB's legacy
scripts/init-db.sql seeding -- confirmed by replaying the full chain
against a brand new, completely empty database from scratch:
- 20260318235959: customer_profiles.status is UPDATEd by
20260319090000's backfill 4 months before it's ever ADDed
(20260721020000). Adds it early (IF NOT EXISTS).
- 20260401235959: 20260317190000 creates the old users-linked
`employees` shape; 20260402030000's CREATE TABLE IF NOT EXISTS no-ops
against it and fails creating an index on a column that was never
added. Conditionally drops the old shape first (only if it's still
pre-transition -- gated on the missing `email` column), restoring
20260402030000's own documented original intent.
- 20260419235959: the schema `20260420000003_external_role_modules`
needs (persona_types, modules, role_module_access, ...) was only ever
defined in a disabled .up.sql.skip (its version slot was taken by
...seed.sql); the seed data that depends on it was never skipped.
Creates that schema early -- verbatim content, purely additive.
- 20260421235959: same disabled-migration pattern for the
role_permissions -> role_admin_permissions / dashboard_configs ->
role_sidebar_configs / runtime_configs -> role_runtime_configs /
user_roles -> user_role_assignments renames that 20260422000000's
widget seed needs. Conditionally renames each pair (only if old name
exists and new name doesn't), verified against live Rust code that
already queries the new names exclusively.
payments/invoices were NOT chain bugs -- confirmed clean on the fresh
bootstrap test -- so no fix needed for those; they only conflicted on
this one DB because of its scripts/init-db.sql legacy seed, which is
already a documented, known gap.
Verified twice: applied cleanly as no-ops against the now-fully-migrated
local dev DB, and applied successfully end-to-end (0 manual steps)
against a brand new empty database created from scratch.
Runbook updated with the full pending-migration list and today's
findings.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-14 18:30:42 +05:30
### Local dev DB note (2026-08-14)
The local dev Postgres (`nxtgauge-backend-rust-postgres-1` ) was found ~63
migrations behind (stalled since March) and was brought fully current as
part of today's work, including manually reconciling `payments` /`invoices`
legacy tables seeded by `scripts/init-db.sql` (dropped + recreated, both
verified empty first — not a chain bug, doesn't affect fresh bootstraps).
The four "early" migrations above were then written and verified against
**both** that reconciled DB (all four applied as no-ops) **and** a
completely fresh, empty database created from scratch (`sqlx migrate run`
end-to-end, zero manual intervention) — so any new environment, or anyone
re-bootstrapping from zero, should no longer hit any of these four walls.
2026-08-13 23:10:40 +02:00
---
2026-08-13 21:32:48 +02:00
## 1. Deploy backend changes
2026-08-12 13:39:36 +02:00
```bash
cd nxtgauge-backend-rust
cargo build --release
```
Then restart the affected services:
```bash
2026-08-13 21:32:48 +02:00
# Restart all profession services (wallet/me/holds route)
2026-08-12 13:39:36 +02:00
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
2026-08-13 21:32:48 +02:00
# Restart job_seekers (printpdf upgrade)
2026-08-12 13:39:36 +02:00
systemctl restart nxtgauge-job_seekers
```
---
2026-08-13 21:32:48 +02:00
## 2. Run security checks (no DB needed)
2026-08-12 13:39:36 +02:00
```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.
---
2026-08-13 21:32:48 +02:00
## 3. Set up schemathesis API fuzzing
2026-08-12 13:39:36 +02:00
Schemathesis fuzzes your real API from an OpenAPI spec. It needs:
- The server running (with DB connected)
- An OpenAPI spec (`openapi.json` )
2026-08-13 21:32:48 +02:00
### 3a. Install schemathesis
2026-08-12 13:39:36 +02:00
```bash
pip install schemathesis
2026-08-13 21:32:48 +02:00
# or with uv:
2026-08-12 13:39:36 +02:00
uv tool install schemathesis
```
2026-08-13 21:32:48 +02:00
### 3b. Generate the OpenAPI spec
2026-08-12 13:39:36 +02:00
2026-08-13 21:32:48 +02:00
> **Note:** The axum services don't yet have utoipa annotations. Until then, use
> the manually maintained spec in `docs/openapi.wallet-holds.json` or skip to 3c.
2026-08-12 13:39:36 +02:00
>
> 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.
2026-08-13 21:32:48 +02:00
### 3c. Run the fuzzer
2026-08-12 13:39:36 +02:00
```bash
schemathesis run openapi.json \
--base-url http://localhost:3000 \
--auth "Bearer < admin_or_test_jwt > " \
--checks all \
--hypothesis-settings max_examples=200
2026-08-13 21:32:48 +02:00
# Quick smoke-check:
2026-08-12 13:39:36 +02:00
schemathesis run openapi.json \
--base-url http://localhost:3000 \
--auth "Bearer < jwt > " \
--checks not_a_server_error
```
---
2026-08-13 21:32:48 +02:00
## 4. Run Playwright end-to-end tests
2026-08-12 13:39:36 +02:00
2026-08-13 21:32:48 +02:00
Playwright tests live in `nxtgauge-frontend-solid/tests/` . Need full stack running.
2026-08-12 13:39:36 +02:00
```bash
cd nxtgauge-frontend-solid
2026-08-13 21:32:48 +02:00
npx playwright install --with-deps chromium # one-time
2026-08-12 13:39:36 +02:00
2026-08-13 21:32:48 +02:00
export PLAYWRIGHT_BASE_URL=https://nxtgauge.com
2026-08-12 13:39:36 +02:00
npx playwright test
2026-08-13 21:32:48 +02:00
npx playwright test --grep @smoke # smoke only
npx playwright show-report # view results
2026-08-12 13:39:36 +02:00
```
2026-08-13 21:32:48 +02:00
> **Note:** A few e2e test files still have `localhost:3001` URLs — pending cleanup,
> update to the staging/prod URL before running against live.
2026-08-12 13:39:36 +02:00
2026-08-13 21:32:48 +02:00
---
2026-08-12 13:39:36 +02:00
2026-08-13 21:32:48 +02:00
## 5. Backend integration tests (CI — already wired)
2026-08-12 13:39:36 +02:00
2026-08-13 21:32:48 +02:00
The `nxtgauge_test` DB and Forgejo CI secret are already set up.
To run locally:
2026-08-12 13:39:36 +02:00
```bash
export TEST_DATABASE_URL=postgres://user:pass@localhost:5432/nxtgauge_test
cd nxtgauge-backend-rust
cargo test --test ai_credits -- --test-threads=1
```
---
2026-08-13 21:32:48 +02:00
## 6. Frontend linter
2026-08-12 13:39:36 +02:00
```bash
cd nxtgauge-frontend-solid
npm run lint
```
---
2026-08-13 21:32:48 +02:00
## 7. TypeScript check
2026-08-12 13:39:36 +02:00
```bash
cd nxtgauge-frontend-solid
npx tsc --noEmit --skipLibCheck
```
2026-08-13 21:32:48 +02:00
Should exit 0.
2026-08-12 13:39:36 +02:00
---
2026-08-13 21:32:48 +02:00
## Summary
2026-08-12 13:39:36 +02:00
2026-08-13 21:32:48 +02:00
| Task | Needs DB | Needs server | Status |
2026-08-12 13:39:36 +02:00
|---|---|---|---|
2026-08-13 21:32:48 +02:00
| DB migrations | ✅ | ✅ | ✅ Done (prod) |
| Build + deploy backend | — | — | Pending next release |
| `cargo audit` / `cargo deny` | — | — | Run anytime |
| Schemathesis fuzzing | ✅ | ✅ | Pending OpenAPI spec |
| Playwright e2e | ✅ | ✅ | Pending URL cleanup |
| Backend integration tests | ✅ | — | ✅ Green in CI |
| `npm run lint` | — | — | ✅ Passing |
| `tsc --noEmit` | — | — | Run anytime |