Skip to main content

Coding Standards

Condensed from the 17 standards documents in docs/standards/. See those for full details.

Go

Naming

  • Packages: Lowercase, single word (invoice, generator, handlers)
  • Files: Lowercase with underscores (invoice_handler.go, rate_rule.go)
  • Exported types: PascalCase (InvoiceService, GenerateRequest)
  • Unexported: camelCase (parseHTTPDSN, buildLineItems)

Error Handling

// Always wrap errors with context
if err != nil {
return fmt.Errorf("get invoice %s: %w", id, err)
}

// Check with errors.Is/errors.As, never string comparison
if errors.Is(err, ErrNotFound) {
return nil, ErrNotFound
}

// Sentinel errors per package
var (
ErrNotFound = errors.New("not found")
ErrConflict = errors.New("conflict")
ErrInvalidInput = errors.New("invalid input")
)

// Log at handler level, not deep in services
// Never log AND return the same error

Error → HTTP Mapping

ErrorHTTP Status
ErrNotFound404
ErrConflict409
ErrInvalidInput400
Unexpected500

Context

Every I/O function takes context.Context as the first parameter. Request IDs are propagated via context.

Logging

// slog only, JSON to stdout, snake_case keys
slog.Info("invoice generated",
"component", "generator",
"invoice_id", id.String(),
"deal_type", dealType,
)

// Never log secrets (tokens, passwords, API keys)

Financial Math

// Always use shopspring/decimal for money
amount := decimal.NewFromFloat(15000000.00)
total := amount.Add(overtime)

// Never float64 for financial calculations

Dependencies

Prefer stdlib. Pre-approved packages:

  • gin (HTTP), pgx/v5 (PostgreSQL), clickhouse-go/v2
  • shopspring/decimal (money), google/uuid
  • testify (testing), golang-migrate
  • prometheus/client_golang, otel (observability)

TypeScript / React

Naming

  • Components: PascalCase (InvoiceRegistry)
  • Hooks: use{Name} (useInvoices)
  • API functions: verb + noun (fetchInvoices)
  • Event handlers: handle{Event} (handleSubmit)

State Management

  • React Query for server state (centralized keys in query-keys.ts)
  • URL search params for filter state
  • React useState for local UI state
  • Custom hooks in hooks/

UI

  • shadcn/ui primitives in components/ui/ — do not modify
  • sonner for toast notifications
  • Debounce search inputs at 300ms
  • aria-label on icon buttons
  • aria-invalid on form inputs with errors

SQL

PostgreSQL

-- Plural snake_case tables
CREATE TABLE invoices (...);
CREATE TABLE invoice_line_items (...);

-- $1, $2 placeholders (never fmt.Sprintf)
SELECT * FROM invoices WHERE id = $1;

-- Named indexes
CREATE INDEX idx_invoices_status ON invoices(status);

ClickHouse

-- ? placeholders (never string interpolation)
SELECT * FROM tempo.worklogs_flat WHERE project_label IN (?) AND start_date >= ?;

-- Cast types for Go scanning
SELECT toFloat64(deal_amount), ifNull(monthly_limit, 0) FROM cdm.jira_applications;

Migrations

  • Format: {number}_{description}.{up|down}.sql
  • Every up.sql has a matching down.sql
  • Immutable once merged to main
  • Sequential numbering (000001, 000002, ...)