Skip to main content

Architecture & Compliance: Building an Unshakeable Data Foundation

In enterprise software evaluation, development efficiency is rarely the primary concern for architects. How thoroughly data is isolated, how easily privacy might be compromised, and whether the system satisfies rigorous compliance audits (such as SOC2 / GDPR) are the core factors that decide the fate of an underlying data framework.

From the beginning, TeaQL rejected the traditional "global static connection pool" pattern, deeply embedding security and compliance aspects into every single data transaction.

1. UserContext: A Secure Sandbox Environment

In traditional ORMs (such as SQLx / Diesel), developers fetch database connections (Connection / Pool) directly to execute SQL. This pattern is highly prone to privilege escalation because the connection itself carries no business context.

TeaQL enforces a mandatory UserContext mechanism:

// Incorrect Example: TeaQL does not allow naked data querying bypassing the Context
// Q::tasks().fetch_all(&pool).await; // Compilation Error!

// Correct Example: Encapsulating identity and permissions inside the Context
let ctx = UserContext::new()
.with_module(crm::module())
.insert_resource(TenantId(1024))
.insert_resource(CurrentUser::from_token(token)?);

let tasks = Q::tasks().comment("Query tasks").purpose("Load data").execute_for_list(&ctx).await?;

UserContext is essentially a resource container with a strict lifetime. When a request arrives, the architectural layer injects the parsed multi-tenant ID, user roles, and security tokens into ctx. All derived queries, interceptors, and persistence actions must run within this closed context.

2. RLS via TypedChecker (Row-Level Security)

Privilege escalation (BOLA/IDOR) is the most painful security vulnerability in SaaS systems. Relying on developers to manually append WHERE tenant_id = ? to every query is prone to human error.

TeaQL provides TypedChecker, allowing architects to forcefully inject physical isolation barriers at the framework level.

// Interceptor defined at the architectural layer
pub struct TenantIsolationChecker;

#[async_trait]
impl TypedChecker<Task> for TenantIsolationChecker {
async fn on_before_query(&self, ctx: &UserContext, query: &mut SelectQuery) -> Result<(), CheckerError> {
let tenant_id = ctx.get_resource::<TenantId>()
.ok_or(CheckerError::SecurityViolation("Missing tenant context"))?;

// Enforce the tenant isolation filter; the business layer cannot bypass this
query.and_filter(Expr::eq("tenant_id", tenant_id.0));
Ok(())
}
}

Once this Checker is registered to a module, any possibility of unauthorized reads or writes is completely blocked at the framework level. The business code can still simply write Q::tasks().comment("Query tasks").purpose("Load data").execute_for_list(&ctx), while the generated SQL will always be appended with WHERE tenant_id = 1024.

3. Non-Repudiable Event Auditing (Audit Trails)

Financial and healthcare systems require precise audit logging: who, when, through which business action, modified which field from A to B. Traditional solutions rely heavily on manual logging, which is tedious and easily leads to compliance gaps when omitted.

TeaQL's design principle is: Let the data engine itself be the single source of truth.

When persistence is triggered via entity.audit_as("Save operation").save(&ctx), the TeaQL runtime compares memory snapshots to extract the exact "dirty fields" and synchronously dispatches them to both internal and external dual-channel log sinks after the transaction commits.

Furthermore, to prevent custom log sinks from receiving sensitive credentials (like passwords) or blowing up memory, the event model is strictly split into two layers:

  1. RawAuditEvent (Internal Kernel Only): Contains 100% complete change details and raw request data, used for hardened compliance writes at the database level.
  2. SafeAuditEvent (Exposed Externally): Cleaned, desensitized, and truncated safety events.

The kernel reads the desensitization metadata configured in the XML model (e.g., _audit_mask_fields="password,ssn" and _audit_value_max_len="2048"). Before publishing to external event sinks, it automatically replaces passwords with *** MASKED *** and truncates large text to ...(truncated). Sensitive fields are not removed; only their plaintext representations are masked.

pub struct ComplianceAuditLogger;

impl EntityEventSink for ComplianceAuditLogger {
fn on_event(&self, ctx: &UserContext, event: &SafeAuditEvent) -> Result<(), RuntimeError> {
let user = ctx.user_identifier().unwrap_or("SYSTEM");

// Generate an immutable compliance log; passwords are auto-masked and long JSONs are truncated
publish_to_kafka("audit_logs", json!({
"operator": user,
"entity": event.entity,
"action": format!("{:?}", event.kind),
"changed_fields": event.changes.iter().map(|c| c.field.clone()).collect::<Vec<_>>(),
"timestamp": chrono::Utc::now()
}));

Ok(())
}
}

