Corteksa

TestTools

The TestTools model — fields, relations, and API.

Transport: REST — POST /api/v1/testing/purge-account · Auth: API key only (no JWT) · Gates: TEST_TOOLS_ENABLED + TEST_TOOLS_API_KEY

PRD

Business problem

QA needs to sign up, exercise a workspace, and tear it down repeatedly against a shared (staging) environment. The real self-deletion flow enforces a 7-day grace window before a workspace is purged, which makes a fast signup→delete→repeat loop impossible. Testers were resorting to hand-run SQL against the database.

User stories

  • As a tester, I want to delete an account by email with a single authenticated call, so that I can immediately re-register the same email and run the flow again — as many times as I like — without waiting out a grace period or asking for DB access.

Success criteria

  • One call hard-deletes the user and every workspace they own (hyper rows + dedicated DBs), freeing the email for immediate re-signup.
  • Reachable with only a shared API key — no JWT, no admin account.
  • Impossible to trigger by accident in real production: disabled unless an explicit flag is on and a matching key is supplied.
  • Idempotent — deleting a missing account is a 200 with deleted: false, not an error.

How it works

High-level overview — enough to understand the feature without reading the code.

Summary

A test-only endpoint that hard-deletes an account by email, reusing the exact purge primitives the production workspace-deletion cron uses — just keyed by email and looped over every workspace, with the grace window skipped. It is walled off behind a double fail-closed guard so it can only ever run where a tester explicitly enabled it.

Flow

Steps

  1. The guard checks TEST_TOOLS_ENABLED === 'true' (else 403) then a constant-time X-Api-Key vs TEST_TOOLS_API_KEY (else 401). No user context is resolved.
  2. TestAccountService.purgeByEmail looks the user up by email; a miss returns deleted: false (no error).
  3. For each of the user's workspaces:
    • HyperWorkspaceMigrationService.deleteWorkspaceData deletes every workspace_id-scoped row from the shared crm_hyper DB (including the admin row), then the user_workspaces row is removed; the shared tenant stays.
    • DedicatedTenantProvisioningService.dropDatabase drops the tenant DB, then its main-DB records (memberships → workspace → tenant) are removed.
  4. The user's remaining memberships and the user row itself are deleted, freeing the email.

Key components

  • Controllertest-account.controller.ts (POST /testing/purge-account, @UseGuards(TestToolsGuard)).
  • Servicetest-account.service.ts (purgeByEmail, mirrors WorkspaceDeletionProcessor.purge).
  • Guardguards/test-tools.guard.ts (enable-flag + constant-time key check).
  • ReusedWorkspaceMigrationService, HyperTenantService, TenantProvisioningService — the same primitives as production deletion, so RLS / connection-pinning behavior is identical (no hand-rolled SQL).

FRD

The single capability this module exposes:

  • purge-account — hard-delete a user + all their workspaces by email. Body { email }; returns { deleted, email, user_id?, workspaces[] }. Bypasses the self-deletion grace window (test-only). Idempotent on a missing account.

HLD

Frontend

None — this is a backend QA utility. A tester calls it from a script, Postman, or curl with the shared X-Api-Key.

API

REST, POST /api/v1/testing/purge-account, guarded by TestToolsGuard (API key, no JWT). See API.

Database changes

Destructive and irreversible: deletes workspace_id rows across the shared crm_hyper DB, drops dedicated tenant databases, and removes user_workspaces, user_tenant_memberships, and user rows in the main DB. Creates nothing.

LLD

Configuration

Env varPurposeFail-closed behavior
TEST_TOOLS_ENABLEDMaster on/off. Must equal "true".Anything else → 403
TEST_TOOLS_API_KEYShared secret sent as X-Api-Key.Unset → 401; mismatch → 401

Leave TEST_TOOLS_ENABLED=false in real production. Both gates must pass, so a stray key with the flag off (or the flag on with no key) stays inert.

Services

  • TestAccountService.purgeByEmail(email) — orchestrates the lookup + per-workspace purge + user removal; returns a PurgeAccountResult.
  • purgeHyperWorkspace / purgeDedicatedWorkspace — private helpers, one per tenant kind, mirroring the production processor.

Validators

  • PurgeAccountDto@IsEmail() + @IsNotEmpty(); the email is trimmed + lowercased before lookup.
  • TestToolsGuard — enforces the enable flag and the constant-time key comparison.

Request / response

POST /api/v1/testing/purge-account
X-Api-Key: <TEST_TOOLS_API_KEY>
Content-Type: application/json

{ "email": "tester@example.com" }
{
  "message": "Account purged",
  "data": {
    "deleted": true,
    "email": "tester@example.com",
    "user_id": 262,
    "workspaces": [
      { "workspace_id": 56, "type": "hyper", "rows_deleted": 137 }
    ]
  }
}

workspaces[].typehyper | dedicated | orphan; rows_deleted is the hyper row count (null for a dedicated DB drop). A missing account returns deleted: false with an empty workspaces array.

ERD

No entities — this module owns no tables. It operates on existing main-DB records (user, user_workspaces, user_tenant_memberships, tenants) and the shared crm_hyper workspace-scoped tables, reusing the deletion module's primitives.

On this page