Skip to content

Development Guide ​

Complete development documentation for Altus 4 contributors

This guide covers everything developers need to know to contribute effectively to Altus 4, from setting up the development environment to submitting pull requests.

Getting Started ​

Prerequisites ​

Before contributing to Altus 4, ensure you have:

  • Node.js 18+ with npm 8+
  • MySQL 8.0+ for database operations
  • Redis 6.0+ for caching
  • Git for version control
  • IDE with TypeScript support (VS Code recommended)

Development Environment Setup ​

  1. Fork and Clone the Repository
bash
# Fork the repository on GitHub, then clone your fork
git clone https://github.com/YOUR_USERNAME/altus4.git
cd altus4

# Add upstream remote
git remote add upstream https://github.com/original/altus4.git
  1. Install Dependencies
bash
# Install all dependencies
npm install

# Verify installation
npm run typecheck
  1. Configure Environment
bash
# Copy development environment template
cp .env.example .env

# Edit with your local configuration
nano .env
  1. Setup Development Environment

Option 1: Docker Environment (Recommended)

bash
# Start complete development environment
npm run dev:start

# This automatically:
# - Starts MySQL and Redis containers
# - Creates the altus4 database
# - Runs all migrations
# - Waits for services to be healthy

Option 2: Manual Database Setup

sql
-- Create development database
CREATE DATABASE altus4 CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;

-- Create test database
CREATE DATABASE altus4_test CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
  1. Run Database Migrations
bash
# Apply all migrations to development database
npm run migrate

# Check migration status
npm run migrate:status

# Rollback if needed
npm run migrate:down
  1. Start Development Server
bash
# Start in development mode with hot reload
npm run dev

# Verify server is running
curl http://localhost:3000/health

Available npm Scripts ​

Altus 4 provides a comprehensive set of npm scripts organized by functionality:

Core Development ​

bash
npm run dev              # Start development server with hot reload
npm run build            # Build production bundle (tsc + tsc-alias)
npm start                # Start production server
npm run clean            # Clean build artifacts

Quality Assurance ​

bash
npm run typecheck        # TypeScript type checking only
npm run lint             # ESLint checking only
npm run lint:fix         # Fix ESLint issues
npm run format           # Format all files with Prettier
npm run format:check     # Check Prettier formatting
npm run format:src       # Format source files only
npm run format:tests     # Format test files only
npm run check            # Full quality check (typecheck + lint + format:check)
npm run validate         # Complete validation (check + test)
npm run fix              # Fix all issues (lint:fix + format)

Testing ​

bash
npm test                 # Unit tests only
npm run test:watch       # Unit tests in watch mode
npm run test:coverage    # Unit tests with coverage
npm run test:integration # Integration tests only
npm run test:performance # Performance tests only
npm run test:all         # All tests (unit + integration)

Database Management ​

bash
npm run migrate          # Run pending migrations (up)
npm run migrate:up       # Run pending migrations (explicit)
npm run migrate:down     # Rollback migrations
npm run migrate:status   # Check migration status

Development Environment ​

bash
npm run dev:start        # Start Docker services + migrations
npm run dev:stop         # Stop Docker services
npm run dev:reset        # Reset development environment
npm run dev:logs         # View Docker service logs

Security & Git Hooks ​

bash
npm run security:audit           # Security audit
npm run security:fix             # Fix security issues
npm run security:verify-commits  # Verify commit signatures
npm run security:setup-gpg       # Setup GPG signing
npm run security:configure-gpg   # Configure GPG signing
npm run security:generate-jwt    # Generate JWT secret
npm run hooks:test               # Test Git hooks functionality

Project Structure ​

Understanding the codebase organization:

text
altus4/
├── src/                          # Source code
│   ├── config/                   # Configuration management
│   │   └── index.ts             # Environment configuration
│   ├── controllers/             # Request handlers
│   │   ├── AuthController.ts    # Authentication endpoints
│   │   ├── SearchController.ts  # Search endpoints
│   │   └── DatabaseController.ts # Database management
│   ├── middleware/              # Express middleware
│   │   ├── auth.ts             # Legacy JWT authentication
│   │   ├── apiKeyAuth.ts       # API key authentication
│   │   ├── errorHandler.ts     # Error handling
│   │   ├── rateLimiter.ts      # Rate limiting
│   │   └── validation.ts       # Request validation
│   ├── routes/                  # API route definitions
│   │   ├── auth.ts             # Auth routes
│   │   ├── search.ts           # Search routes
│   │   └── database.ts         # Database routes
│   ├── services/                # Business logic layer
│   │   ├── SearchService.ts    # Core search orchestration
│   │   ├── DatabaseService.ts  # MySQL operations
│   │   ├── AIService.ts        # OpenAI integration
│   │   ├── CacheService.ts     # Redis operations
│   │   ├── ApiKeyService.ts    # API key management
│   │   └── UserService.ts      # User management
│   ├── types/                   # TypeScript definitions
│   │   └── index.ts            # Shared type definitions
│   ├── utils/                   # Utility functions
│   │   ├── logger.ts           # Logging utility
│   │   └── encryption.ts       # Encryption helpers
│   └── index.ts                # Application entry point
├── tests/                       # Test files
│   ├── integration/            # Integration tests
│   ├── performance/            # Performance tests
│   ├── utils/                  # Test utilities
│   └── setup.ts               # Test configuration
├── docs/                       # Documentation
├── .github/                    # GitHub workflows
├── dist/                      # Compiled JavaScript (generated)
└── coverage/                  # Test coverage reports (generated)

Code Style & Standards ​

TypeScript Configuration ​

Altus 4 uses strict TypeScript configuration:

json
// tsconfig.json highlights
{
  "compilerOptions": {
    "strict": true,
    "noImplicitAny": true,
    "noImplicitReturns": true,
    "noUnusedLocals": true,
    "noUnusedParameters": true
  }
}

ESLint & Prettier ​

Code formatting is enforced through ESLint and Prettier:

bash
# Check code style
npm run lint

# Auto-fix style issues
npm run lint:fix

# Format code
npm run format

Naming Conventions ​

TypeConventionExample
VariablescamelCasesearchResults
FunctionscamelCaseexecuteSearch()
ClassesPascalCaseSearchService
InterfacesPascalCase with I prefixISearchRequest
TypesPascalCaseSearchMode
ConstantsUPPER_SNAKE_CASEMAX_SEARCH_RESULTS
FilescamelCase or kebab-caseSearchService.ts, auth-controller.ts
DirectoriescamelCasecontrollers/, middleware/

