Skip to main content

18 posts tagged with "architecture"

View All Tags

Direct Data API or Governed Business Query API? Supabase and TeaQL Solve Different Boundaries

· 10 min read
Philip Z
Architect

Supabase gives applications a direct Data API. TeaQL gives applications and AI agents a governed business query API.

The two ideas can produce a similar developer experience: a frontend composes a query instead of waiting for a backend team to add one more endpoint. But they place the public boundary at different layers of the system.

Supabase reflects a PostgreSQL schema into an API. TeaQL exposes capabilities from a shared business model and lets a trusted runtime decide how those capabilities are executed. That difference becomes important when an application has complex authorization, several backend languages, multiple data sources, or AI agents that need composition without database authority.

Rust Made Object Mutation Hard—So We Designed It Properly

· 9 min read
Philip Z
Architect

Object mutation feels simple in many languages. Load an object, call a setter, and save it. If the object has children, mutate those too. Somewhere underneath, an ORM compares snapshots, observes setters, or walks an identity map and turns the differences into database commands.

Then we implemented the same programming model in Rust.

Rust did not let us casually hide shared mutable state behind an object graph. Ownership and borrowing forced us to answer questions that our other runtimes had allowed us to postpone.

Beyond SQL Dialects: A Governed Business Query Language for AI Agents

· 8 min read
TeaQL Team
Core Team

An AI agent becomes much more useful when it can answer questions that an application team did not anticipate when the system was built.

Consider this request:

Find customers who placed more than three orders in the last 30 days, have a refund rate above 20%, and still have an unresolved support ticket.

A conventional application may not have an endpoint for that exact question. A model with unrestricted SQL access could try to construct it, but it would also need to know the physical schema, joins, enum encodings, tenant filters, authorization rules, soft-delete conventions, and database dialect. That is a large and dangerous contract to place in a prompt.

TeaQL offers a different boundary:

Give the model composable business semantics, not database authority.

TeaQL sits above SQL dialects as a governed business query language. The model can combine approved domain concepts into a query that has never been exposed as a dedicated endpoint, while the application retains control of identity, permissions, limits, audit, and execution.

Internationalization as Application Infrastructure

· 10 min read
TeaQL Team
Core Team

Internationalization often enters an application as a small feature: read a language header, look up a string, and return the translated text. That approach works—until the application grows beyond one HTTP endpoint, one runtime, or one team.

TeaQL is taking a different path. We are designing internationalization as part of the application infrastructure: explicit in UserContext, structured before rendering, consistent across six programming languages, and constrained strongly enough that both people and coding agents can extend it without inventing a new architecture at every call site.

This work is still in design and is not yet a released portable TeaQL capability. This article explains why we believe the design is worth doing, the trade-offs we are making, and the kinds of organizations that benefit from it.

Lightweight Skills, Strong Tools: A Practical Architecture for Reliable AI Agents

· 9 min read
Philip Z
Architect

As AI agents become more capable, it is tempting to make their Skills increasingly detailed. Every new failure becomes another instruction. Every exception becomes another paragraph. Eventually, the Skill tries to describe the domain, encode the workflow, enforce safety, teach the tool interface, and anticipate every future mistake.

That approach does not scale.

Our practical conclusion is different:

Keep Skills lightweight. Make Tools strong.

This is not an argument for fewer safeguards. It is an argument about where safeguards belong.

It is also a principle for harness engineering. The core of an agent harness should not be an ever-growing library of Skills. It should be a set of strong, model-aware Tools and deterministic feedback loops that turn guidance into enforceable action boundaries.

Dynamic World Models: The Missing Requirements Layer for AI-Native Software Engineering

· 11 min read
Philip Z
Architect
Clariones Wang
Jacky Tian

AI can generate code. That does not mean it understands the world the code is supposed to represent.

This distinction is becoming one of the central problems in AI-native software engineering. A model may produce a plausible database schema, API, or workflow while missing an implicit business rule, confusing a role with a person, or treating a derived state as a source of truth. The output can be syntactically correct and still describe the wrong system.

The missing layer is not another code generator. It is a better representation of requirements.

We call this representation a Dynamic World Model: a reasoning framework for explaining how a domain works and why it is in its current state. In this framework, concepts participate in events, under constraints, to create and evolve relationships. Software is then generated or implemented as an executable projection of that explanation.

