Skip to content

Monorepo Structure

Overview

Jubiloop uses Turborepo to manage its monorepo structure, enabling efficient code sharing, consistent tooling, and optimized build pipelines across all applications and packages.

Project Structure

jubiloop/
├── apps/                      # Application workspaces
│   ├── server/                # AdonisJS API backend
│   ├── webapp/                # React frontend webapp
│   ├── marketing/             # Next.js marketing website
│   └── ui-prototype/          # React design prototype (lab.jubiloop.localhost)
├── packages/                  # Shared packages
│   ├── auth-client/            # Auth & org client (Better Auth + TanStack Query hooks)
│   ├── eslint-config/         # Shared ESLint configuration
│   ├── logger/                # @jubiloop/logger — Structured logging, adaptor pattern
│   ├── shared-types/          # Shared TypeScript interfaces (entities, DTOs, API envelopes)
│   ├── typescript-config/     # Shared TypeScript configuration
│   ├── ui/                    # Shared UI components library
│   └── vitest-config/         # Shared Vitest testing configuration
├── infra/                     # Infrastructure configurations
│   ├── local_dev/             # Local development setup
│   └── deploy/                # Deployment configurations
├── docs/                      # Documentation
└── turbo.json                 # Turborepo configuration

Directory Explanations

Applications (/apps)

The apps directory contains all deployable applications in the monorepo:

Server (/apps/server)

  • Purpose: Backend API server providing all business logic and data management
  • Framework: AdonisJS with TypeScript
  • Key Features:
    • RESTful API endpoints
    • Authentication and authorization
    • Database migrations and models
    • Background job processing
    • WebSocket support for real-time features
  • Structure:
    server/
    ├── app/
    │   ├── controllers/   # Request handlers
    │   ├── models/        # Database models
    │   ├── middleware/    # HTTP middleware
    │   └── validators/    # Input validation
    ├── config/            # Application configuration
    ├── database/
    │   ├── migrations/    # Database migrations
    │   └── seeders/       # Database seeders
    └── start/             # Application bootstrap files

Web Application (/apps/webapp)

  • Purpose: Main user-facing web application
  • Framework: React with Vite
  • Key Features:
    • Single-page application (SPA)
    • Type-safe routing with TanStack Router
    • State management with Zustand
    • API integration with TanStack Query
  • Structure:
    webapp/
    ├── src/
    │   ├── components/    # React components
    │   ├── routes/        # Application routes
    │   ├── hooks/         # Custom React hooks
    │   ├── services/      # API service layer
    │   ├── store/         # State management
    │   └── utils/         # Utility functions
    └── public/            # Static assets

Marketing Site (/apps/marketing)

  • Purpose: Public-facing marketing website
  • Framework: Next.js with TypeScript
  • Key Features:
    • Server-side rendering (SSR)
    • Static site generation (SSG)
    • SEO optimization
    • Blog/content management
  • Structure:
    marketing/
    ├── src/
    │   ├── app/           # Next.js App Router
    │   ├── components/    # React components
    │   └── utils/         # Utility functions
    ├── content/           # Markdown content
    └── public/            # Static assets

Shared Packages (/packages)

The packages directory contains shared code and configurations used across applications:

ESLint Config (/packages/eslint-config)

  • Centralized ESLint rules and configurations
  • Ensures consistent code style across all applications
  • Extends popular configs with custom rules

TypeScript Config (/packages/typescript-config)

  • Shared TypeScript compiler configurations
  • Different configs for different environments:
    • base.json: Common settings
    • react.json: React-specific settings
    • node.json: Node.js backend settings

Auth Client (/packages/auth-client)

  • Authentication and organization client for frontend apps
  • Wraps Better Auth with TanStack Query hooks
  • Handles: sign-in/up/out, session management, organization CRUD, member management
  • General API calls (events, health, etc.) use Tuyau — not this package
  • Features:
    • Better Auth client factory with organization plugin
    • Pre-configured TanStack Query hooks for auth and org operations
    • Cache-first session queries for route guards
    • Centralized query keys (defaultQueryKeys)
    • TypeScript interfaces for type safety

UI Package (/packages/ui)

  • Shared component library using shadcn/ui
  • Tailwind CSS configuration
  • Common UI utilities and helpers
  • Benefits:
    • Consistent design system
    • Reduced duplication
    • Centralized component updates