Code Organization Principles ​

  1. Single Responsibility: Each class/function has one clear purpose
  2. Dependency Injection: Use constructor injection for dependencies
  3. Interface Segregation: Prefer small, focused interfaces
  4. DRY (Don't Repeat Yourself): Extract common functionality
  5. SOLID Principles: Follow object-oriented design principles

Development Workflow ​

Git Workflow ​

We follow the GitHub Flow with feature branches:

bash
# Always start from latest main
git checkout main
git pull upstream main

# Create feature branch
git checkout -b feature/search-optimization

# Make changes, commit frequently
git add .
git commit -m "feat: optimize database query performance"

# Push to your fork
git push origin feature/search-optimization

# Create pull request on GitHub

Commit Message Format ​

We follow the Conventional Commits specification:

text
<type>[optional scope]: <description>

[optional body]

[optional footer]

Types:

  • feat: New feature
  • fix: Bug fix
  • docs: Documentation changes
  • style: Code style changes (formatting, etc.)
  • refactor: Code refactoring
  • test: Adding or modifying tests
  • chore: Maintenance tasks

Examples:

bash
feat(search): add semantic search capability
fix(auth): resolve JWT token expiration issue
docs(api): update search endpoint documentation
test(services): add unit tests for SearchService
refactor(database): optimize connection pooling

Branch Naming ​

TypeFormatExample
Featurefeature/descriptionfeature/ai-search-integration
Bug Fixfix/descriptionfix/redis-connection-leak
Documentationdocs/descriptiondocs/api-reference-update
Refactorrefactor/descriptionrefactor/service-architecture

Adding New Features ​

Feature Development Process ​

  1. Planning & Design

    • Create or reference GitHub issue
    • Design API endpoints if needed
    • Plan database schema changes
    • Consider performance implications
  2. Implementation Steps

    • Add TypeScript types
    • Implement service layer
    • Add controller methods
    • Create API routes
    • Add middleware if needed
    • Write comprehensive tests
  3. Testing & Documentation

    • Unit tests for new services
    • Integration tests for new endpoints
    • Update API documentation
    • Add usage examples

Example: Adding a New Service ​

  1. Define TypeScript Interface
typescript
// src/types/index.ts
export interface IAnalyticsService {
  generateReport(
    userId: string,
    dateRange: DateRange
  ): Promise<AnalyticsReport>;
  getUserMetrics(userId: string): Promise<UserMetrics>;
}

export interface AnalyticsReport {
  searchCount: number;
  averageResponseTime: number;
  popularQueries: string[];
  trends: TrendData[];
}
  1. Implement Service Class
typescript
// src/services/AnalyticsService.ts
import { IAnalyticsService } from '@/types';
import { logger } from '@/utils/logger';

export class AnalyticsService implements IAnalyticsService {
  constructor(
    private cacheService: CacheService,
    private databaseService: DatabaseService
  ) {}

  async generateReport(
    userId: string,
    dateRange: DateRange
  ): Promise<AnalyticsReport> {
    try {
      logger.info(`Generating analytics report for user ${userId}`);

      // Implementation here
      const searchCount = await this.getSearchCount(userId, dateRange);
      const averageResponseTime = await this.getAverageResponseTime(
        userId,
        dateRange
      );

      return {
        searchCount,
        averageResponseTime,
        popularQueries: [],
        trends: [],
      };
    } catch (error) {
      logger.error('Failed to generate analytics report:', error);
      throw new AppError('ANALYTICS_ERROR', 'Failed to generate report');
    }
  }

  private async getSearchCount(
    userId: string,
    dateRange: DateRange
  ): Promise<number> {
    // Implementation
    return 0;
  }
}
  1. Add Controller Methods
typescript
// src/controllers/AnalyticsController.ts
import { Request, Response } from 'express';
import { AnalyticsService } from '@/services/AnalyticsService';

export class AnalyticsController {
  constructor(private analyticsService: AnalyticsService) {}

  generateReport = async (req: Request, res: Response): Promise<void> => {
    try {
      const { userId } = req.user!;
      const { startDate, endDate } = req.query;

      const report = await this.analyticsService.generateReport(userId, {
        startDate: new Date(startDate as string),
        endDate: new Date(endDate as string),
      });

      res.json({
        success: true,
        data: report,
        meta: {
          timestamp: new Date(),
          requestId: req.id,
        },
      });
    } catch (error) {
      throw error; // Let error middleware handle it
    }
  };
}
  1. Add API Routes
typescript
// src/routes/analytics.ts
import { Router } from 'express';
import { z } from 'zod';
import { AnalyticsController } from '@/controllers/AnalyticsController';
import { authenticateApiKey, requirePermission } from '@/middleware/apiKeyAuth';
import { validateRequest } from '@/middleware/validation';

const router = Router();
const analyticsController = new AnalyticsController();

const generateReportSchema = z.object({
  query: z.object({
    startDate: z.string().datetime(),
    endDate: z.string().datetime(),
  }),
});

router.get(
  '/report',
  authenticateApiKey,
  requirePermission('analytics'),
  validateRequest(generateReportSchema),
  analyticsController.generateReport
);

export default router;
  1. Write Tests
typescript
// src/services/AnalyticsService.test.ts
import { AnalyticsService } from './AnalyticsService';

describe('AnalyticsService', () => {
  let analyticsService: AnalyticsService;
  let mockCacheService: jest.Mocked<CacheService>;
  let mockDatabaseService: jest.Mocked<DatabaseService>;

  beforeEach(() => {
    mockCacheService = createMockCacheService();
    mockDatabaseService = createMockDatabaseService();

    analyticsService = new AnalyticsService(
      mockCacheService,
      mockDatabaseService
    );
  });

  describe('generateReport', () => {
    it('should generate analytics report successfully', async () => {
      const report = await analyticsService.generateReport('user1', {
        startDate: new Date('2024-01-01'),
        endDate: new Date('2024-01-31'),
      });

      expect(report).toBeDefined();
      expect(report.searchCount).toBeGreaterThanOrEqual(0);
    });
  });
});

Debugging ​

Development Debugging ​

VS Code Launch Configuration:

json
// .vscode/launch.json
{
  "version": "0.2.1",
  "configurations": [
    {
      "name": "Launch Development Server",
      "type": "node",
      "request": "launch",
      "program": "${workspaceFolder}/src/index.ts",
      "outFiles": ["${workspaceFolder}/dist/**/*.js"],
      "env": {
        "NODE_ENV": "development"
      },
      "runtimeArgs": ["-r", "ts-node/register"],
      "console": "integratedTerminal"
    },
    {
      "name": "Debug Tests",
      "type": "node",
      "request": "launch",
      "program": "${workspaceFolder}/node_modules/.bin/jest",
      "args": ["--runInBand", "--no-cache"],
      "env": {
        "NODE_ENV": "test"
      },
      "console": "integratedTerminal"
    }
  ]
}

Debug Commands:

bash
# Debug with Node.js inspector
node --inspect-brk src/index.ts

# Debug specific service
node --inspect-brk -r ts-node/register src/services/SearchService.ts

# Debug tests
node --inspect-brk node_modules/.bin/jest --runInBand

# Debug with Chrome DevTools
node --inspect src/index.ts
# Then open chrome://inspect

Logging Strategy ​

Use structured logging for debugging:

typescript
import { logger } from '@/utils/logger';

// Different log levels
logger.debug('Detailed debugging info');
logger.info('General information');
logger.warn('Warning conditions');
logger.error('Error conditions');

// Structured logging with context
logger.info('User search request', {
  userId: 'user123',
  query: 'database optimization',
  searchMode: 'semantic',
  duration: 150,
});

// Error logging with stack trace
try {
  // Some operation
} catch (error) {
  logger.error('Operation failed', {
    error: error.message,
    stack: error.stack,
    context: { userId, requestId },
  });
}

Performance Considerations ​

Database Optimization ​

  1. Use Connection Pooling
typescript
// Proper connection management
export class DatabaseService {
  private pool: Pool;

  constructor() {
    this.pool = mysql.createPool({
      host: config.database.host,
      connectionLimit: 10,
      acquireTimeout: 60000,
      timeout: 60000,
    });
  }
}
  1. Optimize Queries
typescript
// Use prepared statements
const query = 'SELECT * FROM users WHERE id = ? AND status = ?';
const [rows] = await connection.execute(query, [userId, 'active']);

// Avoid SELECT *
const query = 'SELECT id, name, email FROM users WHERE id = ?';

// Use appropriate indexes
// CREATE INDEX idx_user_email ON users(email);
// CREATE FULLTEXT INDEX idx_content_search ON articles(title, content);
  1. Implement Caching Strategies
typescript
// Multi-level caching
async getCachedData(key: string): Promise<any> {
  // L1: In-memory cache
  let data = this.memoryCache.get(key);
  if (data) return data;

  // L2: Redis cache
  data = await this.redisCache.get(key);
  if (data) {
    this.memoryCache.set(key, data, 60); // 1 minute TTL
    return data;
  }

  // L3: Database
  data = await this.database.query(key);
  await this.redisCache.set(key, data, 300); // 5 minute TTL
  this.memoryCache.set(key, data, 60);

  return data;
}

Memory Management ​

  1. Avoid Memory Leaks
typescript
// Properly close connections
async cleanup(): Promise<void> {
  await this.databasePool.end();
  await this.redisClient.quit();
  this.eventEmitter.removeAllListeners();
}

// Use weak references for caches
const cache = new WeakMap();

// Clean up timers
const timer = setInterval(() => {}, 1000);
clearInterval(timer);
  1. Monitor Memory Usage
typescript
// Memory usage monitoring
setInterval(() => {
  const memUsage = process.memoryUsage();
  logger.info('Memory usage', {
    rss: Math.round(memUsage.rss / 1024 / 1024) + ' MB',
    heapUsed: Math.round(memUsage.heapUsed / 1024 / 1024) + ' MB',
    heapTotal: Math.round(memUsage.heapTotal / 1024 / 1024) + ' MB',
  });
}, 60000); // Every minute

Error Handling ​

Custom Error Classes ​

typescript
// src/utils/errors.ts
export class AppError extends Error {
  constructor(
    public code: string,
    public message: string,
    public statusCode: number = 500,
    public details?: any
  ) {
    super(message);
    this.name = 'AppError';
    Error.captureStackTrace(this, this.constructor);
  }
}

// Specific error types
export class ValidationError extends AppError {
  constructor(message: string, details?: any) {
    super('VALIDATION_ERROR', message, 400, details);
  }
}

export class NotFoundError extends AppError {
  constructor(resource: string) {
    super('NOT_FOUND', `${resource} not found`, 404);
  }
}

Error Handling Patterns ​

typescript
// Service layer error handling
export class SearchService {
  async search(request: SearchRequest): Promise<SearchResponse> {
    try {
      // Validate input
      if (!request.query?.trim()) {
        throw new ValidationError('Search query cannot be empty');
      }

      // Perform search
      const results = await this.executeSearch(request);
      return results;
    } catch (error) {
      if (error instanceof AppError) {
        throw error; // Re-throw known errors
      }

      // Log unexpected errors
      logger.error('Unexpected search error:', error);
      throw new AppError('SEARCH_FAILED', 'Search operation failed');
    }
  }
}

// Controller error handling (let middleware handle)
export class SearchController {
  search = async (req: Request, res: Response): Promise<void> => {
    const results = await this.searchService.search(req.body);
    res.json({ success: true, data: results });
    // Don't catch errors here - let error middleware handle them
  };
}

Security Best Practices ​

Input Validation ​

typescript
// Always validate input with Zod schemas
const searchSchema = z.object({
  query: z.string().min(1).max(1000),
  databases: z.array(z.string().uuid()),
  searchMode: z.enum(['natural', 'boolean', 'semantic']).default('natural'),
  limit: z.number().min(1).max(100).default(20),
});

// Use in middleware
export const validateRequest = (schema: z.ZodSchema) => {
  return (req: Request, res: Response, next: NextFunction) => {
    try {
      const validated = schema.parse({
        body: req.body,
        query: req.query,
        params: req.params,
      });

      req.body = validated.body || req.body;
      req.query = validated.query || req.query;
      req.params = validated.params || req.params;

      next();
    } catch (error) {
      throw new ValidationError('Invalid request data', error.errors);
    }
  };
};

SQL Injection Prevention ​

typescript
// Always use parameterized queries
const query = `
  SELECT id, title, content
  FROM articles
  WHERE MATCH(title, content) AGAINST(? IN NATURAL LANGUAGE MODE)
  AND category = ?
  LIMIT ?
`;

const [rows] = await connection.execute(query, [searchTerm, category, limit]);

// Never concatenate user input
// BAD: `SELECT * FROM users WHERE id = ${userId}`
// GOOD: Use parameterized queries as shown above

Authentication & Authorization ​

typescript
// API key authentication
export const authenticateApiKey = async (
  req: Request,
  res: Response,
  next: NextFunction
) => {
  try {
    const authHeader = req.headers.authorization;
    if (!authHeader) {
      throw new AppError('NO_API_KEY', 'Authorization header missing', 401);
    }

    const parts = authHeader.split(' ');
    if (parts.length !== 2 || parts[0] !== 'Bearer') {
      throw new AppError(
        'INVALID_AUTH_FORMAT',
        'Authorization header must be in format: Bearer <api_key>',
        401
      );
    }

    const apiKey = parts[1];
    if (!apiKey.startsWith('altus4_sk_')) {
      throw new AppError(
        'INVALID_API_KEY_FORMAT',
        'API key must start with altus4_sk_',
        401
      );
    }

    const result = await apiKeyService.validateApiKey(apiKey);
    if (!result) {
      throw new AppError('INVALID_API_KEY', 'Invalid or expired API key', 401);
    }

    const clientIp = req.ip || req.connection?.remoteAddress || 'unknown';
    await apiKeyService.updateLastUsedIp(result.apiKey.id, clientIp);

    req.user = result.user;
    req.apiKey = result.apiKey;
    next();
  } catch (error) {
    if (error instanceof AppError) {
      throw error;
    }
    throw new AppError('AUTH_ERROR', 'Authentication failed', 401);
  }
};

// Permission-based authorization for API keys
export const requirePermission = (permission: string) => {
  return (req: Request, res: Response, next: NextFunction) => {
    if (!req.apiKey) {
      throw new AppError('UNAUTHORIZED', 'Authentication required', 401);
    }

    if (!req.apiKey.permissions.includes(permission)) {
      throw new AppError(
        'INSUFFICIENT_PERMISSIONS',
        `Permission '${permission}' required`,
        403,
        {
          required: permission,
          available: req.apiKey.permissions,
        }
      );
    }
    next();
  };
};

// Role-based authorization
export const requireRole = (role: string) => {
  return (req: Request, res: Response, next: NextFunction) => {
    if (!req.user) {
      throw new AppError('UNAUTHORIZED', 'Authentication required', 401);
    }

    if (req.user.role !== 'admin' && req.user.role !== role) {
      throw new AppError('FORBIDDEN', `${role} role required`, 403, {
        required: role,
        current: req.user.role,
      });
    }
    next();
  };
};

Testing Guidelines ​

Test Structure ​

typescript
describe('ServiceName', () => {
  // Setup and teardown
  beforeEach(() => {
    // Initialize test environment
  });

  afterEach(() => {
    // Clean up after each test
  });

  describe('methodName', () => {
    it('should handle success case correctly', async () => {
      // Arrange
      const input = {
        /* test data */
      };
      const expected = {
        /* expected result */
      };

      // Act
      const result = await service.methodName(input);

      // Assert
      expect(result).toEqual(expected);
    });

    it('should handle error case gracefully', async () => {
      // Arrange
      const invalidInput = {
        /* invalid data */
      };

      // Act & Assert
      await expect(service.methodName(invalidInput)).rejects.toThrow(
        'Expected error message'
      );
    });
  });
});

Mocking External Dependencies ​

typescript
// Mock external services
jest.mock('@/services/AIService');
jest.mock('openai');

// Create typed mocks
const mockAIService = {
  isAvailable: jest.fn(),
  processSearchQuery: jest.fn(),
} as jest.Mocked<AIService>;

// Mock with implementation
mockAIService.processSearchQuery.mockImplementation(async query => {
  return { optimizedQuery: query, confidence: 0.95 };
});

Documentation Standards ​

Code Documentation ​

typescript
/**
 * Executes a search across multiple databases with AI enhancements
 *
 * @param request - Search request containing query, databases, and options
 * @returns Promise resolving to search results with metadata
 *
 * @throws {ValidationError} When search query is invalid
 * @throws {AppError} When search operation fails
 *
 * @example
 * ```typescript
 * const results = await searchService.search({
 *   query: 'database optimization',
 *   databases: ['db-1', 'db-2'],
 *   searchMode: 'semantic',
 *   limit: 20
 * });
 * ```
 */
async search(request: SearchRequest): Promise<SearchResponse> {
  // Implementation
}

API Documentation ​

Update OpenAPI specification for new endpoints:

yaml
# In openapi.yaml
/api/search:
  post:
    summary: Execute search across databases
    description: |
      Performs a comprehensive search across specified databases with optional
      AI enhancements for improved relevance and categorization.
    requestBody:
      required: true
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/SearchRequest'
    responses:
      200:
        description: Search completed successfully
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/SearchResponse'

Pull Request Process ​

Before Submitting ​

  1. Code Quality Checklist

    • [ ] Code follows style guidelines
    • [ ] All tests pass
    • [ ] Test coverage meets requirements
    • [ ] No linting errors
    • [ ] Documentation updated
  2. Testing Checklist

    • [ ] Unit tests for new functionality
    • [ ] Integration tests for new endpoints
    • [ ] Manual testing completed
    • [ ] Edge cases considered
  3. Documentation Checklist

    • [ ] Code comments added
    • [ ] API documentation updated
    • [ ] README updated if needed
    • [ ] Migration guide if breaking changes

Pull Request Template ​

markdown
## Description

Brief description of changes made.

## Type of Change

- [ ] Bug fix (non-breaking change that fixes an issue)
- [ ] New feature (non-breaking change that adds functionality)
- [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected)
- [ ] Documentation update

## Testing

- [ ] Unit tests pass
- [ ] Integration tests pass
- [ ] Manual testing completed

## Checklist

- [ ] Code follows style guidelines
- [ ] Self-review completed
- [ ] Documentation updated
- [ ] No merge conflicts

Review Process ​

  1. Automated Checks - CI pipeline runs tests and linting
  2. Peer Review - At least one team member reviews the code
  3. Integration Testing - Changes tested in staging environment
  4. Approval - Maintainer approves and merges

Release Process ​

Semantic Versioning ​

We follow SemVer:

  • MAJOR: Breaking changes (1.0.0 → 2.0.0)
  • MINOR: New features (1.0.0 → 1.1.0)
  • PATCH: Bug fixes (1.0.0 → 1.0.1)

Release Workflow ​

bash
# Create release branch
git checkout -b release/v1.2.0

# Update version numbers
npm version 1.2.0

# Update CHANGELOG.md
# Run final tests
npm run test:all

# Merge to main
git checkout main
git merge release/v1.2.0

# Tag release
git tag v1.2.0
git push origin v1.2.0

# Deploy to production
npm run deploy:production

Community & Support ​

Getting Help ​

  • Documentation: Start with this guide and API docs
  • GitHub Issues: Report bugs and request features
  • Discussions: Ask questions and share ideas
  • Discord: Real-time community chat (link in README)

Contributing Guidelines ​

  • Follow the code style and conventions
  • Write comprehensive tests
  • Update documentation
  • Be respectful and constructive
  • Help others in the community

Thank you for contributing to Altus 4! Your efforts help make MySQL search intelligent and accessible for everyone.