Registering this Sink to the context (via ctx.set_custom_event_sink(...)) guarantees that any data change will leave a signed audit trail. Because the framework separates custom sinks from the core compliance sink, developer configuration mistakes cannot disable system audits.

4. Compile-Time Foolproofing: A Fail-Fast Linter for AI

If desensitization relies on metadata (_audit_mask_fields), what happens if the AI or a developer forgets to add it to the XML schema?

To address this, TeaQL embeds the KSML Static Evaluation Engine (Evaluation Linter) in the compiler/generator phase:

  • When high-risk fields like password or token are detected without desensitization flags, the generator directly halts compilation and prints a JSON error response with a correction example, instructing the developer or AI to resolve it using <user _audit_mask_fields="password" />.
  • For secondary sensitive PII fields like phone or email, the engine generates warnings in evaluation_report.json for IDE plugins or AI self-correction.

This "Defensive Design" guards against human neglect and mitigates security risks associated with automated AI code generation.

5. Strict Physical Ban on "Context-Bypassing" Calls

In globalized systems, "time" and "data" are never stateless. "Today" in Beijing is different from "today" in New York. Architects dread developers calling the standard library's Utc::now(), introducing timezone offsets, or accessing low-level std::fs directly to bypass auditing.

TeaQL enforces this boundary using the compiler's clippy.toml:

disallowed-types = [
"teaql_tool::T", # Ban stateless utility facade
"chrono::Utc", # Ban context-bypassing time acquisition
"std::fs::File", # Ban direct file I/O
]

At the application layer, all computation and I/O operations must go through ctx (the Context Facade). This allows the framework to automatically correct and intercept calls based on the tenant's Timezone, Locale, and user identity:

// Correct: Retrieve tenant-specific date and mandate business intent comments
let deadline = ctx.time().today().add_days(7).comment("Calculate payment deadline");

// Correct: Perform HTTP request via the context; the system automatically records audit logs
let external_data = ctx.http().get("https://...").comment("Sync tenant metadata").await?;

This absolute defense ensures non-compliant code fails at compile time: "No comment, no execution; no context, no compilation."

6. Zero-Code Environment-Driven Safety and Schema Protection

Security lapses often occur during the transition between development and production environments. Configuring log levels or schema migration policies using code modifications or complex YAMLs is error-prone.

TeaQL resolves this through a combination of zero-code environment variable control and dual compile-time/runtime whitelisting.

Dual Whitelisting for Maximum Security

  • Compile-time: The code generator creates constant arrays of all trusted entities and table names from the model. There are no magic strings in the codebase, cutting off AI hallucinations and typos.
  • Runtime: The framework strictly validates all TEAQL_ environment variables. If a variable is misspelled (e.g., TEAQL_AUDT) or contains invalid table/reserved names, the application immediately terminates with a fatal error (offering a "Did you mean?" suggestion) instead of running with incorrect configurations.

Schema Migration: Default to Safe

In production, accidental automatic schema updates (like CREATE INDEX or ALTER TABLE) can lock the database. Using the TEAQL_SCHEMA variable, architects retain full control:

  • Default (_verify): If no environment variable is set, this is the default behavior. The framework only verifies whether the database schema matches the business model. If there is a mismatch, startup is rejected.
  • Pre-deployment Audit (_dryrun): Only outputs the migration SQL for DBA review without executing any changes.
  • Dev & CI (_execute): Automatically creates tables and applies migrations to speed up development.

This "dangerous operations must be explicitly declared" pattern avoids production disasters caused by operational oversights.

Design Philosophy

TeaQL's strict zero-code control is derived from real-world enterprise engineering lessons:

  1. The application layer can only order from the menu, not enter the kitchen: Application code should never decide which logs to write or whether to alter the table structure. Elevating controls to environment variables allows operations and security teams to manage compliance without touching the application build.
  2. Nothing outside the whitelist is permitted: Misspelled variables by SREs or table name hallucinations by AI Coder will trigger an immediate fail-fast crash. Quietly ignoring invalid configurations is the greatest threat to security.
  3. Restricting freedom to guarantee extreme security: We deliberately restrict environment variables to 7 predefined choices. In core infrastructure, limiting unnecessary flexibility is the best way to safeguard the system.

Summary

For architects, TeaQL offers a highly cohesive security declaration framework. By controlling UserContext assembly and registering global checkers and event sinks, architects absorb the complexity of data security, multi-tenancy isolation, and compliance auditing into the infrastructure layer, letting business developers write code safely in an isolated sandbox.