Phase 2: Operation Test Suites
Goal
Create three operation-measurement test suites so TendSocial can measure the Prisma database cost and performance impact of each API route, standard user flow, page load, click, and action.
Prisma pricing is based on database operations. Prisma states that it counts Prisma ORM queries, not every SQL statement generated behind the scenes. Source: Prisma pricing.
Metrics to capture
Each measured action should capture:
| Metric | Meaning |
|---|---|
measurementId | Unique UUID for request/action correlation. |
label | Human-readable action label. |
apiDurationMs | Backend request duration. |
browserDurationMs | User-visible browser action duration. |
prismaOrmOps | Count of Prisma ORM operations. |
sqlStatements | SQL statement count generated by Prisma. |
sqlDurationMs | Total SQL duration from Prisma query events. |
networkRequests | API calls triggered by a browser action. |
rowsRead | Optional if available. |
rowsWritten | Optional if available. |
warnings | N+1, duplicate fetches, slow query, missing-index suspicion. |
Instrumentation foundation
Prisma query logging
Prisma Client supports event-based logging with $on('query'), including query, params, and duration. Source: Prisma Client logging.
Example:
import { PrismaClient } from "@prisma/client";
export const prisma = new PrismaClient({
log: [
{ emit: "event", level: "query" },
{ emit: "stdout", level: "error" },
{ emit: "stdout", level: "warn" },
],
});
prisma.$on("query", (event) => {
console.log({
query: event.query,
params: event.params,
durationMs: event.duration,
});
});Request correlation
Every API request and Playwright action should include:
x-tendsocial-measurement-id: <uuid>
x-tendsocial-measurement-label: dashboard.loadBackend responses should include headers where possible:
x-db-orm-ops: 8
x-db-sql-statements: 11
x-db-sql-duration-ms: 42
x-api-duration-ms: 123And optionally a JSON debug payload in benchmark mode:
{
"measurementId": "...",
"label": "dashboard.load",
"apiDurationMs": 123,
"prismaOrmOps": 8,
"sqlStatements": 11,
"sqlDurationMs": 42
}Suite A: Backend API operation tests
Goal
Call each API route directly from the backend test runner and measure the Prisma impact of every route without browser noise.
Command
pnpm test:dbops:apiCoverage checklist
| API area | Required actions |
|---|---|
| Auth/session | current user, session check, workspace membership |
| Workspace | list, load, switch, update |
| Brand profile | load, update, brand voice/tone |
| Content | list, detail, create, update, archive/delete |
| Blog | list, load body, save draft |
| Calendar | month load, week load, schedule item |
| Campaigns | list, detail, attach content |
| Social accounts | list, connect placeholder, sync metadata |
| AI workflow metadata | create draft, save generation result, update status |
| Publishing queue | enqueue, list, update status |
| Notifications | list, mark read |
| Settings | load/update account and workspace settings |
Output
reports/dbops/api-summary.json
reports/dbops/api-summary.csv
reports/dbops/api-summary.mdAPI result row
{
"endpoint": "/api/content",
"method": "GET",
"actionLabel": "content.list",
"status": 200,
"apiDurationMs": 118,
"prismaOrmOps": 7,
"sqlStatements": 9,
"sqlDurationMs": 39,
"warnings": []
}Suite B: Playwright standard task run
Goal
Measure representative user workflows through a real browser.
Playwright supports reusable authenticated browser state, which avoids logging in during every test. It recommends storing auth state under playwright/.auth and keeping it out of source control because it can contain sensitive cookies/headers. Source: Playwright authentication.
Command
pnpm test:dbops:e2e-standardStandard flows
| Flow | Steps |
|---|---|
| App shell | Open app, load dashboard, load workspace |
| Content creation | Create social post, save draft, view list |
| Blog draft | Create blog post, edit body, save |
| Calendar scheduling | Open calendar, schedule content, change date |
| Brand settings | Load brand profile, update voice/tone settings |
| Social accounts | Load connections, open account detail |
| AI draft generation | Trigger mocked AI generation, save result |
| Publishing queue | Enqueue mocked post, view queue/status |
Playwright network tracking
Playwright can monitor request and response events and wait for network responses after user actions. Source: Playwright network.
Use:
page.on("request", request => {
// capture request.method(), request.url(), headers
});
page.on("response", async response => {
// capture response.status(), response.url(), DB measurement headers
});Output
reports/dbops/e2e-standard.json
reports/dbops/e2e-standard.csv
reports/dbops/e2e-standard.mdSuite C: Exhaustive Playwright action/page-load crawl
Goal
Measure every page load, click, modal open, tab switch, filter, search, sort, pagination, save, and destructive action in the app.
This is a DB profiler, not a QA suite.
Command
pnpm test:dbops:e2e-exhaustiveAction registry
Create:
tests/dbops/action-registry.tsExample:
export const actions = [
{
id: "dashboard.load",
route: "/dashboard",
steps: [
{ type: "goto", url: "/dashboard" }
],
},
{
id: "content.open-create-modal",
route: "/content",
steps: [
{ type: "goto", url: "/content" },
{ type: "click", role: "button", name: "Create" }
],
},
{
id: "content.filter.status-draft",
route: "/content",
steps: [
{ type: "goto", url: "/content" },
{ type: "click", role: "button", name: "Status" },
{ type: "click", role: "option", name: "Draft" }
],
}
];Measurement wrapper
For every action:
const measurementId = crypto.randomUUID();
await page.setExtraHTTPHeaders({
"x-tendsocial-measurement-id": measurementId,
"x-tendsocial-measurement-label": action.id,
});Collect all API responses and sum DB measurement headers.
Output
reports/dbops/e2e-exhaustive.json
reports/dbops/e2e-exhaustive.csv
reports/dbops/e2e-exhaustive.md
reports/dbops/e2e-exhaustive-hotspots.mdHotspot ranking:
highest Prisma ORM operations
highest SQL statement count
highest SQL duration
highest browser duration
highest repeated API calls
highest background/polling noiseTraces
Enable Playwright trace on failure or retry. Trace viewer is useful for debugging which browser actions and network requests created a DB hotspot. Source: Playwright trace viewer.
Suggested config:
use: {
trace: "on-first-retry",
}For dedicated investigation:
npx playwright test --trace onInitial thresholds
| Action class | Target Prisma ops |
|---|---|
| Simple read | 1-3 |
| Workspace/dashboard shell | <10 |
| Calendar/content list | <15 |
| Heavy editor save | <10 |
| AI generation save | <10 |
| Background batch job | Bounded and paginated |
Acceptance criteria
| Item | Target |
|---|---|
| API suite created | Yes |
| Standard Playwright suite created | Yes |
| Exhaustive Playwright suite created | Yes |
| Reports emitted as JSON, CSV, and Markdown | Yes |
| Measurement IDs correlate browser/API/Prisma activity | Yes |
| Top 20 DB hotspots identified | Yes |
| CI can run API suite | Yes |
| Exhaustive suite can run manually/on demand | Yes |