Development Guide
This comprehensive guide covers development best practices, coding standards, and workflows for the HostingCo system.
Development Environment Setup
Prerequisites
Node.js 18+ and npm 8+
PostgreSQL 15+
Redis 7+
Git
VS Code (recommended)
PostgreSQL 15+
Redis 7+
Git
VS Code (recommended)
Local Development Setup
1. Clone Repository
git clone https://github.com/your-org/hostingco-system.git
cd hostingco-system
2. Install Dependencies
# Use the automated setup script (recommended)
./scripts/setup.sh development
# Or install manually
npm run install:all
# Or install individually
npm install
cd backend && npm install
cd ../frontend && npm install
cd ../shared && npm install
3. Environment Configuration
# Copy environment template
cp .env.example .env
# Edit environment variables
nano .env
4. Database Setup
# Create database
createdb hostingco_dev
# Run migrations
npm run migrate:latest
# Seed database
npm run seed:dev
Development Workflow
Daily Development
# Start development servers
npm run dev
# Or start individually
npm run dev:backend # Backend on port 3003
npm run dev:frontend # Frontend on port 3000
Testing Workflow
# Run all tests
npm test
# Run tests in watch mode
npm run test:watch
# Run tests with coverage
npm run test:coverage
# Run specific test suites
npm run test:unit
npm run test:integration
npm run test:e2e
Building for Production
# Build all packages
npm run build
# Build specific packages
npm run build:frontend
npm run build:backend
# Build for production
npm run build:prod
📝 Coding Standards
TypeScript Configuration
// tsconfig.json
{
"compilerOptions": {
"target": "ES2020",
"module": "commonjs",
"lib": ["ES2020"],
"outDir": "./dist",
"rootDir": "./src",
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true,
"resolveJsonModule": true,
"declaration": true,
"declarationMap": true,
"sourceMap": true
}
}
ESLint Configuration
// .eslintrc.json
{
"extends": [
"@typescript-eslint/recommended",
"prettier"
],
"rules": {
"@typescript-eslint/no-unused-vars": "error",
"@typescript-eslint/explicit-function-return-type": "warn",
"prefer-const": "error",
"no-var": "error"
}
}
Code Style Guidelines
Functions: Use arrow functions for callbacks
Variables: Use const by default, let when needed
Classes: Use classes for complex objects
Imports: Use ES6 import/export syntax
Comments: Document complex logic and APIs
Variables: Use const by default, let when needed
Classes: Use classes for complex objects
Imports: Use ES6 import/export syntax
Comments: Document complex logic and APIs
📁 Project Structure
Monorepo Organization
hostingco-system/
├── backend/ # Node.js backend
│ ├── src/
│ │ ├── controllers/ # Route handlers
│ │ ├── middleware/ # Express middleware
│ │ ├── models/ # Database models
│ │ ├── routes/ # API routes
│ │ ├── services/ # Business logic
│ │ └── utils/ # Utility functions
│ ├── tests/ # Backend tests
│ └── package.json
├── frontend/ # React frontend
│ ├── src/
│ │ ├── components/ # React components
│ │ ├── hooks/ # Custom hooks
│ │ ├── pages/ # Page components
│ │ ├── services/ # API services
│ │ ├── utils/ # Utility functions
│ │ └── styles/ # CSS/SCSS files
│ ├── public/ # Static assets
│ └── package.json
├── shared/ # Shared code
│ ├── src/
│ │ ├── types/ # TypeScript types
│ │ └── utils/ # Shared utilities
│ └── package.json
├── scripts/ # Automation scripts
├── docs/ # Documentation
└── package.json # Root package.json
Package Management
// Root package.json
{
"private": true,
"workspaces": [
"backend",
"frontend",
"shared"
],
"scripts": {
"install:all": "npm install --workspaces",
"dev": "concurrently \"npm run dev:backend\" \"npm run dev:frontend\"",
"test": "npm run test --workspaces",
"build": "npm run build --workspaces",
"clean": "npm run clean --workspaces"
}
}
Database Development
Migration Workflow
# Create new migration
npm run migrate:create add_user_table
# Run migrations
npm run migrate:latest
# Rollback migration
npm run migrate:rollback
# Check migration status
npm run migrate:status
Database Schema
// Example model
import { knex } from '../database';
export class User {
static async findById(id: string) {
return knex('users').where('id', id).first();
}
static async create(userData: CreateUserDto) {
const [user] = await knex('users').insert(userData).returning('*');
return user;
}
static async update(id: string, updates: Partial<User>) {
return knex('users').where('id', id).update(updates);
}
}
Seeding Data
# Seed development data
npm run seed:dev
# Seed specific data
npm run seed:users
npm run seed:servers
# Reset and reseed
npm run seed:reset
🔌 API Development
Route Structure
// Example controller
import { Request, Response } from 'express';
import { UserService } from '../services/UserService';
export class UserController {
static async create(req: Request, res: Response) {
try {
const user = await UserService.create(req.body);
res.status(201).json(user);
} catch (error) {
res.status(400).json({ error: error.message });
}
}
static async getAll(req: Request, res: Response) {
try {
const users = await UserService.getAll();
res.json(users);
} catch (error) {
res.status(500).json({ error: error.message });
}
}
}
Middleware
// Authentication middleware
export const authenticate = async (req: Request, res: Response, next: NextFunction) => {
try {
const token = req.headers.authorization?.replace('Bearer ', '');
const user = await UserService.verifyToken(token);
req.user = user;
next();
} catch (error) {
res.status(401).json({ error: 'Unauthorized' });
}
};
Error Handling
// Global error handler
export const errorHandler = (error: Error, req: Request, res: Response, next: NextFunction) => {
console.error(error);
if (error instanceof ValidationError) {
return res.status(400).json({ error: error.message });
}
if (error instanceof AuthenticationError) {
return res.status(401).json({ error: error.message });
}
res.status(500).json({ error: 'Internal server error' });
};
⚛️ Frontend Development
Component Structure
// Example component
import React, { useState, useEffect } from 'react';
import { User } from '../types';
interface UserListProps {
users: User[];
onUserSelect: (user: User) => void;
}
export const UserList: React.FC<UserListProps> = ({ users, onUserSelect }) => {
const [selectedUser, setSelectedUser] = useState<User | null>(null);
return (
<div className="user-list">
{users.map(user => (
<div
key={user.id}
className={`user-item ${selectedUser?.id === user.id ? 'selected' : ''}`}
onClick={() => {
setSelectedUser(user);
onUserSelect(user);
}}
>
{user.name}
</div>
))}
</div>
);
};
State Management
// Custom hook example
import { useState, useEffect } from 'react';
import { User } from '../types';
export const useUsers = () => {
const [users, setUsers] = useState<User[]>([]);
const [loading, setLoading] = useState(true);
const [error, setError] = useState<string | null>(null);
useEffect(() => {
const fetchUsers = async () => {
try {
const response = await fetch('/api/users');
const data = await response.json();
setUsers(data);
} catch (err) {
setError(err.message);
} finally {
setLoading(false);
}
};
fetchUsers();
}, []);
return { users, loading, error };
};
Styling
/* Component-specific styles */
.user-list {
display: grid;
gap: 1rem;
padding: 1rem;
}
.user-item {
padding: 1rem;
border: 1px solid var(--border-primary);
border-radius: var(--border-radius-md);
cursor: pointer;
transition: all var(--transition-fast);
}
.user-item:hover {
background-color: var(--bg-tertiary);
transform: translateY(-1px);
}
.user-item.selected {
background-color: var(--primary-color);
color: var(--text-inverse);
}
Testing Strategy
Test Organization
tests/
├── unit/ # Unit tests
│ ├── controllers/
│ ├── services/
│ └── utils/
├── integration/ # Integration tests
│ ├── api/
│ └── database/
├── e2e/ # End-to-end tests
│ ├── user-flows/
│ └── admin-flows/
└── fixtures/ # Test data
Test Examples
// Unit test example
import { UserService } from '../services/UserService';
describe('UserService', () => {
describe('create', () => {
it('should create a new user', async () => {
const userData = {
email: 'test@example.com',
name: 'Test User'
};
const user = await UserService.create(userData);
expect(user).toBeDefined();
expect(user.email).toBe(userData.email);
expect(user.name).toBe(userData.name);
});
it('should throw error for duplicate email', async () => {
const userData = {
email: 'existing@example.com',
name: 'Test User'
};
await expect(UserService.create(userData))
.rejects.toThrow('Email already exists');
});
});
});
Test Configuration
// jest.config.js
module.exports = {
preset: 'ts-jest',
testEnvironment: 'node',
roots: ['<rootDir>/tests'],
testMatch: ['**/__tests__/**/*.ts', '**/?(*.)+(spec|test).ts'],
collectCoverageFrom: [
'src/**/*.ts',
'!src/**/*.d.ts',
'!src/index.ts'
],
coverageThreshold: {
global: {
branches: 80,
functions: 80,
lines: 80,
statements: 80
}
}
};
🐛 Debugging
Backend Debugging
# Start backend with debugging
npm run dev:debug
# Or with VS Code launch configuration
node --inspect-brk dist/index.js
Frontend Debugging
# Start frontend with debugging
npm run dev:debug
# Or with Chrome DevTools
# Open Chrome DevTools and use the React DevTools extension
VS Code Configuration
// .vscode/launch.json
{
"version": "0.2.0",
"configurations": [
{
"name": "Debug Backend",
"type": "node",
"request": "launch",
"program": "${workspaceFolder}/backend/dist/index.js",
"outFiles": ["${workspaceFolder}/backend/dist/**/*.js"],
"env": {
"NODE_ENV": "development"
}
},
{
"name": "Debug Frontend",
"type": "chrome",
"request": "launch",
"url": "http://localhost:3000",
"webRoot": "${workspaceFolder}/frontend/src"
}
]
}