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>
199 lines
7.8 KiB
Markdown
199 lines
7.8 KiB
Markdown
# 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:
|
|
|
|
```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:** `**<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*
|