Docs /architecture/design-decisions

Design Decisions

Key architectural and engineering decisions with rationale

📋 Overview

This document records important decisions made during the development of Izri. Each decision includes context, alternatives considered, and reasoning. This helps current and future team members understand why things are the way they are.

🎯 Decision Framework

When making significant decisions, we consider:

  • Technical Merit: Does it solve the problem well?
  • Developer Experience: Is it enjoyable to work with?
  • Performance: Does it meet our performance goals?
  • Maintainability: Can we maintain it long-term?
  • Community: Is there good community support?
  • Cost: Is it sustainable financially?

🏗️ Architecture Decisions

React Router v7 Over Next.js

Decision: Use React Router v7 for the frontend framework

Context: Needed a modern React framework with SSR capabilities

Alternatives Considered:

  • Next.js 14/15
  • Remix (now merged with React Router)
  • Create React App
  • Astro

Reasoning:

Pros of React Router v7:

  • ✅ Familiar routing API (used by millions)
  • ✅ No vendor lock-in (unlike Vercel/Next.js)
  • ✅ File-based routing with excellent DX
  • ✅ SSR ready without complexity
  • ✅ Smaller bundle sizes
  • ✅ More flexible deployment options
  • ✅ Evolution of Remix (battle-tested patterns)

Cons of Next.js:

  • ❌ Vercel-optimized (lock-in concerns)
  • ❌ Heavier bundle
  • ❌ App Router complexity
  • ❌ More opinionated
  • ❌ Harder to deploy outside Vercel

Outcome: React Router v7 gives us the benefits of a modern framework without the vendor lock-in

Status: ✅ Implemented and working well


tRPC Over REST and GraphQL

Decision: Use tRPC for API communication

Context: Needed type-safe API layer between frontend and backend

Alternatives Considered:

  • Traditional REST APIs
  • GraphQL with Apollo
  • gRPC with protobuf

Reasoning:

Pros of tRPC:

  • ✅ End-to-end type safety (no codegen)
  • ✅ Automatic type inference
  • ✅ Minimal boilerplate
  • ✅ Built-in validation (Zod)
  • ✅ Excellent DX (autocomplete everywhere)
  • ✅ No schema files to maintain
  • ✅ WebSocket support

Cons of Alternatives:

  • REST: No type safety, manual validation, lots of boilerplate
  • GraphQL: Code generation overhead, schema-first approach, complexity
  • gRPC: Protocol buffers, not web-friendly, overkill

