Authentication Invariants
JWT-INV-001: Token Structure
Rule: All JWTs MUST contain required claims Required Claims:JWT-INV-002: User Ownership
Rule:user_id extracted from JWT sub claim MUST match resource owner for mutations
Applies To: Thread updates, thread deletions, share endpoint
Enforcement:
JWT-INV-003: User Sync Idempotency
Rule: User sync MUST be idempotent (UPSERT operation) Constraint: Multiple sync calls with sameuser_id do not create duplicates
SQL Guarantee:
Database Invariants
DB-INV-001: UUID Primary Keys
Rule: All primary keys MUST be UUIDs (RFC 4122 v4) Tables: users, threads, thread_messages, comparisons, model_votes, ai_models Generation:uuid_generate_v4() (database) or Guid.NewGuid() (C#)
Rationale:
- Globally unique without coordination
- 2^122 possible values (collision probability negligible)
- URL-safe identifiers
DB-INV-002: Timestamp Presence
Rule: All tables MUST havecreated_at timestamp
Constraint: created_at defaults to NOW() on insert, never null
Enforcement:
created_at never updated after insert
DB-INV-003: Cascade Deletion
Rule: Foreign key deletions MUST cascade or nullify (no orphans) Cascade Paths:DB-INV-004: UPSERT Idempotency
Rule: User sync operations MUST be idempotent Guarantee: Running sync N times ≡ Running sync 1 time Implementation:API Compatibility Invariants
API-INV-001: Response Envelope
Rule: All JSON responses MUST use standard envelope Success Format:API-INV-002: Error Code Stability
Rule: Error codes MUST NOT change meaning across versions Stable Codes:UNAUTHORIZED: Missing/invalid JWTFORBIDDEN: Valid JWT but insufficient permissionsINVALID_REQUEST: Validation failurePROVIDER_ERROR: AI provider failureNOT_FOUND: Resource does not exist
API-INV-003: ISO8601 Timestamps
Rule: All datetime fields MUST use ISO8601 format with UTC timezone Format:YYYY-MM-DDTHH:mm:ss.sssZ
Example: 2024-01-15T10:30:00.000Z
Enforcement:
API-INV-004: Pagination Limits
Rule: List endpoints MUST enforce maximum page size Limits:- Default: 50 items
- Maximum: 500 items
- Minimum: 1 item
Realtime Protocol Invariants
SSE-INV-001: Event Format
Rule: All SSE events MUST follow format:data: {json}\n\n
Structure:
- Prefix:
data: - JSON: Single-line (no embedded newlines)
- Suffix:
\n\n(double newline)
SSE-INV-002: Unidirectional Flow
Rule: SSE communication MUST be server→client only Constraint: Client cannot send data during SSE stream Protocol: HTTP long-polling, not bidirectional WebSocket Implication: All request parameters sent in initial HTTP POSTSSE-INV-003: Event Type Contract
Rule: Event types MUST be from defined set Allowed Types:ai.stream.startai.stream.deltaai.stream.doneai.error
SSE-INV-004: Event Ordering
Rule: SSE events MUST follow lifecycle order Valid Sequence:Idempotency Invariants
IDEMP-INV-001: GET Request Safety
Rule: GET requests MUST NOT mutate state Guarantee: Multiple identical GET calls produce same result Applies To: All read endpoints Counter-example: User sync executes UPSERT even on GET (acceptable side effect)IDEMP-INV-002: POST Chat Non-Idempotency
Rule: Chat requests MUST NOT be idempotent Rationale: Each request should generate fresh AI response, not cached result Behavior: Identical prompts → different responses (due to temperature > 0) Constraint: No response caching based on prompt hashIDEMP-INV-003: User Sync Idempotency
Rule: POST /api/users/sync MUST be idempotent Guarantee: Multiple sync calls with same user data → same database state Mechanism: UPSERT operationIDEMP-INV-004: Vote Non-Idempotency
Rule: Vote submissions MUST allow duplicates Rationale: Enables vote changes without explicit DELETE+INSERT Design: Insert new row for each vote (no UPDATE on existing vote) Query Impact: Vote statistics aggregate all votes (duplicates counted)IDEMP-INV-005: DELETE Idempotency
Rule: DELETE requests MUST be idempotent Guarantee: Deleting already-deleted resource returns success Implementation: Check if resource exists, return 200 regardlessProvider Invariants
PROV-INV-001: 45-Second Timeout
Rule: Each provider attempt MUST timeout after 45 seconds Enforcement:PROV-INV-002: Fallback Chain
Rule: Provider failures MUST follow defined fallback order Chain:- Groq with selected model
- Groq with
llama-3.3-70b-versatile - Bytez provider
- Throw exception
PROV-INV-003: Independent Dual-Chat Fallback
Rule: In dual-chat, each model has independent fallback chain Guarantee: Model 1 failure does not affect Model 2 execution Parallel Execution:Task.WhenAll(task1, task2)
Partial Results: If one succeeds and one fails, return single-model response
Security Invariants
SEC-INV-001: JWT Signature Validation
Rule: All authenticated endpoints MUST validate JWT signature Algorithm: HS256 Secret:JWT_SECRET environment variable
Validation: ASP.NET Core JWT middleware (automatic)
Development Exception: Signature validation may be skipped if JWT_SECRET not set (logged as warning)
SEC-INV-002: HTTPS in Production
Rule: Production deployments MUST use HTTPS Rationale: JWT tokens transmitted in Authorization header (bearer token security) Enforcement: Infrastructure-level (reverse proxy/load balancer)SEC-INV-003: No Service Role Exposure
Rule: Supabase service role key MUST NOT be exposed to clients Storage: Server-side environment variable only Client Keys: Clients use Supabase anon key (limited permissions) Backend Usage: Service role for unrestricted database access (bypasses RLS)Data Consistency Invariants
DATA-INV-001: Thread Ownership
Rule:thread.user_id MUST match creator’s JWT sub at creation
Immutability: user_id cannot change after thread creation
Enforcement: Set from JWT claim, no UPDATE allowed
DATA-INV-002: Comparison Integrity
Rule: Comparison models MUST be different Constraint:model1_id != model2_id
Validation:
DATA-INV-003: Vote Choice Validity
Rule: Vote choice MUST be from defined set Valid Choices:left, right, tie, both-bad
Enforcement:
DATA-INV-004: Message-Comparison Link
Rule: Thread message withcomparison_id MUST reference valid comparison
Foreign Key: thread_messages.comparison_id → comparisons.comparison_id
Cascade: If comparison deleted, message’s comparison_id set to NULL
Violation Detection
Monitoring Invariant Violations
Health Checks: Monitor API response times for timeout violations Database Logs: Check foreign key constraint violation errors Application Logs:UnauthorizedException count indicates auth invariant violations
Metrics:
- 401 error rate (JWT validation failures)
- 403 error rate (ownership violations)
- 500 error rate (provider timeout violations)
Next Steps
Request Lifecycle
How invariants are enforced in execution
Database Schema
Schema-level constraint enforcement