Data Flow
1. Data Flow Principles
TestoQA is server-first. The database is the source of truth, and all tenant-scoped reads/writes occur on the server.
Core principles
- Boundaries validate and contextualize: Input validation +
RequestContextresolution occur before any work. - Authorization before data access: Permission checks must occur before reading or mutating tenant data.
- Tenant scoping is mandatory: All tenant-scoped data access must include
projectId. - DTOs cross boundaries: UI receives controlled shapes; persistence models are not treated as API contracts.
- No client trust: Client state can request actions but cannot assert identity, tenant, or permissions.
System-wide invariants are defined in
system-overview.mdx. This document focuses on the shape of read/write flows and the boundaries where data transforms.
2. Read Flow
A read flow is any operation that retrieves data to render UI or return a response.
Typical read flow (tenant-scoped)
UI (Client/Server Components)
→ Boundary (Server Component data fetch OR Server Action/Route Handler)
→ Resolve session (user identity)
→ Resolve RequestContext (userId + projectId)
→ Authorize (read permission)
→ Service (business interpretation / orchestration)
→ Repository (tenant-scoped query)
→ Prisma → PostgreSQL
→ Map result to DTO
→ Response (render or JSON)
Where reads happen
Reads may be initiated from:
- Server Components (SSR data fetching patterns)
- Route Handlers (API-like reads)
- Server Actions (occasionally used for reads, but typically writes)
Regardless of entry point, the same invariant holds:
Tenant context + authorization must be enforced before tenant data is returned.
Read transformation boundaries
- Repository layer: returns persistence objects (or internal shapes)
- Service layer: maps to DTOs and applies business interpretation
- Boundary/UI layer: consumes DTOs only
3. Write Flow
A write flow is any operation that mutates state or triggers a domain workflow.
Typical write flow (tenant-scoped)
UI (Client Component interaction)
→ Server Action / Route Handler (boundary)
→ Validate input (schema)
→ Resolve session
→ Resolve RequestContext (userId + projectId)
→ Authorize (create/update/delete/execute)
→ Service (workflow + rules)
→ Repository (tenant-scoped mutation)
→ Prisma → PostgreSQL (transaction if needed)
→ Optional side-effects (events/notifications)
→ Map to DTO
→ Response (success/failure)
Write guarantees
- Writes must never occur without an explicit
projectId. - Writes must not rely on client-provided tenant IDs unless verified via membership + context resolution.
- Authorization must be checked before:
- reading any resource used to determine the mutation
- executing the mutation itself
Transactions and multi-step workflows
When a workflow requires multiple database operations:
- Services may coordinate a transaction boundary (implementation detail)
- The architectural requirement is that multi-step writes must be:
- consistent
- tenant-scoped
- safe under concurrency
4. Validation and Transformation Boundaries
Validation and transformation prevent untrusted input or persistence details from leaking across layers.
Input validation (required at boundaries)
- All boundary inputs must be validated against schemas.
- Validated inputs should be treated as the only “trusted” request payload.
DTO mapping (recommended output contract)
- DTOs define what flows upward to the UI.
- DTOs prevent accidental exposure of:
- internal identifiers that shouldn’t be shown
- cross-tenant fields
- persistence-specific fields
- security-sensitive metadata
Where mapping should occur
- Prefer mapping in services (business-owned shaping)
- Repositories should avoid returning raw persistence models directly to UI/boundary
5. File Upload and Binary Data Flow
Uploads are treated as untrusted inputs and require special handling.
Upload flow (high-level)
- Client initiates upload.
- Server validates:
- authentication
- tenant context (
projectId) - authorization to upload within that tenant
- file metadata constraints (size/type)
- Client uploads file content to storage via an upload gateway/provider.
- Server persists upload metadata scoped by
projectId. - Access/serving is controlled by tenant + authorization checks.
Access control rules
- Private files must only be retrievable by authorized users within the same tenant.
- Public exposure is explicit and reviewed.
- File paths, names, and metadata must be sanitized.
Safety notes
- Treat file content as hostile.
- Do not log raw file content or sensitive metadata.
- Virus scanning is not assumed unless explicitly implemented.
6. Realtime Event Flow
Realtime behavior (e.g., execution updates, run status changes) should be modeled as events emitted by server-side workflows.
Event flow (conceptual)
Domain Service completes a state change
→ Emits domain event (internal concept)
→ Integration publishes to realtime provider (e.g., Pusher)
→ Clients subscribed to project-scoped channels receive updates
Tenant-scoped channels
Realtime channels must be scoped by:
projectId(always)- and user scope when needed for sensitive updates
Rule: A client must not be able to subscribe to events for a tenant they do not belong to.
Authorization for subscription or channel naming is part of the realtime integration boundary.
7. Caching and Revalidation
Caching in a multi-tenant system is dangerous if not explicitly scoped.
Default posture
- Prefer no caching (
no-store) for authorization-dependent and tenant-scoped reads unless a safe strategy is proven.
If caching is used
Cache keys must include:
- tenant scope (
projectId) - user scope if results vary by permissions
- any other condition that changes the output
Revalidation rules
- Mutations should invalidate or revalidate relevant reads.
- Revalidation must not cause cross-tenant pollution (e.g., revalidating a shared path that serves different tenant content without scoping).
8. Data Flow Failure Modes
Data flow failures must fail safely without leaking cross-tenant information.
Validation failures
- Return a controlled validation response
- Do not proceed to service/repository calls
Authentication failures
- Treat as unauthenticated (401/redirect semantics)
- No tenant data must be accessed or revealed
Authorization failures
- Return a forbidden response (403 or equivalent)
- Prefer not to reveal whether a resource exists in a different tenant
Tenant resolution failures
- Fail fast before any data access
- Treat as mis-scoped or invalid request
External integration failures
- Handle explicitly (timeouts/retries where safe)
- Avoid logging sensitive payloads
- Fail in a way that does not corrupt tenant state
9. Review Checklist (Data Flow)
- Are inputs validated at the boundary?
- Is
RequestContextresolved (userId + projectId) before work? - Is authorization enforced before tenant data access?
- Do repository queries/mutations enforce tenant scoping?
- Are DTOs used to shape outputs to UI?
- Are uploads treated as untrusted and access-controlled?
- Are realtime channels/events tenant-scoped?
- Is caching either disabled or explicitly scoped by tenant/user?