infra/.planning/codebase/CONVENTIONS.md
2026-02-23 20:54:27 +00:00

192 lines
8.2 KiB
Markdown

# Coding Conventions
**Analysis Date:** 2026-02-23
## Naming Patterns
**Terraform Files:**
- `main.tf` - Primary resource definitions and module calls
- `terragrunt.hcl` - Stack-specific Terragrunt configuration
- `variables.tf` - Variable declarations for a stack
- `providers.tf` - Generated by Terragrunt root `terragrunt.hcl`
- `backend.tf` - Generated by Terragrunt for state backend configuration
**Terraform Variables:**
- snake_case for variable names: `var.tls_secret_name`, `var.dbaas_root_password`
- snake_case for resource names: `resource "kubernetes_namespace" "nextcloud"`
- snake_case for local values: `local.tiers`
- UPPERCASE for environment-like globals in shell: `KUBECONFIG_PATH`, `PASS_COUNT`
**Resource/Module Names:**
- kebab-case for Kubernetes resources: `nextcloud`, `whiteboard`, `kms-web-page`
- Leading underscore for prefixed resource names (internal/private pattern): resource names with underscores are module-internal
- Descriptive names matching functionality: `kubernetes_namespace`, `kubernetes_deployment`, `helm_release`
**Shell Functions:**
- snake_case for function names: `parse_args()`, `count_lines()`, `check_nodes()`
- CamelCase for utility color variables: `RED`, `GREEN`, `YELLOW`, `BLUE`, `BOLD`, `NC`
**Go Package/Test Names:**
- Package-level test functions: `TestContainsVideoMarkers()`, `TestIsDirectVideoContentType()`
- Table-driven test pattern with struct fields: `name`, `body`, `ct`, `want`
## Code Style
**Terraform Formatting:**
- Use `terraform fmt -recursive` for consistent formatting
- No explicit linter/formatter config file (tflint/terraform-lint not present)
- Indentation: 2 spaces (standard Terraform convention)
- Multi-line strings use heredoc syntax: `<<EOT ... EOT` for YAML/config blocks
**Bash Script Style:**
- Shebang: `#!/usr/bin/env bash`
- Safety flags: `set -euo pipefail` (exit on error, undefined vars, pipe failures)
- Comments use `# ---` separator for section dividers
- Comments use `# ---` for grouping related variables/functions
- One-liner functions defined as: `function_name() { [[ condition ]] && action; }`
- Multiline functions use explicit function body with local keyword for variables
**Terraform Style:**
- Comments for major sections use `# =============================================================================`
- Comments for subsections use `# --------- -------`
- Inline comments explain why, not what: `# anything secret is fine` (explaining arbitrary choice)
- Module calls include comments above describing purpose: `# --- Core ---`, `# --- dbaas ---`
## Import Organization
**Terraform:**
- Locals (tier definitions) defined at top of main.tf
- Variables declared in order: core/required first, then by feature area (dbaas, traefik, etc.)
- Modules called after variables, grouped by functional area with comment headers
- Resources defined after modules
**Go:**
- Standard imports from `testing` package
- No grouping (single simple import)
**Bash:**
- Source definitions at top (colors, globals, helper functions)
- Argument parsing in dedicated `parse_args()` function
- Main logic organized by check sections with `section()` calls
## Error Handling
**Terraform:**
- No explicit error handling (declarative; errors cause apply failure)
- Dependency management via `depends_on` for explicit ordering
- `dependency` blocks in terragrunt for cross-stack dependencies
- `skip_outputs = true` used when only needing ordering, not outputs
**Bash:**
- Inline error checks: `command 2>&1) || { fail "message"; return 0; }`
- `set -euo pipefail` prevents silent failures and undefined var issues
- Error status captured: `$?` implicit via `||` pattern
- Graceful degradation with fallback values or skip-able steps
**Go:**
- Standard testing error reporting: `t.Errorf()` with formatted messages
- Table-driven test pattern allows multiple related test cases
- Error messages include actual vs expected: `got = %v, want = %v`
## Logging
**Framework:** Not formally configured; uses `echo` and `echo -e` for output
**Bash Logging Patterns:**
- Color-coded output with status prefixes: `${BLUE}[INFO]${NC}`, `${GREEN}[PASS]${NC}`, `${YELLOW}[WARN]${NC}`, `${RED}[FAIL]${NC}`
- Helper functions: `info()`, `pass()`, `warn()`, `fail()` - each increments counters and respects `--quiet` flag
- Section headers: `section()` for verbose output, `section_always()` for always-shown sections
- Conditional logging: functions check `$JSON`, `$QUIET` flags and skip output as needed
- JSON output option available via `json_add()` for machine-readable logging
- Detail strings accumulated in variables for final reporting
**Terraform Logging:**
- Relies on Terraform's built-in CLI output
- Human-readable variable values in descriptions (Terraform renders these on errors)
## Comments
**When to Comment:**
Terraform:
- Section dividers: Major logical groups separated by `# =============================================================================`
- Feature group headers: `# --- Feature Name ---` before variable/module blocks
- Commented-out code: Temporarily disabled resources/modules include explanation (e.g., "Do not use until issue #X is solved")
- Clarifying arbitrary choices: `# anything secret is fine` explains non-obvious variable usage
Bash:
- Function-level comments: Each check function has purpose on first line
- Complex logic: Comments before conditional blocks explain intent
- Inline comments for edge cases: `# Skip nodes where metrics are not yet available`
- Header comments: Scripts include usage documentation at top
**JSDoc/TSDoc:**
- Not used in this codebase (Terraform, Bash, Go only)
## Function Design
**Size:**
- Terraform modules typically 20-50 lines for simple services, variable declaration blocks 30-100+ lines
- Bash functions average 20-40 lines, check functions 10-30 lines
- Go test functions 10-60 lines (table + loop)
**Parameters:**
- Terraform: via `variable` declarations and module input variables
- Bash: positional parameters passed via `$1`, `$2`, etc. with validation in `parse_args()`
- Go: test functions accept `*testing.T` parameter
**Return Values:**
- Terraform: no explicit returns; resource state is the "return"
- Bash: `return 0` for success, implicit via `echo` output for values, status codes for error handling
- Go: functions tested for boolean returns or calculated values
**Variables:**
- Terraform: module variables, locals, and resource attributes (computed values)
- Bash: Global state tracked via counters (`PASS_COUNT`, `WARN_COUNT`, `FAIL_COUNT`), local variables in functions with `local` keyword
- Go: table-driven tests use struct fields (no getter/setter pattern)
## Module Design
**Exports:**
- Terraform: outputs typically omitted unless another stack depends on them (implicit via dependency blocks)
- Modules called with `source = "./modules/<name>"` or `source = "../../modules/kubernetes/<name>"`
- Module version pinning used for Terraform registry modules: `version = "0.1.5"`
**Barrel Files:**
- Not applicable (no aggregating re-exports in this codebase)
- Directories: `stacks/<service>/` is a unit, `stacks/platform/modules/<service>/` groups related modules
**Module Organization:**
- Single responsibility per module directory
- Each module typically contains: `main.tf` (resources) and optional `variables.tf` for input variables
- Shared Kubernetes utility modules in `modules/kubernetes/`: `ingress_factory/`, `setup_tls_secret/`
- Platform services grouped in `stacks/platform/modules/<service>/`
## Special Patterns
**Locals for Configuration:**
- Tier definitions centralized as map in locals (each service defines same tiers locally)
```hcl
locals {
tiers = {
core = "0-core"
cluster = "1-cluster"
gpu = "2-gpu"
edge = "3-edge"
aux = "4-aux"
}
}
```
- Tier applied to `kubernetes_namespace` labels and `priority_class_name` for resource governance
**Inline Config Blocks:**
- YAML/config data stored in `<<EOT ... EOT` heredoc blocks within `data` maps
- Example: MetalLB address pool config in ConfigMap data
**File Inclusion:**
- `templatefile()` used for dynamic YAML values: `templatefile("${path.module}/chart_values.yaml", { var1 = value })`
- `file()` used for static file content in ConfigMap data
---
*Convention analysis: 2026-02-23*