Skip to content

Software Design Specification (SDS) #2

@lakinmindfire

Description

@lakinmindfire

Software Design Specification (SDS)

Self-Hosted Monorepo Package Manager Dashboard

Document Version: 1.0
Date: October 08, 2025
Prepared By: Development Team
Approved By: Project Stakeholders


1. Introduction

1.1 Purpose

This Software Design Specification (SDS) describes the complete technical architecture, implementation details, and development setup for a self-hosted monorepo package manager dashboard. The system will be distributed as an npm package that automatically generates a web UI for package oversight within any monorepo.

1.2 Scope

The dashboard provides visual management and monitoring for packages in monorepos using pnpm, Turborepo, and Nx, with automated CI/CD integration, semantic versioning, and development workflow optimization.

1.3 Intended Audience

  • Software Architects
  • Frontend/Backend Developers
  • DevOps Engineers
  • Quality Assurance Engineers
  • Technical Project Managers

1.4 Reference Documents

  • Functional Requirements Specification (FRS) v1.0
  • Turborepo Documentation[124][125][127]
  • PNPM Workspace Configuration[132][141][144]
  • Semantic Release Monorepo Setup[139][142]

2. System Architecture

2.1 High-Level Architecture

┌─────────────────────────────────────────────────────────────┐
│                    Monorepo Dashboard                       │
├─────────────────────────────────────────────────────────────┤
│  Frontend (React + TypeScript + Vite)                      │
│  ├── Package Overview       ├── Dependency Graph           │
│  ├── Health Monitoring      ├── Version Management         │
│  └── Configuration Inspector                               │
├─────────────────────────────────────────────────────────────┤
│  Backend API (Node.js + Express)                           │
│  ├── Package Scanner        ├── CI/CD Integration          │
│  ├── Git Operations         ├── Semantic Release           │
│  └── WebSocket Server       └── File System Watcher       │
├─────────────────────────────────────────────────────────────┤
│  Integration Layer                                          │
│  ├── pnpm/Turborepo/Nx     ├── GitHub Actions/GitLab CI   │
│  ├── Git Hooks             └── NPM Registry                │
└─────────────────────────────────────────────────────────────┘

2.2 Technology Stack

Layer Technology Version Purpose
Frontend React ^18.0.0 UI Framework
Frontend TypeScript ^5.0.0 Type Safety
Frontend Vite ^5.0.0 Build Tool & Dev Server
Frontend Cytoscape.js ^3.26.0 Graph Visualization
Backend Node.js >=18.0.0 Runtime Environment
Backend Express ^4.18.0 Web Framework
Backend TypeScript ^5.0.0 Type Safety
Backend WebSocket ^8.0.0 Real-time Updates
Package Manager pnpm ^8.0.0 Package Management
Build System Turborepo ^1.10.0 Task Orchestration
Code Quality ESLint ^8.50.0 Linting
Code Quality Prettier ^3.0.0 Code Formatting
Git Hooks Husky ^8.0.0 Git Hook Management
Commit Validation Commitlint ^17.0.0 Commit Message Validation
Release Semantic Release ^21.0.0 Automated Versioning

3. Project Structure

3.1 Monorepo Directory Structure

