# Coding Standards ## AtlasOS - Calypso Backup Appliance **Version:** 1.0.0-alpha **Date:** 2025-01-XX **Status:** Active --- ## 1. Overview This document defines the coding standards and best practices for the Calypso project. All code must adhere to these standards to ensure consistency, maintainability, and quality. ## 2. General Principles ### 2.1 Code Quality - **Readability**: Code should be self-documenting and easy to understand - **Maintainability**: Code should be easy to modify and extend - **Consistency**: Follow consistent patterns across the codebase - **Simplicity**: Prefer simple solutions over complex ones - **DRY**: Don't Repeat Yourself - avoid code duplication ### 2.2 Code Review - All code must be reviewed before merging - Reviewers should check for adherence to these standards - Address review comments before merging ### 2.3 Documentation - Document complex logic and algorithms - Keep comments up-to-date with code changes - Write clear commit messages --- ## 3. Backend (Go) Standards ### 3.1 Code Formatting #### 3.1.1 Use gofmt - Always run `gofmt` before committing - Use `goimports` for import organization - Configure IDE to format on save #### 3.1.2 Line Length - Maximum line length: 100 characters - Break long lines for readability #### 3.1.3 Indentation - Use tabs for indentation (not spaces) - Tab width: 4 spaces equivalent ### 3.2 Naming Conventions #### 3.2.1 Packages ```go // Good: lowercase, single word, descriptive package storage package auth package monitoring // Bad: mixed case, abbreviations package Storage package Auth package Mon ``` #### 3.2.2 Functions ```go // Good: camelCase, descriptive func createZFSPool(name string) error func listNetworkInterfaces() ([]Interface, error) func validateUserInput(input string) error // Bad: unclear names, abbreviations func create(name string) error func list() ([]Interface, error) func val(input string) error ``` #### 3.2.3 Variables ```go // Good: camelCase, descriptive var poolName string var networkInterfaces []Interface var isActive bool // Bad: single letters, unclear var n string var ifs []Interface var a bool ``` #### 3.2.4 Constants ```go // Good: PascalCase for exported, camelCase for unexported const DefaultPort = 8080 const maxRetries = 3 // Bad: inconsistent casing const defaultPort = 8080 const MAX_RETRIES = 3 ``` #### 3.2.5 Types and Structs ```go // Good: PascalCase, descriptive type ZFSPool struct { ID string Name string Status string } // Bad: unclear names type Pool struct { I string N string S string } ``` ### 3.3 File Organization #### 3.3.1 File Structure ```go // 1. Package declaration package storage // 2. Imports (standard, third-party, local) import ( "context" "fmt" "github.com/gin-gonic/gin" "github.com/atlasos/calypso/internal/common/database" ) // 3. Constants const ( defaultTimeout = 30 * time.Second ) // 4. Types type Service struct { db *database.DB } // 5. Functions func NewService(db *database.DB) *Service { return &Service{db: db} } ``` #### 3.3.2 File Naming - Use lowercase with underscores: `handler.go`, `service.go` - Test files: `handler_test.go` - One main type per file when possible ### 3.4 Error Handling #### 3.4.1 Error Return ```go // Good: always return error as last value func createPool(name string) (*Pool, error) { if name == "" { return nil, fmt.Errorf("pool name cannot be empty") } // ... } // Bad: panic, no error return func createPool(name string) *Pool { if name == "" { panic("pool name cannot be empty") } } ``` #### 3.4.2 Error Wrapping ```go // Good: wrap errors with context if err != nil { return fmt.Errorf("failed to create pool %s: %w", name, err) } // Bad: lose error context if err != nil { return err } ``` #### 3.4.3 Error Messages ```go // Good: clear, actionable error messages return fmt.Errorf("pool '%s' already exists", name) return fmt.Errorf("insufficient disk space: need %d bytes, have %d bytes", needed, available) // Bad: unclear error messages return fmt.Errorf("error") return fmt.Errorf("failed") ``` ### 3.5 Comments #### 3.5.1 Package Comments ```go // Package storage provides storage management functionality including // ZFS pool and dataset operations, disk discovery, and storage repository management. package storage ``` #### 3.5.2 Function Comments ```go // CreateZFSPool creates a new ZFS pool with the specified configuration. // It validates the pool name, checks disk availability, and creates the pool. // Returns an error if the pool cannot be created. func CreateZFSPool(ctx context.Context, name string, disks []string) error { // ... } ``` #### 3.5.3 Inline Comments ```go // Good: explain why, not what // Retry up to 3 times to handle transient network errors for i := 0; i < 3; i++ { // ... } // Bad: obvious comments // Loop 3 times for i := 0; i < 3; i++ { // ... } ``` ### 3.6 Testing #### 3.6.1 Test File Naming - Test files: `*_test.go` - Test functions: `TestFunctionName` - Benchmark functions: `BenchmarkFunctionName` #### 3.6.2 Test Structure ```go func TestCreateZFSPool(t *testing.T) { tests := []struct { name string input string wantErr bool }{ { name: "valid pool name", input: "tank", wantErr: false, }, { name: "empty pool name", input: "", wantErr: true, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { err := createPool(tt.input) if (err != nil) != tt.wantErr { t.Errorf("createPool() error = %v, wantErr %v", err, tt.wantErr) } }) } } ``` ### 3.7 Concurrency #### 3.7.1 Context Usage ```go // Good: always accept context as first parameter func (s *Service) CreatePool(ctx context.Context, name string) error { // Use context for cancellation and timeout ctx, cancel := context.WithTimeout(ctx, 30*time.Second) defer cancel() // ... } // Bad: no context func (s *Service) CreatePool(name string) error { // ... } ``` #### 3.7.2 Goroutines ```go // Good: use context for cancellation go func() { ctx, cancel := context.WithCancel(ctx) defer cancel() // ... }() // Bad: no cancellation mechanism go func() { // ... }() ``` ### 3.8 Database Operations #### 3.8.1 Query Context ```go // Good: use context for queries rows, err := s.db.QueryContext(ctx, query, args...) // Bad: no context rows, err := s.db.Query(query, args...) ``` #### 3.8.2 Transactions ```go // Good: use transactions for multiple operations tx, err := s.db.BeginTx(ctx, nil) if err != nil { return err } defer tx.Rollback() // ... operations ... if err := tx.Commit(); err != nil { return err } ``` --- ## 4. Frontend (TypeScript/React) Standards ### 4.1 Code Formatting #### 4.1.1 Use Prettier - Configure Prettier for consistent formatting - Format on save enabled - Maximum line length: 100 characters #### 4.1.2 Indentation - Use 2 spaces for indentation - Consistent spacing in JSX ### 4.2 Naming Conventions #### 4.2.1 Components ```typescript // Good: PascalCase, descriptive function StoragePage() { } function CreatePoolModal() { } function NetworkInterfaceCard() { } // Bad: unclear names function Page() { } function Modal() { } function Card() { } ``` #### 4.2.2 Functions ```typescript // Good: camelCase, descriptive function createZFSPool(name: string): Promise { } function handleSubmit(event: React.FormEvent): void { } function formatBytes(bytes: number): string { } // Bad: unclear names function create(name: string) { } function handle(e: any) { } function fmt(b: number) { } ``` #### 4.2.3 Variables ```typescript // Good: camelCase, descriptive const poolName = 'tank' const networkInterfaces: NetworkInterface[] = [] const isActive = true // Bad: unclear names const n = 'tank' const ifs: any[] = [] const a = true ``` #### 4.2.4 Constants ```typescript // Good: UPPER_SNAKE_CASE for constants const DEFAULT_PORT = 8080 const MAX_RETRIES = 3 const API_BASE_URL = '/api/v1' // Bad: inconsistent casing const defaultPort = 8080 const maxRetries = 3 ``` #### 4.2.5 Types and Interfaces ```typescript // Good: PascalCase, descriptive interface ZFSPool { id: string name: string status: string } type PoolStatus = 'online' | 'offline' | 'degraded' // Bad: unclear names interface Pool { i: string n: string s: string } ``` ### 4.3 File Organization #### 4.3.1 Component Structure ```typescript // 1. Imports (React, third-party, local) import { useState } from 'react' import { useQuery } from '@tanstack/react-query' import { zfsApi } from '@/api/storage' // 2. Types/Interfaces interface Props { poolId: string } // 3. Component export default function PoolDetail({ poolId }: Props) { // 4. Hooks const [isLoading, setIsLoading] = useState(false) // 5. Queries const { data: pool } = useQuery({ queryKey: ['pool', poolId], queryFn: () => zfsApi.getPool(poolId), }) // 6. Handlers const handleDelete = () => { // ... } // 7. Effects useEffect(() => { // ... }, [poolId]) // 8. Render return ( // JSX ) } ``` #### 4.3.2 File Naming - Components: `PascalCase.tsx` (e.g., `StoragePage.tsx`) - Utilities: `camelCase.ts` (e.g., `formatBytes.ts`) - Types: `camelCase.ts` or `types.ts` - Hooks: `useCamelCase.ts` (e.g., `useStorage.ts`) ### 4.4 TypeScript #### 4.4.1 Type Safety ```typescript // Good: explicit types function createPool(name: string): Promise { // ... } // Bad: any types function createPool(name: any): any { // ... } ``` #### 4.4.2 Interface Definitions ```typescript // Good: clear interface definitions interface ZFSPool { id: string name: string status: 'online' | 'offline' | 'degraded' totalCapacityBytes: number usedCapacityBytes: number } // Bad: unclear or missing types interface Pool { id: any name: any status: any } ``` ### 4.5 React Patterns #### 4.5.1 Hooks ```typescript // Good: custom hooks for reusable logic function useZFSPool(poolId: string) { return useQuery({ queryKey: ['pool', poolId], queryFn: () => zfsApi.getPool(poolId), }) } // Usage const { data: pool } = useZFSPool(poolId) ``` #### 4.5.2 Component Composition ```typescript // Good: small, focused components function PoolCard({ pool }: { pool: ZFSPool }) { return (
) } // Bad: large, monolithic components function PoolCard({ pool }: { pool: ZFSPool }) { // 500+ lines of JSX } ``` #### 4.5.3 State Management ```typescript // Good: use React Query for server state const { data, isLoading } = useQuery({ queryKey: ['pools'], queryFn: zfsApi.listPools, }) // Good: use local state for UI state const [isModalOpen, setIsModalOpen] = useState(false) // Good: use Zustand for global UI state const { user, setUser } = useAuthStore() ``` ### 4.6 Error Handling #### 4.6.1 Error Boundaries ```typescript // Good: use error boundaries function ErrorBoundary({ children }: { children: React.ReactNode }) { // ... } // Usage ``` #### 4.6.2 Error Handling in Queries ```typescript // Good: handle errors in queries const { data, error, isLoading } = useQuery({ queryKey: ['pools'], queryFn: zfsApi.listPools, onError: (error) => { console.error('Failed to load pools:', error) // Show user-friendly error message }, }) ``` ### 4.7 Styling #### 4.7.1 TailwindCSS ```typescript // Good: use Tailwind classes

Storage Pools

// Bad: inline styles

Storage Pools

``` #### 4.7.2 Class Organization ```typescript // Good: logical grouping className="flex items-center gap-4 p-6 bg-card-dark rounded-lg border border-border-dark hover:bg-border-dark transition-colors" // Bad: random order className="p-6 flex border rounded-lg items-center gap-4 bg-card-dark border-border-dark" ``` ### 4.8 Testing #### 4.8.1 Component Testing ```typescript // Good: test component behavior describe('StoragePage', () => { it('displays pools when loaded', () => { render() expect(screen.getByText('tank')).toBeInTheDocument() }) it('shows loading state', () => { render() expect(screen.getByText('Loading...')).toBeInTheDocument() }) }) ``` --- ## 5. Git Commit Standards ### 5.1 Commit Message Format ``` ():