Trade-offs:

  • ⚠️ Requires TypeScript monorepo (acceptable for us)
  • ⚠️ Less suitable for public APIs (we'll add REST later if needed)

Outcome: Perfect fit for our monorepo architecture

Status: ✅ Implemented, extremely productive


Drizzle ORM Over Prisma

Decision: Use Drizzle ORM for database access

Context: Needed a TypeScript ORM for PostgreSQL

Alternatives Considered:

  • Prisma
  • TypeORM
  • Kysely
  • Raw SQL with pg

Reasoning:

Pros of Drizzle:

  • ✅ Zero runtime overhead
  • ✅ SQL-like API (familiar)
  • ✅ Full TypeScript inference
  • ✅ No code generation step
  • ✅ Edge runtime compatible
  • ✅ Drizzle Studio (visual DB tool)
  • ✅ Simple migrations

Cons of Prisma:

  • ❌ 4MB+ runtime overhead
  • ❌ Custom DSL (less familiar)
  • ❌ Code generation required
  • ❌ Not edge-compatible
  • ❌ Slower query performance

Performance:

Drizzle: ~1ms query time
Prisma:  ~4ms query time (includes runtime overhead)

Outcome: Drizzle is faster, lighter, and more TypeScript-native

Status: ✅ Implemented, excellent DX


Hono Over Express/Fastify

Decision: Use Hono for the HTTP server

Context: Needed a fast, modern web framework

Alternatives Considered:

  • Express.js
  • Fastify
  • Koa
  • Elysia

Reasoning:

Pros of Hono:

  • ✅ Fastest Node.js framework (benchmarks)
  • ✅ Express-like API (familiar)
  • ✅ First-class TypeScript support
  • ✅ Edge runtime compatible
  • ✅ Tiny bundle (~10KB)
  • ✅ Rich middleware ecosystem

Cons of Alternatives:

  • Express: Slow, old architecture, poor TypeScript support
  • Fastify: Good but more complex, heavier
  • Koa: Less active, smaller ecosystem

Benchmarks (requests/sec):

Hono:    ~50,000
Fastify: ~45,000
Express: ~15,000

Outcome: Hono provides best performance with excellent DX

Status: ✅ Implemented


Monorepo with pnpm + Turbo

Decision: Use pnpm workspaces with Turbo for monorepo management

Context: Needed to share code between frontend, backend, and packages

Alternatives Considered:

  • npm workspaces + Nx
  • Yarn workspaces + Lerna
  • Separate repositories

Reasoning:

Pros of pnpm + Turbo:

  • ✅ Fastest package manager (3x faster than npm)
  • ✅ Efficient disk usage (content-addressable storage)
  • ✅ Strict dependency resolution
  • ✅ Turbo's intelligent caching
  • ✅ Simple configuration
  • ✅ Great DX

Performance:

pnpm install:     ~15s
npm install:      ~45s
yarn install:     ~30s

pnpm build (cached):  <5s
pnpm build (clean):   ~20s

Outcome: Significant productivity gains from fast installs and builds

Status: ✅ Implemented


🔐 Authentication Decisions

Lucia Over NextAuth

Decision: Use Lucia for authentication

Context: Needed flexible authentication solution

Alternatives Considered:

  • NextAuth.js / Auth.js
  • Passport.js
  • Custom JWT solution
  • Supabase Auth

Reasoning:

Pros of Lucia:

  • ✅ Framework-agnostic
  • ✅ Full control over database schema
  • ✅ TypeScript-first
  • ✅ No magic, explicit code
  • ✅ Flexible session management
  • ✅ Multiple providers supported

Cons of NextAuth:

  • ❌ Next.js specific
  • ❌ Opinionated database schema
  • ❌ Hidden complexity
  • ❌ Harder to customize

Outcome: Lucia gives us flexibility without framework lock-in

Status: ✅ Implemented (Better Auth being explored as alternative)


💾 Database Decisions

PostgreSQL Over MySQL/MongoDB

Decision: Use PostgreSQL 15 as primary database

Context: Needed reliable, feature-rich database

Alternatives Considered:

  • MySQL
  • MongoDB
  • SQLite (for simplicity)

Reasoning:

Pros of PostgreSQL:

  • ✅ ACID compliance
  • ✅ JSONB for flexible schemas
  • ✅ Advanced indexing (GiST, GIN)
  • ✅ Full-text search
  • ✅ Rich extension ecosystem
  • ✅ Excellent performance
  • ✅ Strong community

Use Cases:

  • Relational data (users, projects, test runs)
  • JSONB for flexible data (test results, analysis)
  • Full-text search (future feature)

Outcome: PostgreSQL provides everything we need

Status: ✅ Implemented


Redis for Caching and Sessions

Decision: Use Redis for caching and session storage

Context: Needed fast session storage and caching layer

Alternatives Considered:

  • In-memory sessions (not scalable)
  • Database-backed sessions (slower)
  • Memcached

Reasoning:

Pros of Redis:

  • ✅ Sub-millisecond latency
  • ✅ Rich data structures
  • ✅ Pub/sub support
  • ✅ Persistent storage option
  • ✅ Battle-tested at scale

Use Cases:

  • Session storage (Lucia)
  • API response caching
  • Rate limiting (planned)
  • Real-time features (planned)

Outcome: Redis is industry standard for these use cases

Status: ✅ Implemented


🤖 AI Service Decisions

Python FastAPI for AI Service

Decision: Use Python with FastAPI for AI/ML service

Context: Needed to integrate AI capabilities for code analysis

Alternatives Considered:

  • Node.js with TensorFlow.js
  • Go with ML libraries
  • Keep everything TypeScript

Reasoning:

Pros of Python:

  • ✅ Best AI/ML ecosystem (PyTorch, LangChain, etc.)
  • ✅ Rich code analysis tools (tree-sitter, AST parsers)
  • ✅ Mature scientific computing stack
  • ✅ FastAPI provides excellent performance
  • ✅ Async/await support

Why FastAPI:

  • ✅ Fast (comparable to Node.js)
  • ✅ Automatic OpenAPI docs
  • ✅ Type hints with Pydantic
  • ✅ Modern Python async
  • ✅ Easy to deploy

Communication:

  • HTTP REST between TypeScript API and Python service
  • Async job-based processing
  • Clear service boundaries

Outcome: Python is the right tool for AI, FastAPI makes it web-friendly

Status: ✅ Implemented


🎨 Frontend Decisions

Tailwind CSS Over CSS-in-JS

Decision: Use Tailwind CSS for styling

Context: Needed styling approach for rapid UI development

Alternatives Considered:

  • Styled Components
  • Emotion
  • CSS Modules
  • Vanilla CSS

Reasoning:

Pros of Tailwind:

  • ✅ Rapid development
  • ✅ Consistent design system
  • ✅ No naming decisions
  • ✅ Purged CSS (small bundle)
  • ✅ Excellent tooling
  • ✅ Great IntelliSense

Cons of CSS-in-JS:

  • ❌ Runtime overhead
  • ❌ Larger bundle sizes
  • ❌ Hydration issues
  • ❌ Complex build setup

Outcome: Tailwind provides best DX and performance

Status: ✅ Implemented


shadcn/ui Over Component Libraries

Decision: Use shadcn/ui (copy-paste components)

Context: Needed accessible, customizable UI components

Alternatives Considered:

  • Material UI
  • Chakra UI
  • Radix UI (raw)
  • Build from scratch

Reasoning:

Pros of shadcn/ui:

  • ✅ You own the code (no package dependency)
  • ✅ Fully customizable
  • ✅ Accessible by default (Radix UI)
  • ✅ Tailwind-first
  • ✅ Modern, beautiful design
  • ✅ No bundle bloat

Approach:

# Copy component into your project
npx shadcn@latest add button

# Now it's your code, modify as needed

Outcome: Best of both worlds - pre-built + fully customizable

Status: ✅ Implemented


🚀 Deployment Decisions

Docker for Development and Production

Decision: Use Docker Compose for local dev, containers for production

Context: Needed consistent environments across machines

Alternatives Considered:

  • Local PostgreSQL/Redis installation
  • Vagrant
  • Development-only (skip Docker)

Reasoning:

Pros of Docker:

  • ✅ Consistent across machines
  • ✅ Easy onboarding (one command)
  • ✅ Production parity
  • ✅ Service isolation
  • ✅ Easy cleanup

Docker Compose for Dev:

services:
  postgres:
    image: postgres:15-alpine
  redis:
    image: redis:7-alpine

Outcome: Docker simplifies development significantly

Status: ✅ Implemented


🔧 Development Tool Decisions

Biome for Formatting and Linting

Decision: Transitioning from ESLint+Prettier to Biome

Context: Needed fast formatting and linting

Reasoning:

Pros of Biome:

  • ✅ 10x faster than ESLint+Prettier
  • ✅ Single tool (replaces two)
  • ✅ Written in Rust
  • ✅ Compatible with ESLint/Prettier configs
  • ✅ Zero config out of the box

Performance:

Biome:              ~0.5s
ESLint + Prettier:  ~5s

Status: 🚧 In progress (ESLint still used for some rules)


📊 Privacy Principles

Metadata-First Analysis

Decision: Analyze repository metadata, not code contents

Context: Users concerned about code privacy

Principles:

  1. Metadata First: Collect structure, sizes, languages, frameworks
  2. Skip Binary Files: No images, videos, compiled code
  3. Ignore Build Dirs: Skip node_modules, dist, .git, etc.
  4. Optional Hashing: Size-capped (1MB), can be disabled
  5. Shallow Clone: --depth=1 by default
  6. User Control: Users can configure what's analyzed

What We Collect:

  • ✅ File paths and sizes
  • ✅ File extensions
  • ✅ Language detection
  • ✅ Framework detection
  • ✅ Dependency file contents (package.json)

What We Don't Collect:

  • ❌ Source code contents (unless explicitly requested)
  • ❌ Commit history
  • ❌ Author information
  • ❌ Large files (>1MB)

Outcome: Privacy-first approach builds trust

Status: ✅ Implemented


🔄 Decision Review Process

When to Document Decisions

Document a decision when:

  • ✅ It affects architecture significantly
  • ✅ There were multiple viable alternatives
  • ✅ It might be questioned later ("Why did we...?")
  • ✅ It has performance/cost implications
  • ✅ It sets a pattern for future work

Decision Template

### [Decision Title]

**Decision**: [What was decided]

**Context**: [Why we needed to decide]

**Alternatives Considered**:
- Option A
- Option B
- Option C

**Reasoning**:
- Pros
- Cons
- Trade-offs

**Outcome**: [Result of decision]

**Status**: ✅ Implemented / 🚧 In Progress / ❌ Deprecated

🔗 Related Documentation


📝 Historical Decisions Log

This document contains the complete history of architectural and engineering decisions made during development.

Standing Rule: Always record significant product/engineering decisions when they are made or implemented.


Proposing a change to these decisions? Open an issue or PR with rationale and discuss with the team.

Reading this with an agent? /docs/architecture/design-decisions.md serves the raw markdown.

All docs