monorepo-dashboard/
├── .github/                          # GitHub workflows and templates
│   ├── workflows/
│   │   ├── ci.yml                    # Continuous Integration
│   │   ├── release.yml               # Automated releases
│   │   └── codeql.yml                # Security scanning
│   └── ISSUE_TEMPLATE/               # Issue templates
├── .husky/                           # Git hooks
│   ├── pre-commit                    # Pre-commit hook
│   ├── commit-msg                    # Commit message validation
│   └── pre-push                      # Pre-push validation
├── apps/                             # Applications
│   └── dashboard/                    # Main dashboard application
│       ├── src/
│       │   ├── components/           # React components
│       │   ├── pages/               # Page components
│       │   ├── hooks/               # Custom React hooks
│       │   ├── services/            # API services
│       │   ├── stores/              # State management
│       │   ├── types/               # TypeScript types
│       │   └── utils/               # Utility functions
│       ├── public/                  # Static assets
│       ├── package.json
│       ├── vite.config.ts           # Vite configuration
│       └── tsconfig.json            # TypeScript config
├── packages/                         # Shared packages
│   ├── server/                      # Backend server package
│   │   ├── src/
│   │   │   ├── routes/              # Express routes
│   │   │   ├── services/            # Business logic services
│   │   │   ├── utils/               # Server utilities
│   │   │   ├── types/               # Shared types
│   │   │   └── integrations/        # CI/CD integrations
│   │   ├── package.json
│   │   └── tsconfig.json
│   ├── shared/                      # Shared utilities and types
│   │   ├── src/
│   │   │   ├── types/               # Common TypeScript types
│   │   │   ├── constants/           # Application constants
│   │   │   └── utils/               # Shared utility functions
│   │   ├── package.json
│   │   └── tsconfig.json
│   ├── eslint-config/               # Shared ESLint configuration
│   │   ├── index.js                 # ESLint rules
│   │   └── package.json
│   └── tsconfig/                    # Shared TypeScript configurations
│       ├── base.json                # Base TS config
│       ├── react.json               # React-specific config
│       ├── node.json                # Node.js config
│       └── package.json
├── tools/                            # Development tools and scripts
│   ├── scripts/                     # Build and deployment scripts
│   ├── templates/                   # Code generation templates
│   └── configs/                     # Tool configurations
├── docs/                            # Documentation
│   ├── api/                         # API documentation
│   ├── guides/                      # User guides
│   └── development/                 # Development docs
├── .gitignore                       # Git ignore rules
├── .prettierrc                      # Prettier configuration
├── .nvmrc                          # Node.js version
├── commitlint.config.js            # Commitlint configuration
├── package.json                     # Root package.json
├── pnpm-workspace.yaml             # PNPM workspace configuration
├── turbo.json                      # Turborepo configuration
├── README.md                       # Project documentation
└── LICENSE                         # License file

3.2 Package Configuration Files

3.2.1 Root package.json

{
  "name": "@org/monorepo-dashboard",
  "version": "1.0.0",
  "description": "Self-hosted monorepo package manager dashboard",
  "private": true,
  "packageManager": "pnpm@8.10.0",
  "engines": {
    "node": ">=18.0.0",
    "pnpm": ">=8.0.0"
  },
  "workspaces": [
    "apps/*",
    "packages/*"
  ],
  "scripts": {
    "prepare": "husky install",
    "build": "turbo run build",
    "dev": "turbo run dev --parallel",
    "lint": "turbo run lint",
    "lint:fix": "turbo run lint:fix",
    "type-check": "turbo run type-check",
    "test": "turbo run test",
    "clean": "turbo run clean && rm -rf node_modules/.cache",
    "format": "prettier --write \"**/*.{ts,tsx,js,jsx,json,md}\"",
    "format:check": "prettier --check \"**/*.{ts,tsx,js,jsx,json,md}\"",
    "release": "semantic-release",
    "changeset": "changeset",
    "version-packages": "changeset version",
    "publish-packages": "changeset publish"
  },
  "devDependencies": {
    "@changesets/cli": "^2.26.2",
    "@commitlint/cli": "^17.7.1",
    "@commitlint/config-conventional": "^17.7.0",
    "@org/eslint-config": "workspace:*",
    "@org/tsconfig": "workspace:*",
    "@semantic-release/changelog": "^6.0.3",
    "@semantic-release/git": "^10.0.1",
    "@types/node": "^20.5.0",
    "eslint": "^8.50.0",
    "husky": "^8.0.3",
    "lint-staged": "^14.0.1",
    "prettier": "^3.0.3",
    "semantic-release": "^21.1.1",
    "semantic-release-monorepo": "^7.0.5",
    "turbo": "^1.10.14",
    "typescript": "^5.2.2"
  },
  "lint-staged": {
    "*.{ts,tsx,js,jsx}": [
      "eslint --fix",
      "prettier --write"
    ],
    "*.{json,md,yaml,yml}": [
      "prettier --write"
    ]
  }
}

