# Architectural Rules Enforced by Instatic's Architecture Tests: The Complete Guide

> Instatic's architecture tests enforce 18 structural and design-time invariants, breaking your build on violation. Discover the complete guide to these automated checks.

- Repository: [CoreBunch/Instatic](https://github.com/CoreBunch/Instatic)
- Tags: deep-dive
- Published: 2026-07-27

---

**Instatic enforces 18 categories of structural and design-time invariants through automated architecture tests located in `src/__tests__/architecture/*.test.ts`, which break the build immediately upon any violation.**

Instatic, developed by CoreBunch, encodes its architectural decisions as executable tests that run on every `bun test` invocation. These tests act as guardrails for module boundaries, database portability, security boundaries, and UI consistency. The following sections detail every rule encoded in the test suite, referencing the actual test files and enforced constraints found in the source code.

## Module Import and Public API Boundaries

Instatic strictly controls how modules expose and consume internal APIs to maintain stable public surfaces.

### Barrel-Import Discipline

The test [`src/__tests__/architecture/no-core-barrel-deep-imports.test.ts`](https://github.com/CoreBunch/Instatic/blob/main/src/__tests__/architecture/no-core-barrel-deep-imports.test.ts) enforces that external code imports public APIs exclusively through a module’s barrel (`@core/page-tree`) and never via concrete internal paths such as `@core/page-tree/node.ts`. This prevents accidental reliance on private implementation details that may change.

```ts
// ❌ Wrong – deep import of an internal file
import { PageNode } from '@core/page-tree/node';

// ✅ Correct – use the barrel export
import { PageNode } from '@core/page-tree';

```

### Plugin Import Boundaries

Plugin bundles are prohibited from importing Node/Bun core modules or performing unauthorized I/O. The [`plugin-sandbox-invariants.test.ts`](https://github.com/CoreBunch/Instatic/blob/main/plugin-sandbox-invariants.test.ts) and [`plugin-host-import-boundaries.test.ts`](https://github.com/CoreBunch/Instatic/blob/main/plugin-host-import-boundaries.test.ts) tests ensure that all permissions are centrally declared and that plugin hosts do not import the API dispatch layer, preventing circular dependencies.

## Database Dialect and Storage Conventions

Instatic maintains portability between PostgreSQL and SQLite through strict SQL and schema rules.

### ANSI-SQL Compliance and JSON Handling

The [`db-postgres-isms.test.ts`](https://github.com/CoreBunch/Instatic/blob/main/db-postgres-isms.test.ts) test bans PostgreSQL-specific syntax (`now()`, `::int`, etc.), enforcing ANSI-SQL only. Additionally, [`db-json-column-naming.test.ts`](https://github.com/CoreBunch/Instatic/blob/main/db-json-column-naming.test.ts) requires JSON columns to end with `_json`, mapping to `jsonb` in Postgres and `text` in SQLite. All persisted JSON must pass through TypeBox helpers rather than raw `JSON.parse`, as enforced by [`json-extract-egress.test.ts`](https://github.com/CoreBunch/Instatic/blob/main/json-extract-egress.test.ts) and [`boundary-validation.test.ts`](https://github.com/CoreBunch/Instatic/blob/main/boundary-validation.test.ts).

```ts
// ❌ Illegal usage in a repository
await db.query('SELECT * FROM posts WHERE created_at > now()');

// ✅ ANSI-SQL compliant
await db.query('SELECT * FROM posts WHERE created_at > CURRENT_TIMESTAMP');

```

### Migration Parity and Content Storage

The [`migration-parity.test.ts`](https://github.com/CoreBunch/Instatic/blob/main/migration-parity.test.ts) test ensures that migrations for PostgreSQL and SQLite share identical IDs and order. Content-storage conventions are enforced by [`data-tables-system-flag.test.ts`](https://github.com/CoreBunch/Instatic/blob/main/data-tables-system-flag.test.ts), [`no-legacy-content-domain.test.ts`](https://github.com/CoreBunch/Instatic/blob/main/no-legacy-content-domain.test.ts), and [`no-legacy-pages-table.test.ts`](https://github.com/CoreBunch/Instatic/blob/main/no-legacy-pages-table.test.ts), which mandate that system tables (`posts`, `pages`, `components`) are seeded with `system: true`, legacy tables are eradicated, and all content lives in `data_*` tables.

## Validation and Type Safety Boundaries

Instatic uses TypeBox to maintain type safety at runtime boundaries.

### TypeBox-Only Validation

The [`boundary-validation.test.ts`](https://github.com/CoreBunch/Instatic/blob/main/boundary-validation.test.ts) test enforces five critical rules:
1. HTTP responses must be validated with `apiRequest` or `readEnvelope`.
2. No raw `JSON.parse(... ) as` casts at persistence boundaries.
3. Admin code may only use `fetch` for a small allow-list (NDJSON streams, SVG bytes, FormData uploads).
4. Server handlers must use `readValidatedBody`.
5. After `readEnvelope` or `parseJsonResponse`, never cast fields; instead reference the proper TypeBox schema.

```ts
// ❌ Bad – raw cast
const data = JSON.parse(body) as MyType;

// ✅ Good – use TypeBox helper
import { safeParseJson } from '@core/utils/json';
const data = safeParseJson(body, MyTypeSchema);

```

### Error Handling Consistency

The [`no-inline-error-ternary.test.ts`](https://github.com/CoreBunch/Instatic/blob/main/no-inline-error-ternary.test.ts) test requires that every `catch (err)` in admin code extract the message using `getErrorMessage(err, fallback)`, prohibiting manual ternary checks for error messages.

## Authentication and Capability Gating

Security boundaries are enforced through mandatory capability checks.

### Handler Protection

The [`cms-handlers-capability-gated.test.ts`](https://github.com/CoreBunch/Instatic/blob/main/cms-handlers-capability-gated.test.ts) and [`capability-picker-coverage.test.ts`](https://github.com/CoreBunch/Instatic/blob/main/capability-picker-coverage.test.ts) tests ensure that every CMS handler calls a capability check (`requireCapability`, `requireAuthenticatedUser`, etc.) and that capability metadata and client-side lists remain synchronized.

```ts
// ❌ No capability guard
export async function deletePost(req: Request) {
  // …
}

// ✅ Proper guard
export async function deletePost(req: Request) {
  requireCapability(req, 'cms.content.delete');
  // …
}

```

## UI Architecture and Design System

Instatic enforces a strict design system through CSS and component usage rules.

### CSS Token Policies

The [`css-token-policy.test.ts`](https://github.com/CoreBunch/Instatic/blob/main/css-token-policy.test.ts), [`no-css-var-fallbacks.test.ts`](https://github.com/CoreBunch/Instatic/blob/main/no-css-var-fallbacks.test.ts), and [`noTailwindUtilities.test.ts`](https://github.com/CoreBunch/Instatic/blob/main/noTailwindUtilities.test.ts) tests enforce that CSS Modules use only token variables (`var(--token)`) with no raw hex/rgb/hsl values, no fallback values in `var(--x, fallback)`, and absolutely no Tailwind utility classes or dependencies.

```tsx
// ❌ Prohibited
<div className="flex items-center gap-2">...</div>

// ✅ Preferred – CSS Module with token vars
import styles from './MyComponent.module.css';
<div className={styles.container}>...</div>

```

### UI Primitive Requirements

The [`button-primitive-usage.test.ts`](https://github.com/CoreBunch/Instatic/blob/main/button-primitive-usage.test.ts), [`ui-primitives-location.test.ts`](https://github.com/CoreBunch/Instatic/blob/main/ui-primitives-location.test.ts), and related icon tests mandate that all interactive controls use primitives under `src/ui/components/`. Bare `<button>` elements require explicit allow-list justification. Native browser dialogs (`alert`, `confirm`, `prompt`) are banned in favor of built-in `Dialog` and `Toast` components. Icons must be deep-imported from the vendored `pixel-art-icons` package, never from other libraries.

## Admin Routing and Navigation Discipline

Internal navigation consistency is enforced by [`admin-router-usage.test.ts`](https://github.com/CoreBunch/Instatic/blob/main/admin-router-usage.test.ts), which requires all internal navigation in the admin UI to use the custom router (`@admin/lib/routing`). Direct `<a href="/admin…">` links and `react-router-dom` usage are prohibited.

## Editor and Canvas Integrity

The visual editing surface maintains strict structural invariants.

### Canvas and Component Rules

Tests including [`canvasFastRefreshBoundaries.test.ts`](https://github.com/CoreBunch/Instatic/blob/main/canvasFastRefreshBoundaries.test.ts), [`no-circular-dependencies.test.ts`](https://github.com/CoreBunch/Instatic/blob/main/no-circular-dependencies.test.ts), and [`component-system-placement.test.ts`](https://github.com/CoreBunch/Instatic/blob/main/component-system-placement.test.ts) enforce that:
- Component and non-component exports are never mixed in a `.tsx` file.
- The codebase remains free of circular imports.
- Canvas selectors subscribe to the correct slice of state.
- Component insertion always flows through `insertComponentRef`, banning direct tree mutations.

### Page-Tree Mutation Contracts

The [`no-vc-mode-branches-in-mutations.test.ts`](https://github.com/CoreBunch/Instatic/blob/main/no-vc-mode-branches-in-mutations.test.ts) and [`visual-components-mutation-contract.test.ts`](https://github.com/CoreBunch/Instatic/blob/main/visual-components-mutation-contract.test.ts) tests ensure that store actions (`insertNode`, `deleteNode`) never branch on `kind === 'visualComponent'`, and that Visual-Component tree mutations preserve slot-instance / slot-outlet invariants. All mutations funnel through a single entry point to maintain consistent undo/redo history, as verified by [`centralized-site-mutation-history.test.ts`](https://github.com/CoreBunch/Instatic/blob/main/centralized-site-mutation-history.test.ts).

### Spotlight and Keybindings

The [`spotlight-no-direct-store-mutation.test.ts`](https://github.com/CoreBunch/Instatic/blob/main/spotlight-no-direct-store-mutation.test.ts) and [`keybindings-registry-single-source.test.ts`](https://github.com/CoreBunch/Instatic/blob/main/keybindings-registry-single-source.test.ts) tests prohibit Spotlight providers from mutating the editor store directly and mandate that all shortcuts flow through a central registry.

## AI Infrastructure and Security

AI capabilities are isolated and strictly controlled.

### AI Driver Isolation

The [`ai-driver-isolation.test.ts`](https://github.com/CoreBunch/Instatic/blob/main/ai-driver-isolation.test.ts) test bans provider SDKs (`@anthropic-ai/...`, `@openai/...`) except within the MCP server. All AI-tool schemas are defined once with TypeBox and re-exported, enforced by [`ai-tools-typebox-only.test.ts`](https://github.com/CoreBunch/Instatic/blob/main/ai-tools-typebox-only.test.ts) and [`ai-tool-schema-ssot.test.ts`](https://github.com/CoreBunch/Instatic/blob/main/ai-tool-schema-ssot.test.ts).

### Capability and Credential Protection

Every AI handler must check capabilities before performing work ([`ai-handlers-capability-gated.test.ts`](https://github.com/CoreBunch/Instatic/blob/main/ai-handlers-capability-gated.test.ts)), and credentials must never leak in responses ([`ai-credentials-never-leak.test.ts`](https://github.com/CoreBunch/Instatic/blob/main/ai-credentials-never-leak.test.ts)).

## Media and Publishing Pipelines

Content delivery pipelines maintain specific processing orders and isolation guarantees.

### Media Serving Constraints

The [`media-migration-invariants.test.ts`](https://github.com/CoreBunch/Instatic/blob/main/media-migration-invariants.test.ts), [`media-presentation-pipeline.test.ts`](https://github.com/CoreBunch/Instatic/blob/main/media-presentation-pipeline.test.ts), and [`media-storage-no-bytes-in-sandbox.test.ts`](https://github.com/CoreBunch/Instatic/blob/main/media-storage-no-bytes-in-sandbox.test.ts) tests validate that media migrations preserve all variants, `<picture>` and `srcset` generation follows the pipeline, signed URLs are used for downloads, and sandboxed plugins cannot read raw media bytes.

### Publisher Integrity

The [`dispatcher-html-pipeline.test.ts`](https://github.com/CoreBunch/Instatic/blob/main/dispatcher-html-pipeline.test.ts) and [`publish-html-filter-context.test.ts`](https://github.com/CoreBunch/Instatic/blob/main/publish-html-filter-context.test.ts) tests enforce that the HTML pipeline runs in the correct order (sanitize → filters → injections) and that HTML filter plugins receive proper context. Additionally, [`static-artefact-served-before-render.test.ts`](https://github.com/CoreBunch/Instatic/blob/main/static-artefact-served-before-render.test.ts) and [`publish-bumps-cache-version.test.ts`](https://github.com/CoreBunch/Instatic/blob/main/publish-bumps-cache-version.test.ts) ensure static artefacts are served before full renders when possible and that every publish operation bumps the cache version. The [`hole-runtime-asset-route.test.ts`](https://github.com/CoreBunch/Instatic/blob/main/hole-runtime-asset-route.test.ts) verifies the hole runtime route is registered before public routes.

## Site Import and Agent Contracts

Headless operations and AI agents follow strict interface contracts.

### Site Import Isolation

The [`siteImport-headless.test.ts`](https://github.com/CoreBunch/Instatic/blob/main/siteImport-headless.test.ts) test ensures the headless site-import package has zero dependencies on admin UI, server code, or React, guaranteeing it runs in pure Node environments.

### Agent Surface Contracts

The [`agent-no-raw-html-in-reply-rule.test.ts`](https://github.com/CoreBunch/Instatic/blob/main/agent-no-raw-html-in-reply-rule.test.ts), [`agent-system-prompt-no-module-enumeration.test.ts`](https://github.com/CoreBunch/Instatic/blob/main/agent-system-prompt-no-module-enumeration.test.ts), and [`agent-tool-surface.test.ts`](https://github.com/CoreBunch/Instatic/blob/main/agent-tool-surface.test.ts) tests enforce that agent replies remain plain text (no raw HTML/CSS/JSON), system prompts do not enumerate internal modules, and the set of write-tools matches the documented surface exactly.

## Summary

Instatic’s architecture tests form a comprehensive guardrail layer that preserves the codebase’s structural integrity:

- **Module boundaries** are protected through barrel-import discipline and plugin sandboxing.
- **Database portability** is enforced via ANSI-SQL compliance and JSON column conventions.
- **Type safety** is maintained through mandatory TypeBox validation at all boundaries.
- **Security** depends on capability-gated handlers and isolated AI/media pipelines.
- **UI consistency** relies on token-based CSS and primitive component usage.
- **Editor integrity** is preserved through strict canvas and mutation contracts.

Any deviation triggers a failing test during `bun test`, forcing immediate correction at the source.

## Frequently Asked Questions

### What happens when an architecture test fails in Instatic?

When an architecture test fails, the `bun test` command exits with a non-zero status, breaking the build pipeline. Developers must correct the violation—such as replacing a deep import with a barrel import or adding a missing capability check—before the code can be merged, ensuring architectural drift is caught at development time rather than in production.

### Why does Instatic ban Tailwind CSS and enforce CSS Modules?

Instatic bans Tailwind utilities ([`noTailwindUtilities.test.ts`](https://github.com/CoreBunch/Instatic/blob/main/noTailwindUtilities.test.ts)) and enforces CSS Modules with design tokens ([`css-token-policy.test.ts`](https://github.com/CoreBunch/Instatic/blob/main/css-token-policy.test.ts)) to maintain a strict, consistent visual design system that is resilient to refactoring. This prevents utility-class proliferation and ensures all styling values derive from a centralized token source, making theme changes and accessibility updates predictable across the entire application.

### How do the database architecture tests ensure portability between PostgreSQL and SQLite?

The [`db-postgres-isms.test.ts`](https://github.com/CoreBunch/Instatic/blob/main/db-postgres-isms.test.ts) test blocks PostgreSQL-specific syntax like `now()` or `::int`, forcing ANSI-SQL standards, while [`migration-parity.test.ts`](https://github.com/CoreBunch/Instatic/blob/main/migration-parity.test.ts) ensures both dialects share identical migration IDs and ordering. Additionally, [`db-json-column-naming.test.ts`](https://github.com/CoreBunch/Instatic/blob/main/db-json-column-naming.test.ts) standardizes JSON handling by requiring `_json` suffixes, automatically mapping to `jsonb` in PostgreSQL and `text` in SQLite, ensuring schema definitions remain portable across both engines.

### What is the purpose of the barrel-import rule in Instatic's architecture?

The barrel-import rule, enforced by [`no-core-barrel-deep-imports.test.ts`](https://github.com/CoreBunch/Instatic/blob/main/no-core-barrel-deep-imports.test.ts), prevents consumers from importing internal implementation files directly. By forcing all external access through public barrel exports (`@core/page-tree`), Instatic maintains a stable public API surface, allowing internal refactoring without breaking downstream consumers and preventing accidental coupling to private implementation details.