Files
DiunDashboard/.planning/codebase/CONVENTIONS.md
Jean-Luc Makiola 96c4012e2f chore: add GSD codebase map with 7 analysis documents
Parallel analysis of tech stack, architecture, structure,
conventions, testing patterns, integrations, and concerns.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-23 19:13:23 +01:00

7.8 KiB

Coding Conventions

Analysis Date: 2026-03-23

Naming Patterns

Go Files:

  • Package-level source files use the package name: diunwebhook.go
  • Test files follow Go convention: diunwebhook_test.go
  • Test-only export files: export_test.go
  • Entry point: main.go inside cmd/diunwebhook/

Go Functions:

  • PascalCase for exported functions: WebhookHandler, UpdateEvent, InitDB, GetUpdates
  • Handler functions are named <Noun>Handler: WebhookHandler, UpdatesHandler, DismissHandler, TagsHandler, TagByIDHandler, TagAssignmentHandler
  • Test functions use Test<FunctionName>_<Scenario>: TestWebhookHandler_BadRequest, TestDismissHandler_NotFound

Go Types:

  • PascalCase structs: DiunEvent, UpdateEntry, Tag
  • JSON tags use snake_case: json:"diun_version", json:"hub_link", json:"received_at"

Go Variables:

  • Package-level unexported variables use short names: mu, db, webhookSecret
  • Local variables use short idiomatic Go names: w, r, err, res, n, e

TypeScript Files:

  • Components: PascalCase .tsx files: ServiceCard.tsx, AcknowledgeButton.tsx, Header.tsx, TagSection.tsx
  • Hooks: camelCase with use prefix: useUpdates.ts, useTags.ts
  • Types: camelCase .ts files: diun.ts
  • Utilities: camelCase .ts files: utils.ts, time.ts, serviceIcons.ts
  • UI primitives (shadcn): lowercase .tsx files: badge.tsx, button.tsx, card.tsx, tooltip.tsx

TypeScript Functions:

  • camelCase for regular functions and hooks: fetchUpdates, useUpdates, getServiceIcon
  • PascalCase for React components: ServiceCard, StatCard, AcknowledgeButton
  • Helper functions within components use camelCase: getInitials, getTag, getShortName
  • Event handlers prefixed with handle: handleDragEnd, handleNewGroupSubmit

TypeScript Types:

  • PascalCase interfaces: DiunEvent, UpdateEntry, Tag, ServiceCardProps
  • Type aliases: PascalCase: UpdatesMap
  • Interface properties use snake_case matching the Go JSON tags: diun_version, hub_link

Code Style

Go Formatting:

  • gofmt enforced in CI (formatting check fails the build)
  • No additional Go linter (golangci-lint) configured
  • go vet runs in CI
  • Standard Go formatting: tabs for indentation

TypeScript Formatting:

  • No ESLint or Prettier configured in the frontend
  • No formatting enforcement in CI for frontend code
  • Consistent 2-space indentation observed in all .tsx and .ts files
  • Single quotes for strings in TypeScript
  • No semicolons (observed in all frontend files)
  • Trailing commas used in multi-line constructs

TypeScript Strictness:

  • strict: true in tsconfig.app.json
  • noUnusedLocals: true
  • noUnusedParameters: true
  • noFallthroughCasesInSwitch: true
  • noUncheckedSideEffectImports: true

Import Organization

Go Import Order: Standard library imports come first, followed by a blank line, then the project import using the module alias:

import (
    "bytes"
    "encoding/json"
    "net/http"
    "net/http/httptest"
    "os"
    "testing"

    diun "awesomeProject/pkg/diunwebhook"
)
  • The project module is aliased as diun in both main.go and test files
  • The blank-import pattern _ "modernc.org/sqlite" is used for the SQLite driver in pkg/diunwebhook/diunwebhook.go

TypeScript Import Order:

  1. React and framework imports (react, @dnd-kit/core)
  2. Internal imports using @/ path alias (@/hooks/useUpdates, @/components/Header)
  3. Type-only imports: import type { Tag, UpdatesMap } from '@/types/diun'