3.2.2 pnpm-workspace.yaml

packages:
  # Applications
  - "apps/*"
  # Shared packages and libraries
  - "packages/*"
  # Exclude test directories and dist folders
  - "!**/dist"
  - "!**/node_modules"
  - "!**/*.test.*"

3.2.3 turbo.json[124][125][140][143][148]

{
  "$schema": "https://turbo.build/schema.json",
  "globalDependencies": ["**/.env.*local"],
  "pipeline": {
    "//#format": {
      "cache": false
    },
    "//#format:check": {
      "cache": false
    },
    "build": {
      "dependsOn": ["^build", "type-check"],
      "outputs": ["dist/**", ".next/**", "build/**"],
      "env": ["NODE_ENV"]
    },
    "type-check": {
      "dependsOn": ["^build"],
      "outputs": []
    },
    "dev": {
      "cache": false,
      "persistent": true,
      "env": ["NODE_ENV", "PORT"]
    },
    "lint": {
      "dependsOn": ["^topo"],
      "outputs": []
    },
    "lint:fix": {
      "cache": false,
      "outputs": []
    },
    "test": {
      "dependsOn": ["build"],
      "outputs": ["coverage/**"],
      "inputs": ["src/**/*.tsx", "src/**/*.ts", "test/**/*.ts", "test/**/*.tsx"]
    },
    "clean": {
      "cache": false
    },
    "release": {
      "dependsOn": ["build", "test"],
      "cache": false,
      "env": ["GITHUB_TOKEN", "NPM_TOKEN"]
    }
  },
  "remoteCache": {
    "enabled": false
  }
}

4. Development Workflow Setup

4.1 Git Hooks Configuration (Husky)[125][128][130]

4.1.1 .husky/pre-commit

#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"

echo "🔍 Running pre-commit checks..."

# Run lint-staged
npx lint-staged

# Type checking
echo "📝 Type checking..."
pnpm turbo type-check

# Run tests for changed packages
echo "🧪 Running tests..."
pnpm turbo test --filter='...[HEAD~1]'

echo "✅ Pre-commit checks completed"

4.1.2 .husky/commit-msg

#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"

echo "📝 Validating commit message..."
npx --no -- commitlint --edit $1

4.1.3 .husky/pre-push

#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"

echo "🚀 Running pre-push checks..."

# Build all packages
echo "🔨 Building packages..."
pnpm turbo build

# Run full test suite
echo "🧪 Running full test suite..."
pnpm turbo test

# Check formatting
echo "💄 Checking code formatting..."
pnpm format:check

echo "✅ Pre-push checks completed"

4.2 Commit Lint Configuration[125][130][133]

4.2.1 commitlint.config.js

module.exports = {
  extends: ['@commitlint/config-conventional'],
  rules: {
    'type-enum': [
      2,
      'always',
      [
        'feat',     // New feature
        'fix',      // Bug fix
        'docs',     // Documentation changes
        'style',    // Code style changes (formatting, etc)
        'refactor', // Code refactoring
        'perf',     // Performance improvements
        'test',     // Adding or updating tests
        'chore',    // Maintenance tasks
        'ci',       // CI/CD changes
        'build',    // Build system changes
        'revert'    // Reverting changes
      ]
    ],
    'scope-enum': [
      2,
      'always',
      [
        'dashboard',  // Dashboard app
        'server',     // Backend server
        'shared',     // Shared utilities
        'config',     // Configuration files
        'deps',       // Dependencies
        'release',    // Release related
        'docs'        // Documentation
      ]
    ],
    'subject-max-length': [2, 'always', 100],
    'subject-min-length': [2, 'always', 10],
    'header-max-length': [2, 'always', 120]
  }
};

4.3 ESLint Configuration (Shared)[125]

4.3.1 packages/eslint-config/index.js