Numeric Entity IDs Across Rust, Java, Go, Python, SQL, and JSON

· 6 min read
TeaQL Team
Core Team

An entity ID looks like a small implementation detail until the same value has to survive a database join, a Rust service, a Java service, a Go worker, a Python script, and a browser. Each environment can represent a different set of integers, and accepting the widest type in one layer can make the whole system less portable.

TeaQL therefore separates three decisions:

  • persistence identities and foreign keys are compact numeric values;
  • their portable persisted range is the positive signed 64-bit range;
  • IDs crossing a JSON boundary are encoded as decimal strings.

The range is enormous for an identity space, but small enough to have a direct, unambiguous representation in the database and in the major server languages TeaQL supports.

Removing Reflection from TeaQL Java's Core Path: Runtime Determinism as Harness Engineering

· 12 min read
Philip Z
Architect

TeaQL Java did not remove every use of reflection from the repository. We did something more practical: we removed reflection from the core entity execution path, isolated the remaining reflective utilities, and added build-time guardrails to stop reflection from quietly returning.

GraalVM Native Image was an important forcing function, but it was not the highest-level reason for the work. The larger goal was to make the runtime environment more deterministic: important behavior should be explicit, inspectable, bounded, and enforceable before a production request reaches it.

We see that as harness engineering. The reliability of a system should not depend only on developers or coding agents remembering the right conventions. The surrounding environment—generated code, metadata, module boundaries, compiler-visible calls, build rules, and tests—should constrain execution into known-good paths.

TeaQL Java Runtime: Modular Refactor, Multi-Framework Ready, Rust-Aligned

· 6 min read
Philip Z
Architect

We refactored the TeaQL Java runtime (teaql-java) to achieve three goals:

  1. JPMS module boundaries — seal internal packages, expose only what generated code needs
  2. Spring Boot independence — run without Spring Boot using a plain main() function
  3. Rust alignment — dual-layer audit logging, compile-time query enforcement, RequestPolicy

Declarative Data Service Routing for Polyglot Persistence

· 4 min read
TeaQL Team
Core Team

In modern complex application architectures, polyglot persistence has almost become a standard configuration. Within a single system, core transactional data may require PostgreSQL for strong consistency guarantees, massive execution logs might need Meilisearch for full-text search, state information could be thrown into Redis for ultra-high-speed caching, and local development might even downgrade to rusqlite.

The trade-off is coordination complexity: connection pools, provider SDKs, and routing decisions can leak into application code.

Kernel-Level Audit & Privacy: Building Resilient Audit Chains in the AI Coding Era

· 6 min read
Philip Z
Architect

In the era of AI Coding, business code may be co-generated and modified by human developers, AI agents, or automated tools. This brings a new challenge:

While business logic is becoming increasingly easy to generate automatically, the audit chain must not become fragile as a result.

Traditional audit systems often rely on business code to actively record logs. However, in AI Coding scenarios, this approach carries clear risks:

  • AI might forget to write audit logs;
  • AI might accidentally disable logs;
  • AI might generate code that bypasses audits;
  • Business code might unintentionally record sensitive plain text;
  • A custom audit hook might access raw data it shouldn't see;
  • Long strings, JSON payloads, or execution logs might cause audit log bloating or even out-of-memory (OOM) errors.

Therefore, TeaQL underwent a low-level refactoring to move auditing capabilities into the framework kernel rather than leaving them entirely to the business code. We established the following core principles:

Audit must be kernel-level.
Business code may enrich audit trails, but it cannot erase them.
Sensitive fields do not disappear; only their plain text disappears.

The Return of E Expressions: Fluent Chaining and Structured Panics for AI Auto-Healing

· 4 min read
Philip Z
Architect

In the evolution of TeaQL, we've constantly navigated the tension between developer ergonomics and idiomatic Rust. We recently brought the E:: fluent expression chain back to Rust.

This is not a simple rollback. The new design uses reference chaining instead of cloning entity graphs and emits structured diagnostics when a relation was not loaded.

Why AI-generated software needs deterministic business APIs

· 2 min read
TeaQL Team
Core Team

AI coding tools can produce useful application code quickly. The problem is not speed. The problem is boundary control.

If an AI tool has to infer persistence behavior from scattered SQL, repositories, mapper XML, DTOs, and service conventions, it will eventually guess wrong.

