PSA/docs/getting-started/enterprise_edition_architecture.md
Hermes 284313f908
Some checks are pending
Bidi Control Character Guard / bidi-control-guard (push) Waiting to run
Circular Dependency Check / Check for new circular dependencies (push) Waiting to run
Citus Migration Smoke / Combined migrations on single-node Citus (push) Waiting to run
E2E Fresh Install Tests / fresh-install-e2e (push) Waiting to run
ext-v2 guardrails / Run ext-v2 guard and ESLint (push) Waiting to run
Integration Tests / Check for relevant changes (push) Waiting to run
Integration Tests / ${{ (github.event_name == 'schedule' || github.event.inputs.suite == 'full') && 'Full integration suite' || 'Tier-1 integration subset' }} (push) Blocked by required conditions
Mobile checks / Mobile lint + typecheck (push) Waiting to run
Mobile checks / Mobile unit tests (push) Waiting to run
Mobile checks / Mobile dependency audit (report) (push) Waiting to run
Mobile checks / Mobile reproducibility checks (push) Waiting to run
Secrets guard (env backups) / Ensure no tracked env backup files (push) Waiting to run
Temporal Readiness / fast-readiness (push) Waiting to run
Temporal Readiness / docker-parity (push) Waiting to run
TypeScript Type Check / Nx affected typecheck (push) Waiting to run
Unit Tests / Skipped-test budget (push) Waiting to run
Unit Tests / Nx affected unit tests (push) Waiting to run
Unit Tests / Server unit coverage (informational) (push) Waiting to run
Validate Tenant Management Schema / Check for relevant changes (push) Waiting to run
Validate Tenant Management Schema / Validate Tenant Management Schema (push) Blocked by required conditions
EE Workflows Build Guard / ee-workflows-build-guard (push) Waiting to run
Initial import of AlgaPSA codebase from PSA server
Excluded: .git, node_modules, secrets/, compose.env, assemblyscript tgz

Source: /opt/alga-psa on psa.joliet.tech
2026-06-22 16:12:17 -05:00

6.1 KiB

Building Enterprise Edition

This project uses a monorepo structure to integrate the enterprise edition (EE) code with the community edition (CE) code while maintaining them as a single unit.

Project Structure

/
├── package.json          # Root package.json with all dependencies
├── docker-compose.yaml   # Base docker-compose configuration
├── server/              # Community Edition
│   ├── package.json     # CE package.json (minimal, uses workspace)
│   ├── tsconfig.json    # Base TypeScript config
│   └── src/
│       ├── components/
│       ├── lib/
│       └── services/
└── ee/
    └── server/          # Enterprise Edition
        ├── package.json # EE package.json (minimal, uses workspace)
        ├── tsconfig.json# EE TypeScript config (extends base)
        └── src/
            ├── components/
            ├── lib/
            └── services/

Docker Compose Configuration

The project uses a layered docker-compose configuration to support both CE and EE deployments:

  1. Base Configuration (docker-compose.yaml):

    • Contains common service definitions
    • Defines shared environment variables including EDITION
    • Sets up base networking
  2. EE Configuration (ee/setup/docker-compose.yaml):

    • Extends services from base configuration
    • Sets EDITION=enterprise
    • Uses EE-specific Dockerfile and configurations

Running CE Version

# From project root
EDITION=community docker compose -f docker-compose.yaml up

Running EE Version

# From project root
EDITION=enterprise docker compose -f docker-compose.yaml -f ee/setup/docker-compose.yaml up

Workspace Setup

  1. Root package.json defines workspaces and contains all dependencies:
{
  "workspaces": [
    "server",
    "ee/server"
  ],
  "dependencies": {
    // All project dependencies are defined here
  }
}
  1. CE and EE package.json files are minimal:
{
  "name": "sebastian-ee",
  "version": "0.1.0",
  "private": true,
  "workspaces": {
    "nohoist": ["*"]
  }
}

TypeScript Configuration

  1. Base TypeScript config in server/tsconfig.json:
{
  "compilerOptions": {
  }
}
  1. EE TypeScript config in ee/server/tsconfig.json extends the base:
{
  "extends": "../../server/tsconfig.json",
  "compilerOptions": {
    "paths": {
      "@/*": ["../../server/src/*"],
      "@ee/*": ["./src/*"]
    },
    "baseUrl": "."
  }
}

Path Aliases

Use path aliases instead of relative paths:

  • @/* for CE imports
  • @ee/* for EE imports

Example:

// Instead of relative paths like:
import { Something } from "../../../../../server/src/components/Something";

// Use path aliases:
import { Something } from "server/src/components/Something";
import { EEFeature } from "ee/components/EEFeature";

Feature Flags

Use feature flags to conditionally include EE features:

// server/src/lib/features.ts
export const isEnterprise = process.env.EDITION === 'enterprise';

export function getFeatureImplementation<T>(ceModule: T, eeModule?: T): T {
  if (isEnterprise && eeModule) {
    return eeModule;
  }
  return ceModule;
}

Usage:

import { CEFeature } from "features/CEFeature";
import { EEFeature } from "ee/features/EEFeature";
import { getFeatureImplementation } from "server/src/lib/features";

const FeatureComponent = getFeatureImplementation(CEFeature, EEFeature);

Conditional Dependencies

Some packages may only be needed when running in enterprise mode. To handle these cases:

  1. Install the package conditionally in your code:
let anthropicClient;
if (process.env.EDITION === 'enterprise') {
  // Dynamic import ensures the package is only loaded if EE is active
  const { default: Anthropic } = await import('anthropic-sdk');
  anthropicClient = new Anthropic();
}
  1. Add the package to your dependencies in root package.json:
{
  "dependencies": {
    "anthropic-sdk": "^0.1.0"  // Will only be used when EE is active
  }
}

This approach ensures that:

  • The package is available when needed in EE mode
  • The package is not loaded or used in CE mode
  • TypeScript still has access to types for development

Type Declarations

For TypeScript support of EE imports:

// server/src/types/ee.d.ts
declare module '@ee/*' {
  const content: unknown;
  export default content;
}

Build Scripts

The build scripts are defined in the root package.json:

{
  "scripts": {
    "dev": "cd server && EDITION=enterprise next dev",
    "build": "cd server && next build",
    "build:ee": "cd server && EDITION=enterprise next build"
  }
}

Best Practices

  1. Dependencies:

    • Keep all dependencies in the root package.json
    • Use workspace references in CE and EE packages
    • Use dynamic imports for EE-only packages
  2. Code Organization:

    • Keep shared code in the CE codebase
    • Use path aliases consistently
    • Mirror CE directory structure in EE when extending features
  3. Types:

    • Define shared interfaces in CE
    • Extend CE types in EE when needed
    • Use TypeScript path aliases for clean imports
  4. Feature Flags:

    • Use the feature flag system for EE features
    • Document feature flag usage
    • Test both CE and EE configurations
  5. Testing:

    • Test both editions during development
    • Use environment variables to control edition in tests
    • Ensure CE works independently of EE

Development Workflow

  1. Run the development server:
npm run dev  # Runs with EE features enabled
  1. Build the project:
npm run build      # CE build
npm run build:ee   # EE build
  1. Run with Docker Compose:
# Community Edition
EDITION=community docker compose -f docker-compose.yaml up

# Enterprise Edition
EDITION=enterprise docker compose -f docker-compose.yaml -f ee/setup/docker-compose.yaml up

Remember to:

  • Document new EE features
  • Test both CE and EE builds
  • Keep the dependency tree unified
  • Use TypeScript path aliases consistently
  • Follow the established directory structure