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
├── packages/                  # Shared packages
│   ├── api-client/            # Shared API client for frontend apps
│   ├── eslint-config/         # Shared ESLint configuration
│   ├── 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
├── tests/                     # End-to-end and integration tests
└── 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

API Client (/packages/api-client)

  • Shared HTTP client for all frontend applications
  • Built on Axios with automatic CSRF protection
  • Provides flexible configuration for different client needs:
    • Webapp: Adds auth invalidation for session management
    • Marketing: Minimal config for public content
    • Future Mobile: Can override CSRF token handling
  • Features:
    • Automatic CSRF token injection for state-changing requests
    • Session-based authentication support via cookies
    • Configurable 401 response handling
    • Pre-configured TanStack Query hooks
    • TypeScript interfaces for type safety
  • Benefits:
    • Eliminates duplicate axios configurations
    • Consistent API communication patterns
    • Centralized error handling
    • Maintainable and extensible architecture

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 npm workspaces as defined in the root package.json:

json
{
  "workspaces": ["apps/*", "packages/*"]
}

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: npm 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: npm 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
npm run dev                          # Start all applications
npm run dev -- --filter=webapp      # Start specific app
npm run dev -- --filter=@jubiloop/*  # Start all packages

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

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

# Maintenance
npx turbo clean                     # Clear build caches
npm install                         # Install all dependencies
npx turbo prune --scope=webapp     # Extract app for deployment

Built with ❤️ by the Jubiloop team