TeaQL exists to make that boundary deterministic.

The Guessing Problem

When AI writes data-access code directly, it must infer:

  • table names;
  • column names;
  • relation cardinality;
  • tenant filters;
  • permission rules;
  • deleted-row semantics;
  • transaction boundaries;
  • pagination rules;
  • response shape;
  • database dialect differences.

Some of these guesses can pass a simple test and still be wrong in production.

The Business API Boundary

TeaQL generates APIs from the domain model. That means AI code can compose with named business methods instead of inventing storage behavior.

let orders = Q::orders().select_customer_with(Q::customers().comment("Query customers").purpose("Load data").select_name())
.select_line_item_list_with(Q::line_items().comment("Query line_items").purpose("Load data").select_sku())
.which_statuses_are("PAID")
.page(1, 20)
.comment("Query orders").purpose("Load data")
.execute_for_list(&ctx)
.await?;

The model controls what fields and relations exist. The runtime controls how the query executes. The AI composes within those boundaries.

Deterministic Does Not Mean Rigid

A deterministic API can still be expressive:

  • filters can be combined;
  • relation loads can be nested;
  • aggregates can be grouped;
  • graph writes can save parent and child objects together;
  • provider-specific behavior can be selected below the API.

The point is that the API surface is stable and reviewable.

Better Prompts

TeaQL also makes prompts smaller.

Instead of giving an AI tool the entire schema, SQL examples, repository conventions, and DTO rules, a team can provide a generated API guide:

Use TeaQL Q APIs for reads.
Use generated relation selectors.
Execute through UserContext.
Do not write raw SQL unless explicitly requested.
Use graph save for parent-child persistence.

That is a stronger contract than a long explanation of database structure.

Runtime Safety

The generated API is only half the story. Runtime boundaries matter too.

TeaQL keeps execution behind context and provider layers:

  • Java uses UserContext as the runtime boundary.
  • Rust uses teaql_runtime::UserContext, repository registries, behavior hooks, and provider registration.
  • Database providers execute against PostgreSQL, MySQL, SQLite, rusqlite, or memory.

AI-generated application code should not own those decisions.

The Short Version

AI tools are fast at composition. They are unreliable at reconstructing business rules from infrastructure code.

TeaQL gives them deterministic business APIs to compose.

Core Architecture Refactor: Modularization and Reactive Support

· One min read
TeaQL Team
Core Team

TeaQL core was decoupled from Spring, the SQL repository became its own module, and WebFlux reactive support was added.

Module Split

Before

teaql (monolithic)
├── Entity/Request/Context
├── SQLRepository (all databases)
└── Spring auto-config

After

teaql (core, no Spring dependency)
├── Entity/Request/Context
├── Expression framework
└── Checker

teaql-sql (SQL repository base)
teaql-mysql / teaql-pg / teaql-oracle (database-specific)
teaql-autoconfigure (Spring Boot starter)

WebFlux Support

+ WebFlux reactive endpoint support
- Removed spring-boot-starter-web dependency from core

TeaQL now works with both Spring MVC and Spring WebFlux.

JDBC DataSource

Added JdbcDataSource for explicit JDBC connection management.

TeaQL is Born: Type-Safe Query Expressions

· One min read

This is where TeaQL began. In November 2022, the core runtime shipped with 95 files and 4,636 lines of code.

Core Capabilities

SQL Expression Parser

SQLExpressionParser, PropertyParser, and RawSqlParser form the foundation of type-safe query expressions:

Q.orders().filter(
Q.orders().comment("Query orders").purpose("Load data").customer().city().eq("Shanghai")
).comment("Query orders").purpose("Load data").executeForList(ctx);

Sub-Query Support

SubQueryParser (62 lines) enables nested queries expressed naturally in Java:

Q.orders().filter(
Q.orders().comment("Query orders").purpose("Load data").customer().city().eq("Shanghai")
).comment("Query orders").purpose("Load data").executeForList(ctx);

Dynamic Aggregation Framework

SimpleAggregation supports count, sum, avg, and more directly from the domain model.

Architecture at a Glance

  • Expression-based queries: Type-safe Java expressions compiled to SQL
  • Repository pattern: SQLRepository as the base with database-specific extensions
  • Sub-query composition: Nest queries naturally in Java
  • Aggregation framework: First-class aggregate function support

These patterns remain the foundation of TeaQL today.