module.exports = {
  root: true,
  parser: '@typescript-eslint/parser',
  plugins: ['@typescript-eslint', 'react', 'react-hooks'],
  extends: [
    'eslint:recommended',
    '@typescript-eslint/recommended',
    'plugin:react/recommended',
    'plugin:react-hooks/recommended',
    'prettier'
  ],
  settings: {
    react: {
      version: 'detect'
    }
  },
  env: {
    browser: true,
    node: true,
    es2022: true
  },
  parserOptions: {
    ecmaVersion: 'latest',
    sourceType: 'module',
    ecmaFeatures: {
      jsx: true
    }
  },
  rules: {
    // TypeScript specific
    '@typescript-eslint/no-unused-vars': ['error', { argsIgnorePattern: '^_' }],
    '@typescript-eslint/no-explicit-any': 'warn',
    '@typescript-eslint/explicit-function-return-type': 'off',
    '@typescript-eslint/explicit-module-boundary-types': 'off',
    
    // React specific
    'react/react-in-jsx-scope': 'off',
    'react/prop-types': 'off',
    'react/no-unescaped-entities': 'off',
    
    // General
    'no-console': 'warn',
    'prefer-const': 'error',
    'no-var': 'error'
  },
  ignorePatterns: ['dist', 'node_modules', '*.config.js']
};

4.4 Semantic Release Configuration[139][142][145][152]

4.4.1 .releaserc.json

{
  "branches": ["main", "master"],
  "plugins": [
    "@semantic-release/commit-analyzer",
    "@semantic-release/release-notes-generator",
    [
      "@semantic-release/changelog",
      {
        "changelogFile": "CHANGELOG.md"
      }
    ],
    "@semantic-release/npm",
    [
      "@semantic-release/git",
      {
        "assets": ["package.json", "CHANGELOG.md"],
        "message": "chore(release): ${nextRelease.version} [skip ci]\n\n${nextRelease.notes}"
      }
    ],
    "@semantic-release/github"
  ]
}

5. Component Design

5.1 Frontend Architecture

5.1.1 React Component Structure

// apps/dashboard/src/components/PackageOverview/PackageCard.tsx
interface Package {
  name: string;
  version: string;
  description: string;
  type: 'app' | 'lib' | 'tool';
  dependencies: string[];
  devDependencies: string[];
  maintainers: string[];
  lastUpdated: Date;
  buildStatus: 'success' | 'failed' | 'pending';
  testCoverage: number;
}

interface PackageCardProps {
  package: Package;
  onSelect: (packageName: string) => void;
  onViewDependencies: (packageName: string) => void;
}

export const PackageCard: React.FC<PackageCardProps> = ({
  package: pkg,
  onSelect,
  onViewDependencies
}) => {
  // Component implementation
};

5.1.2 State Management (Zustand)

// apps/dashboard/src/stores/packageStore.ts
interface PackageState {
  packages: Package[];
  selectedPackage: Package | null;
  dependencyGraph: DependencyNode[];
  loading: boolean;
  error: string | null;
  
  // Actions
  fetchPackages: () => Promise<void>;
  selectPackage: (packageName: string) => void;
  updatePackageStatus: (packageName: string, status: BuildStatus) => void;
  refreshDependencyGraph: () => Promise<void>;
}

export const usePackageStore = create<PackageState>((set, get) => ({
  packages: [],
  selectedPackage: null,
  dependencyGraph: [],
  loading: false,
  error: null,
  
  fetchPackages: async () => {
    // Implementation
  },
  
  selectPackage: (packageName: string) => {
    // Implementation
  }
}));

5.2 Backend API Design

5.2.1 Express Route Structure

// packages/server/src/routes/packages.ts
import express from 'express';
import { PackageService } from '../services/PackageService';

const router = express.Router();
const packageService = new PackageService();

router.get('/packages', async (req, res) => {
  try {
    const packages = await packageService.getAllPackages();
    res.json({ packages });
  } catch (error) {
    res.status(500).json({ error: error.message });
  }
});

router.get('/packages/:name/dependencies', async (req, res) => {
  try {
    const { name } = req.params;
    const dependencies = await packageService.getDependencyGraph(name);
    res.json({ dependencies });
  } catch (error) {
    res.status(500).json({ error: error.message });
  }
});