Vitest Config (/packages/vitest-config)

  • Shared testing configuration
  • Common test utilities and helpers
  • Consistent testing patterns

Infrastructure (/infra)

Local Development (/infra/local_dev)

  • Docker Compose setup for local services
  • Includes PostgreSQL, Redis, and Caddy
  • HTTPS certificate generation scripts
  • Simplified local environment setup

Deployment (/infra/deploy)

  • Production deployment configurations
  • Terraform infrastructure as code
  • Ansible playbooks for server configuration
  • GitHub Actions workflows
  • Environment management scripts

Documentation (/docs)

  • Architecture documentation
  • API documentation
  • Development guides
  • Deployment procedures

How the Monorepo is Organized

Workspace Management

The monorepo uses pnpm workspaces as defined in pnpm-workspace.yaml:

yaml
packages:
  - 'apps/*'
  - 'packages/*'
  - 'docs'

This configuration:

  • Hoists common dependencies to the root
  • Enables cross-package imports
  • Simplifies dependency management
  • Reduces disk space usage

Dependency Management

  1. Internal Dependencies: Packages can depend on each other

    json
    {
      "dependencies": {
        "@jubiloop/ui": "workspace:*",
        "@jubiloop/eslint-config": "workspace:*"
      }
    }
  2. External Dependencies: Managed at workspace level

    • Common dependencies hoisted to root
    • Version conflicts resolved automatically
    • Single node_modules at root level

Build Pipeline

Turborepo manages the build pipeline with:

  • Task orchestration: Defines task dependencies
  • Intelligent caching: Skips unchanged builds
  • Parallel execution: Runs independent tasks concurrently

Example turbo.json configuration:

json
{
  "pipeline": {
    "build": {
      "dependsOn": ["^build"],
      "outputs": ["dist/**", "build/**"]
    },
    "dev": {
      "cache": false,
      "persistent": true
    },
    "test": {
      "dependsOn": ["build"]
    }
  }
}

Turborepo Benefits

1. Incremental Builds

  • Only rebuilds what has changed
  • Caches build outputs
  • Dramatically faster CI/CD pipelines

2. Task Scheduling

  • Understands task dependencies
  • Runs tasks in optimal order
  • Maximizes parallelization

3. Remote Caching

  • Share build cache across team
  • Faster onboarding for new developers
  • Reduced CI/CD costs

4. Dependency Graph Awareness

  • Understands package relationships
  • Runs affected tests only
  • Prevents circular dependencies

5. Developer Experience

  • Single command to run all apps: pnpm run dev
  • Consistent tooling across projects
  • Simplified configuration management

6. Code Sharing

  • Share types between frontend and backend
  • Reuse UI components across apps
  • Centralized business logic

7. Atomic Changes

  • Change API and client in same commit
  • Ensure compatibility across apps
  • Simplified code reviews

Best Practices

1. Package Organization

  • Keep packages focused and single-purpose
  • Document package APIs clearly
  • Version internal packages together

2. Dependency Management

  • Minimize external dependencies
  • Keep shared dependencies at root
  • Use workspace protocol for internal deps

3. Build Optimization

  • Configure proper cache outputs
  • Use cache-friendly file structures
  • Leverage remote caching in CI/CD

4. Development Workflow

  • Use filters to work on specific apps: pnpm run dev -- --filter=webapp
  • Run targeted tests: turbo test --filter=server
  • Build specific packages: turbo build --filter=@jubiloop/ui

5. Code Sharing Guidelines

  • Share types and interfaces liberally
  • Be cautious with shared business logic
  • Keep UI components generic and configurable

Common Commands

bash
# Development
pnpm run dev                          # Start all applications
pnpm run dev -- --filter=webapp      # Start specific app
pnpm run dev -- --filter=@jubiloop/*  # Start all packages

# Building
pnpm run build                        # Build everything
turbo build --filter=server         # Build specific app
turbo build --filter=...webapp      # Build app and dependencies

# Testing
pnpm run test                         # Run all tests
turbo test --filter=marketing       # Test specific app
turbo test --affected               # Test affected by changes

# Maintenance
pnpm exec turbo clean                     # Clear build caches
pnpm install                         # Install all dependencies
pnpm exec turbo prune webapp              # Extract app for deployment

Built with ❤️ by the Jubiloop team