Monorepo Structure
Understanding how the Izri codebase is organized
📁 Repository Layout
izri/
├── apps/ # Application packages
│ ├── web/ # React Router frontend
│ └── api/ # Hono + tRPC backend
│
├── packages/ # Shared packages
│ ├── database/ # Drizzle ORM + schema
│ ├── trpc/ # tRPC routers + procedures
│ ├── auth/ # Authentication (Lucia)
│ ├── shared/ # Common utilities
│ ├── repo-analyzer/ # Repository analysis
│ └── ai-service/ # Python AI service
│
├── docs/ # Documentation
│ ├── getting-started/
│ ├── architecture/
│ ├── development/
│ └── ...
│
├── docker/ # Dockerfiles
│ ├── web/
│ ├── api/
│ └── ai-service/
│
├── .turbo/ # Turbo cache
├── node_modules/ # Dependencies
├── package.json # Root package config
├── pnpm-workspace.yaml # Workspace definition
├── turbo.json # Turbo configuration
├── tsconfig.json # Base TypeScript config
└── docker-compose.yml # Local infrastructure
🏗️ Workspace Configuration
pnpm Workspace
File: pnpm-workspace.yaml
packages:
- apps/*
- packages/*
onlyBuiltDependencies:
- '@tailwindcss/oxide'
What it does:
- Defines which directories contain packages
- Enables cross-package dependencies
- Links packages via symlinks (fast, efficient)
- Hoists common dependencies to root
Turbo Configuration
File: turbo.json
{
"globalDependencies": [".env", "tsconfig.json"],
"globalEnv": ["DATABASE_URL", "API_URL", ...],
"tasks": {
"build": {
"dependsOn": ["^build"],
"outputs": ["dist/**", "lib/**"],
"cache": true
},
"dev": {
"cache": false,
"persistent": true
}
}
}
What it does:
- Orchestrates task execution
- Manages build dependencies
- Enables intelligent caching
- Runs tasks in parallel
📦 Application Packages
apps/web
Purpose: Frontend React Router application
Structure:
apps/web/
├── app/ # React Router app
│ ├── routes/ # File-based routes
│ │ ├── _index.tsx # Home page
│ │ ├── projects/ # Projects section
│ │ │ ├── $id.tsx # Project detail
│ │ │ └── new.tsx # Create project
│ │ ├── login.tsx # Auth pages
│ │ └── ...
│ ├── components/ # React components
│ │ ├── ui/ # shadcn/ui components
│ │ ├── layout/ # Layout components
│ │ └── features/ # Feature-specific
│ ├── lib/ # Utilities
│ │ ├── trpc.ts # tRPC client setup
│ │ ├── utils.ts # Helper functions
│ │ └── cn.ts # Class name utility
│ ├── styles/ # CSS files
│ │ └── globals.css # Global styles
│ ├── root.tsx # Root component
│ └── entry.client.tsx # Client entry
│
├── public/ # Static assets
│ ├── favicon.ico
│ └── images/
│
├── package.json # Dependencies + scripts
├── tsconfig.json # TypeScript config
├── vite.config.ts # Vite configuration
├── tailwind.config.js # Tailwind config
└── react-router.config.ts # React Router config
Key Files:
app/root.tsx: Root layout with providersapp/entry.client.tsx: Client-side entry pointapp/lib/trpc.ts: tRPC client configurationvite.config.ts: Build and dev server config
Dependencies:
{
"dependencies": {
"react": "^19.0.0",
"react-router": "^7.1.3",
"@tanstack/react-query": "^5.0.0",
"@izri/trpc": "workspace:*",
"@izri/shared": "workspace:*"
}
}
apps/api
Purpose: Backend API server (Hono + tRPC)
Structure:
apps/api/
├── src/
│ ├── index.ts # Server entry point
│ ├── app.ts # Hono app setup
│ ├── middleware/ # Custom middleware
│ │ ├── auth.ts # Auth middleware
│ │ └── logger.ts # Logging
│ ├── lib/ # Utilities
│ │ └── trpc.ts # tRPC server setup
│ └── utils/ # Helper functions
│
├── package.json
└── tsconfig.json
Key Files:
src/index.ts: Starts Hono server, mounts tRPCsrc/app.ts: Configures middleware, routessrc/middleware/auth.ts: Authentication logic
Dependencies:
{
"dependencies": {
"hono": "^4.0.0",
"@trpc/server": "^11.0.0",
"@izri/trpc": "workspace:*",
"@izri/database": "workspace:*",
"@izri/auth": "workspace:*"
}
}
📚 Shared Packages
packages/database
Purpose: Database schema, migrations, and queries
Structure:
packages/database/
├── src/
│ ├── index.ts # Exports
│ ├── db.ts # Database client
│ ├── schema.ts # Drizzle schema
│ ├── seed.ts # Seed script
│ └── migrations/ # (unused, see root)
│
├── migrations/ # Migration files (root)
│ ├── 0000_initial.sql
│ ├── 0001_add_projects.sql
│ └── ...
│
├── drizzle.config.ts # Drizzle Kit config
├── package.json
└── tsconfig.json
Key Files:
src/schema.ts: All table definitionssrc/db.ts: Drizzle client setupdrizzle.config.ts: Migration configuration
Exports:
export { db } from './db'
export * from './schema'
export type {
User, NewUser,
Project, NewProject,
// ... all types
} from './schema'
packages/trpc
Purpose: tRPC routers, procedures, and context
Structure:
packages/trpc/
├── src/
│ ├── index.ts # Main exports
│ ├── router.ts # Root router
│ ├── context.ts # tRPC context
│ ├── trpc.ts # tRPC setup
│ └── routers/ # Feature routers
│ ├── health.ts # Health check
│ ├── projects.ts # Projects CRUD
│ ├── test-runs.ts # Test runs
│ ├── organizations.ts # Organizations
│ └── users.ts # User management
│
├── package.json
└── tsconfig.json
Key Files:
src/trpc.ts: Procedure builderssrc/context.ts: Request context creationsrc/router.ts: Combines all routers
Pattern:
// src/routers/projects.ts
import { router, publicProcedure } from '../trpc'
import { z } from 'zod'
export const projectRouter = router({
list: publicProcedure.query(async ({ ctx }) => {
return ctx.db.select().from(projects)
}),
create: publicProcedure
.input(z.object({ name: z.string() }))
.mutation(async ({ ctx, input }) => {
return ctx.db.insert(projects).values(input)
})
})
packages/auth
Purpose: Authentication with Lucia
Structure:
packages/auth/
├── src/
│ ├── index.ts # Exports
│ ├── lucia.ts # Lucia setup
│ ├── providers/ # OAuth providers
│ │ └── github.ts # GitHub OAuth
│ └── middleware.ts # Auth middleware
│
├── package.json
└── tsconfig.json
packages/shared
Purpose: Common utilities, types, and helpers
Structure:
packages/shared/
├── src/
│ ├── index.ts # Exports
│ ├── types/ # Shared types
│ │ ├── api.ts # API types
│ │ └── common.ts # Common types
│ ├── utils/ # Utilities
│ │ ├── validation.ts # Zod schemas
│ │ ├── errors.ts # Error classes
│ │ └── format.ts # Formatters
│ └── constants/ # Constants
│ └── index.ts
│
├── package.json
└── tsconfig.json
packages/repo-analyzer
Purpose: TypeScript repository analysis utilities
Structure:
packages/repo-analyzer/
├── src/
│ ├── index.ts
│ ├── analyzer.ts # Main analyzer
│ └── parsers/ # Language parsers
│
├── package.json
└── tsconfig.json
packages/ai-service
Purpose: Python AI service (FastAPI)
Structure:
packages/ai-service/
├── main.py # FastAPI app
├── requirements.txt # Python dependencies
└── README.md
🔗 Package Dependencies
Dependency Graph
apps/web
├─→ @izri/trpc
└─→ @izri/shared
apps/api
├─→ @izri/trpc
├─→ @izri/database
├─→ @izri/auth
└─→ @izri/shared
@izri/trpc
├─→ @izri/database
└─→ @izri/shared
@izri/auth
├─→ @izri/database
└─→ @izri/shared
@izri/database
└─→ (no workspace deps)
@izri/shared
└─→ (no workspace deps)
How Workspace Dependencies Work
In package.json:
{
"dependencies": {
"@izri/trpc": "workspace:*"
}
}
What happens:
- pnpm creates symlink to local package
- Changes reflect immediately (no reinstall)
- TypeScript follows symlinks
- Build order managed by Turbo
🔧 Build Pipeline
Build Order (Turbo)
graph TD
A[shared] --> B[database]
B --> C[trpc]
B --> D[auth]
C --> E[api]
C --> F[web]
D --> E
A --> C
A --> D
Execution:
pnpm build # Turbo builds in correct order
What happens:
@izri/sharedbuilds first@izri/databasebuilds (depends on shared)@izri/trpcand@izri/authbuild in parallelapps/apiandapps/webbuild last
Build Outputs
| Package | Output Directory | Contents |
|---|---|---|
shared |
lib/ |
Compiled .js + .d.ts |
database |
lib/ |
Compiled .js + .d.ts |
trpc |
lib/ |
Compiled .js + .d.ts |
auth |
lib/ |
Compiled .js + .d.ts |
api |
dist/ |
Bundled server |
web |
dist/ |
Bundled client |
📝 TypeScript Configuration
Root tsconfig.json
{
"compilerOptions": {
"target": "ES2022",
"lib": ["ES2023"],
"module": "ESNext",
"moduleResolution": "bundler",
"strict": true,
"skipLibCheck": true,
"esModuleInterop": true,
"resolveJsonModule": true
}
}
Package-Specific Configs
Apps extend root:
{
"extends": "../../tsconfig.json",
"compilerOptions": {
"outDir": "./dist"
},
"include": ["src"]
}
Import Resolution
Path aliases (in tsconfig.json):
{
"compilerOptions": {
"paths": {
"@/*": ["./src/*"],
"@/components/*": ["./app/components/*"]
}
}
}
Usage:
import { Button } from '@/components/ui/button'
import { api } from '@/lib/trpc'
🚀 Development Workflow
Installing Dependencies
# Install all packages
pnpm install
# Add to specific package
pnpm --filter @izri/web add react-query
# Add to root (shared dev tool)
pnpm add -w -D vitest
Running Tasks
# Run dev servers (all)
pnpm dev
# Run specific package
pnpm dev:web
pnpm dev:api
# Build all
pnpm build
# Build specific package
pnpm build:web
# Type check
pnpm type:check
# Lint
pnpm lint
Creating New Packages
Create directory:
mkdir packages/my-package cd packages/my-packageInitialize package:
pnpm initUpdate
package.json:{ "name": "@izri/my-package", "version": "0.0.0", "main": "./lib/index.js", "types": "./lib/index.d.ts", "scripts": { "build": "tsc", "dev": "tsc --watch" } }Create
tsconfig.json:{ "extends": "../../tsconfig.json", "compilerOptions": { "outDir": "./lib", "rootDir": "./src" }, "include": ["src"] }Add to Turbo (if needed): Already configured via wildcards
🎯 Best Practices
Do's ✅
- Use workspace protocol:
"@izri/package": "workspace:*" - Keep packages focused: Single responsibility
- Export explicitly: Don't export everything
- Version together: Keep all packages in sync
- Build before use: Ensure packages are built
Don'ts ❌
- Don't create circular dependencies
- Don't skip builds: Always build packages before use
- Don't duplicate code: Move shared code to
sharedpackage - Don't use relative imports: Use package names
- Don't mix concerns: Keep packages focused
🔗 Related Documentation
- Technology Stack: Technologies used
- System Overview: High-level architecture
- Development Guide: Daily workflows
Questions about package structure? Check with the team or refer to existing packages as examples.