export { router as packagesRouter };

5.2.2 Service Layer

// packages/server/src/services/PackageService.ts
export class PackageService {
  private workspaceRoot: string;
  private packageManager: 'pnpm' | 'npm' | 'yarn';

  constructor() {
    this.workspaceRoot = this.detectWorkspaceRoot();
    this.packageManager = this.detectPackageManager();
  }

  async getAllPackages(): Promise<Package[]> {
    const packagePaths = await this.findPackageDirectories();
    const packages = await Promise.all(
      packagePaths.map(path => this.parsePackage(path))
    );
    return packages;
  }

  async getDependencyGraph(packageName: string): Promise<DependencyNode[]> {
    // Build dependency graph using package manager CLI
    return this.buildDependencyGraph(packageName);
  }

  private detectWorkspaceRoot(): string {
    // Implementation to find workspace root
  }

  private detectPackageManager(): 'pnpm' | 'npm' | 'yarn' {
    // Implementation to detect package manager
  }
}

6. CI/CD Integration

6.1 GitHub Actions Configuration

6.1.1 .github/workflows/ci.yml

name: CI

on:
  push:
    branches: [main, develop]
  pull_request:
    branches: [main, develop]

jobs:
  lint-and-test:
    runs-on: ubuntu-latest
    
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0
      
      - name: Setup Node.js
        uses: actions/setup-node@v4
        with:
          node-version-file: '.nvmrc'
      
      - name: Setup pnpm
        uses: pnpm/action-setup@v2
        with:
          version: 8
          run_install: false
      
      - name: Get pnpm store directory
        shell: bash
        run: echo "STORE_PATH=$(pnpm store path --silent)" >> $GITHUB_ENV
      
      - name: Setup pnpm cache
        uses: actions/cache@v3
        with:
          path: ${{ env.STORE_PATH }}
          key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
          restore-keys: |
            ${{ runner.os }}-pnpm-store-
      
      - name: Install dependencies
        run: pnpm install --frozen-lockfile
      
      - name: Lint
        run: pnpm turbo lint
      
      - name: Type check
        run: pnpm turbo type-check
      
      - name: Test
        run: pnpm turbo test --coverage
      
      - name: Build
        run: pnpm turbo build

6.1.2 .github/workflows/release.yml

name: Release

on:
  push:
    branches: [main]

jobs:
  release:
    runs-on: ubuntu-latest
    if: github.ref == 'refs/heads/main'
    
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0
          token: ${{ secrets.GITHUB_TOKEN }}
      
      - name: Setup Node.js
        uses: actions/setup-node@v4
        with:
          node-version-file: '.nvmrc'
          registry-url: 'https://registry.npmjs.org'
      
      - name: Setup pnpm
        uses: pnpm/action-setup@v2
        with:
          version: 8
      
      - name: Install dependencies
        run: pnpm install --frozen-lockfile
      
      - name: Build packages
        run: pnpm turbo build
      
      - name: Run tests
        run: pnpm turbo test
      
      - name: Release
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
          NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
        run: pnpm semantic-release

7. Package Distribution

7.1 NPM Package Configuration

7.1.1 Main Package package.json (for distribution)

{
  "name": "@org/monorepo-dashboard",
  "version": "1.0.0",
  "description": "Self-hosted monorepo package manager dashboard",
  "keywords": ["monorepo", "dashboard", "pnpm", "turborepo", "nx"],
  "homepage": "https://github.com/org/monorepo-dashboard",
  "bugs": "https://github.com/org/monorepo-dashboard/issues",
  "license": "MIT",
  "author": "Your Organization",
  "main": "./dist/index.js",
  "types": "./dist/index.d.ts",
  "bin": {
    "monorepo-dashboard": "./bin/cli.js"
  },
  "files": [
    "dist",
    "bin",
    "README.md",
    "LICENSE"
  ],
  "scripts": {
    "start": "node dist/server.js",
    "postinstall": "node dist/postinstall.js"
  },
  "engines": {
    "node": ">=18.0.0"
  },
  "peerDependencies": {
    "@types/node": ">=18.0.0"
  },
  "dependencies": {
    "express": "^4.18.0",
    "ws": "^8.0.0",
    "chokidar": "^3.5.0"
  }
}

