# FraiseQL Architecture Decisions

This directory contains the evolution of architectural decisions for FraiseQL, documenting the thinking process and trade-offs for major design choices.

## Mutation Response Architecture Evolution

### ADR-001: GraphQL Mutation Response - Initial Plan
**File**: `001_graphql_mutation_response_initial_plan.md`
**Date**: 2025-10-16
**Status**: Superseded by ADR-002

**Decision**: Create GraphQL-native mutation responses with three-layer transformation (PostgreSQL → Python → Rust → GraphQL).

**Context**:
- Original CDC-style response format incompatible with GraphQL cache normalization
- Apollo Client, Relay, URQL require `id` + `__typename` for cache updates
- Python layer would orchestrate transformation

**Why Superseded**:
- Introduced unnecessary Python parsing layer
- User insight: "could there be even more direct path for the data?"

---

### ADR-002: Ultra-Direct Mutation Path
**File**: `002_ultra_direct_mutation_path.md`
**Date**: 2025-10-16
**Status**: Superseded by ADR-003

**Decision**: Eliminate Python parsing, use PostgreSQL JSONB::text → Rust → Client directly.

**Key Innovation**:
- Reuse existing query path (RawJSONResult)
- PostgreSQL returns JSONB as text string (no Python dict parsing)
- Rust transformer handles camelCase + `__typename` injection
- 10-80x faster than Python-based parsing

**Why Superseded**:
- Didn't address CDC event logging requirements
- User requirement: "could we still keep debezium compatible logging function?"

---

### ADR-003: Dual-Path Architecture (Ultra-Direct + CDC)
**File**: `003_dual_path_cdc_pattern.md`
**Date**: 2025-10-16
**Status**: Superseded by ADR-005

**Decision**: Implement two independent paths within same transaction:
- **Path A (Client)**: Ultra-direct PostgreSQL → Rust → Client (~51ms)
- **Path B (CDC)**: Async event logging with `PERFORM` (~1ms, doesn't block client)

**Key Innovation**:
- PostgreSQL `PERFORM` executes functions asynchronously within transaction
- CDC logging doesn't block client response
- Both paths maintain ACID guarantees

**Architecture**:
```sql
-- Build response
v_response := build_mutation_response(...);

-- Log CDC event (ASYNC - doesn't block!)
PERFORM log_cdc_event(...);

-- Return immediately
RETURN v_response;
```

**Why Superseded**:
- Two separate operations (build response + log event)
- Risk of divergence between client response and CDC event
- User insight: "could we simplify by making the direct client response a part of the CDC event logging?"

---

### ADR-004: Dual-Path Implementation Examples
**File**: `004_dual_path_implementation_examples.md`
**Date**: 2025-10-16
**Status**: Reference Implementation (Superseded Pattern)

**Content**: Complete implementation examples of ADR-003 dual-path pattern:
- Example 1: Create Customer (simple entity)
- Example 2: Update Order (complex entity with validation)
- Example 3: Delete Order (with business rules)
- Complete CDC event formats
- Performance characteristics
- Apollo Client cache integration

**Value**:
- Demonstrates thinking process
- Shows how dual-path would have worked
- Reference for understanding ADR-005 simplification

---

### ADR-005: Simplified Single-Source CDC ✅ CURRENT
**File**: `005_simplified_single_source_cdc.md`
**Date**: 2025-10-16
**Status**: ✅ **ACTIVE - IMPLEMENT THIS**

**Decision**: Store both client response AND CDC data in single event, Rust extracts `client_response` field.

**Key Simplification**:
```sql
-- Single INSERT with everything
v_event_id := log_mutation_event(
    client_response,  -- What client receives
    before_state,     -- What CDC consumers need
    after_state,      -- What CDC consumers need
    metadata          -- Audit trail
);

-- Return client_response field directly
RETURN (SELECT client_response::text FROM mutation_events WHERE event_id = v_event_id);
```

**Schema**:
```sql
CREATE TABLE app.mutation_events (
    event_id BIGSERIAL PRIMARY KEY,

    -- What client receives (extracted by Rust)
    client_response JSONB NOT NULL,

    -- What CDC consumers need
    before_state JSONB,
    after_state JSONB,

    -- Audit metadata
    metadata JSONB,
    source JSONB,
    event_timestamp TIMESTAMPTZ DEFAULT NOW(),
    transaction_id BIGINT
);
```

**Benefits**:
1. ✅ **Single Source of Truth**: One INSERT contains everything
2. ✅ **Simpler Code**: No separate `build_mutation_response()` helper
3. ✅ **Better Audit**: CDC log contains exact client response
4. ✅ **Same Performance**: < 0.1ms overhead for event_id lookup
5. ✅ **More Debuggable**: Replay exact client responses from CDC log

**Trade-offs**:
- Slightly larger events (~50-100 bytes per mutation) - negligible
- Requires SELECT after INSERT - < 0.1ms with PRIMARY KEY lookup

**Why This is Final**:
- Maximum simplicity with no performance cost
- Eliminates risk of client response vs CDC data diverging
- Perfect audit trail (see exactly what client received)
- Natural evolution from ADR-003 dual-path concept

---

## Decision Timeline

```
ADR-001 (Initial Plan)
   ↓
   └─→ User: "Use existing Rust transformer, simplify data path"
   ↓
ADR-002 (Ultra-Direct Path)
   ↓
   └─→ User: "Could we still keep CDC logging with ultra-fast returns?"
   ↓
ADR-003 (Dual-Path: Client + CDC)
   ↓
   └─→ User: "Could we simplify by making client response part of CDC event?"
   ↓
   └─→ User: "Store exact payload in dedicated field, no conditionals"
   ↓
ADR-005 (Single-Source CDC) ✅ FINAL
```

## Key Lessons

### 1. User-Driven Simplification
Each ADR was refined based on user insights:
- "Could there be even more direct path?" → Eliminated Python parsing
- "Could we keep CDC logging?" → Dual-path pattern
- "Could we simplify further?" → Single source of truth

### 2. Progressive Refinement
- Started with 3 layers (PostgreSQL → Python → Rust)
- Eliminated Python layer (PostgreSQL → Rust)
- Added CDC logging (dual-path)
- Unified into single source (one INSERT)

### 3. Performance Maintained Throughout
- ADR-002: 10-80x faster than Python parsing
- ADR-003: ~51ms client response (CDC doesn't block)
- ADR-005: Same performance + simpler code

### 4. Architecture Drivers
- **GraphQL Cache Compatibility**: `id` + `__typename` requirement
- **Ultra-Direct Path**: Zero Python parsing overhead
- **CDC Event Streaming**: Debezium-compatible audit trail
- **Single Source of Truth**: Eliminate divergence risk

## Implementation Status

- [x] ADR-001: Documented
- [x] ADR-002: Documented
- [x] ADR-003: Documented + Reference implementation created
- [x] ADR-004: Complete examples documented
- [x] ADR-005: Designed and documented
- [ ] ADR-005: Implement new CDC schema
- [ ] ADR-005: Update mutation functions to use simplified pattern
- [ ] ADR-005: Implement Python layer (execute_function_raw_json)
- [ ] ADR-005: Test end-to-end with GraphQL client

## Next Steps

1. Implement ADR-005 simplified CDC schema
2. Update ecommerce_api mutation functions
3. Update blog_api mutation functions
4. Implement Python layer changes
5. Benchmark performance vs old mutation system
6. Document CDC consumer patterns
