Skip to content

Architecture โ€‹

PerchIQX is built on Hexagonal Architecture (Ports and Adapters) with a strong emphasis on Domain-Driven Design and Semantic Intent patterns. This architecture ensures maintainability, testability, and semantic clarity.

n::: tip Research Foundation PerchIQX implements Hexagonal Architecture with semantic intent - where domain logic is expressed through intent-rich natural language that serves as both documentation and implementation guide. This approach treats semantic meaning as architectural infrastructure.

๐Ÿ“š Read the foundational research: Semantic Intent as Single Source of Truth :::

Architectural Overview โ€‹

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚                   Presentation Layer                     โ”‚
โ”‚              (MCP Server - Protocol Handling)            โ”‚
โ”‚                                                           โ”‚
โ”‚  - Tool registration and routing                         โ”‚
โ”‚  - Request/response transformation                       โ”‚
โ”‚  - MCP protocol compliance                               โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
                     โ”‚
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ–ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚                  Application Layer                       โ”‚
โ”‚        (Use Cases - Schema Analysis Orchestration)      โ”‚
โ”‚                                                           โ”‚
โ”‚  - AnalyzeSchemaUseCase                                  โ”‚
โ”‚  - GetRelationshipsUseCase                               โ”‚
โ”‚  - ValidateSchemaUseCase                                 โ”‚
โ”‚  - SuggestOptimizationsUseCase                           โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
                     โ”‚
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ–ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚                    Domain Layer                          โ”‚
โ”‚     (Schema Entities, Relationship Logic, Services)     โ”‚
โ”‚                  Pure Business Logic                     โ”‚
โ”‚                                                           โ”‚
โ”‚  Entities:                                               โ”‚
โ”‚  - DatabaseSchema, TableInfo, Column                     โ”‚
โ”‚  - ForeignKey, Index, Relationship                       โ”‚
โ”‚                                                           โ”‚
โ”‚  Services:                                               โ”‚
โ”‚  - SchemaAnalyzer                                        โ”‚
โ”‚  - RelationshipAnalyzer                                  โ”‚
โ”‚  - OptimizationService                                   โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
                     โ”‚
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ–ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚                Infrastructure Layer                      โ”‚
โ”‚       (Cloudflare D1 REST API, HTTP Client)             โ”‚
โ”‚                Technical Adapters                        โ”‚
โ”‚                                                           โ”‚
โ”‚  - CloudflareD1Repository (data access)                  โ”‚
โ”‚  - CloudflareAPIClient (HTTP)                            โ”‚
โ”‚  - InMemoryCacheProvider (caching)                       โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

Layer Responsibilities โ€‹

1. Presentation Layer โ€‹

Purpose: Handle MCP protocol communication

Components:

  • D1DatabaseMCPServer - Main MCP server class
  • Tool handlers for each MCP tool
  • Request validation and response formatting

Key Principles:

  • Protocol-agnostic domain layer
  • Thin translation layer
  • No business logic
typescript
// src/presentation/mcp/MCPServer.ts
export class D1DatabaseMCPServer {
  async handleAnalyzeSchema(params: AnalyzeSchemaParams) {
    // 1. Validate MCP request
    // 2. Call use case
    // 3. Format MCP response
  }
}

2. Application Layer โ€‹

Purpose: Orchestrate domain services to fulfill use cases

Components:

  • AnalyzeSchemaUseCase - Coordinate schema analysis
  • GetRelationshipsUseCase - Extract relationships
  • ValidateSchemaUseCase - Run schema validation
  • SuggestOptimizationsUseCase - Generate recommendations

Key Principles:

  • Use case per tool
  • Coordinate domain services
  • No business logic (delegate to domain)
typescript
// src/application/use-cases/AnalyzeSchemaUseCase.ts
export class AnalyzeSchemaUseCase {
  async execute(environment: Environment, options: AnalyzeOptions) {
    // 1. Fetch schema from repository
    // 2. Analyze via SchemaAnalyzer service
    // 3. Return domain result
  }
}

3. Domain Layer โ€‹

Purpose: Pure business logic with no external dependencies

Entities:

  • DatabaseSchema - Root aggregate
  • TableInfo - Table metadata
  • Column - Column definition
  • ForeignKey - Foreign key relationship
  • Index - Index definition
  • Relationship - Analyzed relationship

Services:

  • SchemaAnalyzer - Schema introspection logic
  • RelationshipAnalyzer - Relationship extraction
  • OptimizationService - Recommendation engine

Key Principles:

  • No infrastructure dependencies
  • Semantic validation
  • Observable property anchoring
typescript
// src/domain/entities/TableInfo.ts
export class TableInfo {
  // Semantic validation
  hasPrimaryKey(): boolean {
    return this.columns.some(c => c.isPrimaryKey);
  }

  // Observable anchoring
  getForeignKeys(): ForeignKey[] {
    return this.foreignKeys;  // Direct observation
  }
}

4. Infrastructure Layer โ€‹

Purpose: External system integration (Cloudflare D1 API)

Components:

  • CloudflareD1Repository - D1 data access
  • CloudflareAPIClient - HTTP client
  • InMemoryCacheProvider - Response caching
  • Configuration classes

Key Principles:

  • Implement domain interfaces (ports)
  • Hide external API details
  • Handle technical concerns (retry, caching)
typescript
// src/infrastructure/adapters/CloudflareD1Repository.ts
export class CloudflareD1Repository implements ICloudflareD1Repository {
  async fetchSchema(environment: Environment): Promise<DatabaseSchema> {
    // 1. Call Cloudflare D1 REST API
    // 2. Transform to domain entities
    // 3. Return DatabaseSchema
  }
}

Dependency Flow โ€‹

Presentation โ†’ Application โ†’ Domain โ† Infrastructure
                              โ†‘
                        (Interfaces only)

Key Rules:

  1. Domain has no dependencies
  2. Application depends only on domain
  3. Infrastructure implements domain interfaces
  4. Presentation uses application use cases

Semantic Intent Principles โ€‹

1. Semantic Over Structural โ€‹

Decisions based on meaning, not metrics:

typescript
// โœ… SEMANTIC: Based on observable schema properties
const needsIndex = table.hasForeignKey() && !table.hasIndexOnForeignKey();

// โŒ STRUCTURAL: Based on technical metrics
const needsIndex = table.rowCount > 10000 && table.queryCount > 100;

2. Intent Preservation โ€‹

Environment semantics maintained through transformations:

typescript
// โœ… Environment intent preserved
const schema = await fetchSchema(Environment.PRODUCTION);
// Analysis preserves "production" context - no overrides

// โŒ Intent lost through transformation
const schema = await fetchSchema("prod"); // String loses semantic meaning

3. Observable Anchoring โ€‹

Decisions anchored to directly observable properties:

typescript
// โœ… Based on observable schema markers
const relationships = extractForeignKeys(sqliteMaster);

// โŒ Based on inferred behavior
const relationships = inferFromQueryPatterns(logs);

Testing Strategy โ€‹

398 tests across all layers:

  • โœ… Domain Layer: 212 tests (entities, services, validation)
  • โœ… Infrastructure Layer: 64 tests (D1 adapter, API client, config)
  • โœ… Application Layer: 35 tests (use cases, orchestration)
  • โœ… Presentation Layer: 13 tests (MCP server, tool routing)
  • โœ… Integration: 15 tests (end-to-end flows)
  • โœ… Value Objects: 59 tests (Environment, immutability)

Test Isolation โ€‹

Each layer tested independently:

typescript
// Domain tests - no mocks needed (pure logic)
describe('TableInfo', () => {
  it('detects missing primary key', () => {
    const table = new TableInfo('users', [/* columns */]);
    expect(table.hasPrimaryKey()).toBe(false);
  });
});