7.1.2 CLI Entry Point

#!/usr/bin/env node
# bin/cli.js

const { spawn } = require('child_process');
const path = require('path');

// Parse command line arguments
const args = process.argv.slice(2);
const command = args[0] || 'dev';

switch (command) {
  case 'dev':
  case 'start':
    const serverPath = path.join(__dirname, '..', 'dist', 'server.js');
    const server = spawn('node', [serverPath, ...args.slice(1)], {
      stdio: 'inherit'
    });
    
    server.on('exit', (code) => {
      process.exit(code);
    });
    break;
    
  default:
    console.error(`Unknown command: ${command}`);
    console.log('Available commands: dev, start');
    process.exit(1);
}

8. Testing Strategy

8.1 Testing Configuration

8.1.1 Vitest Configuration

// vitest.config.ts
import { defineConfig } from 'vitest/config';
import react from '@vitejs/plugin-react';

export default defineConfig({
  plugins: [react()],
  test: {
    environment: 'jsdom',
    setupFiles: ['./src/test/setup.ts'],
    coverage: {
      provider: 'v8',
      reporter: ['text', 'html', 'clover', 'json'],
      exclude: [
        'node_modules/',
        'dist/',
        'coverage/',
        '**/*.d.ts',
        '**/*.config.*',
        '**/test/**'
      ]
    }
  }
});

8.2 Test Structure

tests/
├── unit/                    # Unit tests
│   ├── components/          # Component tests
│   ├── services/           # Service layer tests
│   └── utils/              # Utility function tests
├── integration/            # Integration tests
│   ├── api/                # API endpoint tests
│   └── workflows/          # End-to-end workflow tests
├── fixtures/               # Test data and mocks
├── helpers/                # Test utilities
└── setup.ts               # Test setup configuration

9. Performance Considerations

9.1 Build Optimization

9.1.1 Vite Configuration for Production

// apps/dashboard/vite.config.ts
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';

export default defineConfig({
  plugins: [react()],
  build: {
    target: 'es2020',
    minify: 'esbuild',
    sourcemap: true,
    rollupOptions: {
      output: {
        manualChunks: {
          vendor: ['react', 'react-dom'],
          charts: ['cytoscape'],
          utils: ['lodash-es']
        }
      }
    }
  },
  server: {
    port: 3000,
    host: true
  }
});

9.2 Caching Strategy

  • Turborepo cache for build artifacts
  • Browser caching for static assets
  • API response caching for package metadata
  • WebSocket connection management for real-time updates

10. Security Considerations

10.1 API Security

  • Input validation on all endpoints
  • Rate limiting for API requests
  • Secure token storage for CI/CD integrations
  • CORS configuration for cross-origin requests

10.2 Access Control

  • Role-based permissions for package actions
  • Audit logging for sensitive operations
  • Secure credential management
  • Environment variable validation

11. Documentation Requirements

11.1 User Documentation

  • Installation and setup guide
  • Configuration reference
  • API documentation
  • Troubleshooting guide

11.2 Developer Documentation

  • Architecture overview
  • Contributing guidelines
  • Development setup
  • Testing procedures

12. Deployment and Distribution

12.1 Package Publishing

  • Automated publishing via semantic-release
  • Changelog generation from conventional commits
  • Version management across monorepo packages
  • Distribution via NPM registry

12.2 Installation Process

  1. npm install -g @org/monorepo-dashboard
  2. Navigate to monorepo root
  3. Run monorepo-dashboard dev
  4. Dashboard opens automatically in browser

This comprehensive SDS provides the complete technical blueprint for implementing the self-hosted monorepo package manager dashboard with modern tooling, automated workflows, and production-ready configuration[68][85][126][131].

Metadata

Metadata

Assignees

Labels

SDSdocumentationImprovements or additions to documentation

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions