# 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 `Handler`: `WebhookHandler`, `UpdatesHandler`, `DismissHandler`, `TagsHandler`, `TagByIDHandler`, `TagAssignmentHandler` - Test functions use `Test_`: `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: ```go 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: ```go // 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:** `**():** ` **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*