Path Aliases:

  • @/ maps to frontend/src/ (configured in vite.config.ts and tsconfig.app.json)

Error Handling

Go Patterns:

  • Handlers use http.Error(w, message, statusCode) for all error responses
  • Error messages are lowercase: "bad request", "internal error", "not found", "method not allowed"
  • Internal errors are logged with log.Printf before returning HTTP 500
  • Decode errors include context: log.Printf("WebhookHandler: failed to decode request: %v", err)
  • Fatal errors in main.go use log.Fatalf
  • errors.Is() used for sentinel error comparison (e.g., http.ErrServerClosed)
  • String matching used for SQLite constraint errors: strings.Contains(err.Error(), "UNIQUE")

TypeScript Patterns:

  • API errors throw with HTTP status: throw new Error(\HTTP ${res.status}`)`
  • Catch blocks use console.error for logging
  • Error state stored in hook state: setError(e instanceof Error ? e.message : 'Failed to fetch updates')
  • Optimistic updates used for tag assignment (update UI first, then call API)

Logging

Framework: Go standard log package

Patterns:

  • Startup messages: log.Printf("Listening on :%s", port)
  • Warnings: log.Println("WARNING: WEBHOOK_SECRET not set ...")
  • Request logging on success: log.Printf("Update received: %s (%s)", event.Image, event.Status)
  • Error logging before HTTP error response: log.Printf("WebhookHandler: failed to store event: %v", err)
  • Handler name prefixed to log messages: "WebhookHandler: ...", "UpdatesHandler: ..."

Frontend: console.error for API failures, no structured logging

Comments

When to Comment:

  • Comments are sparse in the Go codebase
  • Handler functions have short doc comments describing the routes they handle:
    // TagsHandler handles GET /api/tags and POST /api/tags
    // TagByIDHandler handles DELETE /api/tags/{id}
    // TagAssignmentHandler handles PUT /api/tag-assignments and DELETE /api/tag-assignments
    
  • Inline comments used for non-obvious behavior: // Migration: add acknowledged_at to existing databases
  • No JSDoc/TSDoc in the frontend codebase

Function Design

Go Handler Pattern:

  • Each handler is a standalone func(http.ResponseWriter, *http.Request)
  • Method checking done at the top of each handler (not via middleware)
  • Multi-method handlers use switch r.Method
  • URL path parameters extracted via strings.TrimPrefix
  • Request bodies decoded with json.NewDecoder(r.Body).Decode(&target)
  • Responses written with json.NewEncoder(w).Encode(data) or w.WriteHeader(status)
  • Mutex (mu) used around write operations to SQLite

TypeScript Hook Pattern:

  • Custom hooks return object with state and action functions
  • useCallback wraps all action functions
  • useEffect for side effects (polling, initial fetch)
  • State updates use functional form: setUpdates(prev => { ... })

Module Design

Go Exports:

  • Single package diunwebhook exports all types and handler functions
  • No barrel files; single source file diunwebhook.go contains everything
  • Test helpers exposed via export_test.go (only visible to _test packages)

TypeScript Exports:

  • Named exports for all components, hooks, and utilities
  • Default export only for the root App component (export default function App())
  • Type exports use export interface or export type
  • @/components/ui/ contains shadcn primitives (badge.tsx, button.tsx, etc.)

Git Commit Message Conventions

Format: Conventional Commits with bold markdown formatting

Pattern: **<type>(<scope>):** <description>

Types observed:

  • feat - new features
  • fix - bug fixes
  • docs - documentation changes
  • chore - maintenance tasks (deps, config)
  • refactor - code restructuring
  • style - UI/styling changes
  • test - test additions

Scopes observed: docs, compose, webhook, ci, ui, main, errors, sql, api, deps, stats

Examples:

**feat(webhook):** add `WEBHOOK_SECRET` for token authentication support
**fix(ci):** improve version bump script for robustness and compatibility
**docs:** expand `index.md` with architecture, quick start, and tech stack
**chore(docs):** add `.gitignore` for `docs` and introduce `bun.lock` file

Multi-change commits: Use bullet list with each item prefixed by - **type(scope):**


Convention analysis: 2026-03-23