// Infrastructure tests - mock HTTP client
describe('CloudflareD1Repository', () => {
  it('fetches schema from API', async () => {
    mockAPIClient.get.mockResolvedValue(mockResponse);
    const schema = await repository.fetchSchema(Environment.DEV);
    expect(schema).toBeInstanceOf(DatabaseSchema);
  });
});

Directory Structure โ€‹

src/
โ”œโ”€โ”€ domain/              # Business logic (entities, services)
โ”‚   โ”œโ”€โ”€ entities/        # DatabaseSchema, TableInfo, Column, etc.
โ”‚   โ”œโ”€โ”€ services/        # SchemaAnalyzer, RelationshipAnalyzer, etc.
โ”‚   โ”œโ”€โ”€ repositories/    # Port interfaces
โ”‚   โ””โ”€โ”€ value-objects/   # Environment enum
โ”œโ”€โ”€ application/         # Use cases and orchestration
โ”‚   โ”œโ”€โ”€ use-cases/       # AnalyzeSchema, GetRelationships, etc.
โ”‚   โ””โ”€โ”€ ports/           # Cache provider interface
โ”œโ”€โ”€ infrastructure/      # External adapters
โ”‚   โ”œโ”€โ”€ adapters/        # CloudflareD1Repository, Cache
โ”‚   โ”œโ”€โ”€ config/          # CloudflareConfig, DatabaseConfig
โ”‚   โ””โ”€โ”€ http/            # CloudflareAPIClient
โ”œโ”€โ”€ presentation/        # MCP protocol layer
โ”‚   โ””โ”€โ”€ mcp/             # D1DatabaseMCPServer
โ””โ”€โ”€ index.ts             # Composition root (DI)

Composition Root โ€‹

Dependency Injection at application startup:

typescript
// src/index.ts
async function main() {
  // Infrastructure Layer
  const apiClient = new CloudflareAPIClient(config);
  const repository = new CloudflareD1Repository(apiClient, dbConfig);
  const cache = new InMemoryCacheProvider();

  // Domain Services
  const schemaAnalyzer = new SchemaAnalyzer();
  const relationshipAnalyzer = new RelationshipAnalyzer();

  // Application Use Cases
  const analyzeSchemaUseCase = new AnalyzeSchemaUseCase(
    repository, schemaAnalyzer, cache
  );

  // Presentation Layer
  const mcpServer = new D1DatabaseMCPServer(
    analyzeSchemaUseCase,
    // ... other use cases
  );

  await mcpServer.start();
}

Design Patterns โ€‹

Repository Pattern โ€‹

Abstract data access behind interface:

typescript
// Domain defines interface
interface ICloudflareD1Repository {
  fetchSchema(env: Environment): Promise<DatabaseSchema>;
}

// Infrastructure implements
class CloudflareD1Repository implements ICloudflareD1Repository {
  // Implementation details
}

Service Layer โ€‹

Business logic in domain services:

typescript
class SchemaAnalyzer {
  analyzeSchema(schema: DatabaseSchema): SchemaAnalysis {
    // Pure domain logic
  }
}

Value Objects โ€‹

Immutable semantic values:

typescript
enum Environment {
  DEVELOPMENT = "development",
  STAGING = "staging",
  PRODUCTION = "production"
}

Key Benefits โ€‹

1. Testability โ€‹

  • Pure domain logic (no mocks needed)
  • Interface-based infrastructure (easy to mock)
  • Independent layer testing

2. Maintainability โ€‹

  • Clear separation of concerns
  • Semantic clarity in domain
  • Easy to locate and modify logic

3. Flexibility โ€‹

  • Swap infrastructure (D1 โ†’ PostgreSQL)
  • Change protocols (MCP โ†’ REST API)
  • Domain remains unchanged

4. AI-Friendly โ€‹

  • Semantic intent clear in code
  • Natural language mapping to use cases
  • Observable properties for reasoning

Further Reading โ€‹