11 KiB
11 KiB
AGENTS
Overview
- Languages: Go backend with
github.com/gin-gonic/gin,zap, PostgreSQL migrations and REST handlers underbackend/internal, plus a Vite+React+TypeScript frontend underfrontend/. - Keep the system deterministic: Go 1.22+, PostgreSQL 14+, Node 18+, npm 10+ (use
node --version/npm --versionto confirm). - Secret material lives in
/etc/calypso/config.yamlor environment variables (never commit private keys, JWT secrets, or database passwords). - The backend expects
CALYPSO_DB_PASSWORDandCALYPSO_JWT_SECRET(minimum 32 characters) before running locally or in CI.
Environment Setup
- Run
sudo ./scripts/install-requirements.shfrom the repo root to provision system dependencies on Ubuntu-like hosts before building the backend. config.yaml.exampleprovides defaults; copy it to/etc/calypso/config.yaml, then edit the file or override with theCALYPSO_*environment variables before launching.- For frontend work,
npm installfromfrontend/once before subsequent builds ornpm run devsessions.
Backend Tooling (Go)
Build & Run
make build(go build -o bin/calypso-api ./cmd/calypso-api) produces the local binary.make run(go run ./cmd/calypso-api -config config.yaml.example) is the quickest local dev server; supply-configpointing at your working config.- Production cross-build:
make build-linuxsetsCGO_ENABLED=0 GOOS=linux GOARCH=amd64and strips symbols. deploy/systemd/calypso-api.serviceis a template—copy it to/etc/systemd/system/,daemon-reload,enable, andstartto run as service.
Testing
make testrunsgo test ./...across all packages; it is the authoritative test runner today.- To run a single test, narrow the package and pass
-run:cd backend && go test ./internal/auth -run '^TestHandler_Login$'(use.to target the current package and regular expressions for test names). make test-coveragegeneratescoverage.outand opens a coverage report viago tool cover -html=coverage.out.
Lint & Format
make fmt(go fmt ./...) keeps source gofmt-clean; run it after edits and before committing.make lintrequiresgolangci-lint; install it withmake install-deps(which callsgo install github.com/golangci/golangci-lint/cmd/golangci-lint@latest).make depshandles dependency downloads and tidiesgo.mod/go.sumwhen vendor changes are necessary.
Backend Style Guidelines (Go)
Imports
- Group imports with standard library packages first, blank line, then third-party packages (gofmt enforces this).
- Do not alias imports unless needed to disambiguate. Keep third-party import paths explicit (e.g.,
github.com/gin-gonic/gin). - Prefer explicit package names (
config,database,logger) rather than dot-importing.
Formatting & Files
- Always run
gofmt(ormake fmt) before committing; gofmt enforces tabs for indentation and consistent formatting. - Keep files small (100–300 lines) and break responsibilities into
internal/common,internal/iam, etc., mirroring the current layout. - Maintain doc comments on exported functions, types, and struct fields; these comments start with the identifier they describe.
Types & Naming
- Use PascalCase (UpperCamel) for exported types/fields/methods and camelCase for internal helpers.
- Keep configuration structs descriptive (
ServerConfig,DatabaseConfig) and align YAML tags with snake_case field names. - When introducing new structs, mimic the existing tag conventions (
yaml:"field_name"). - Use short, meaningful receiver names (
func (h *Handler) ...), ideally 1–3 characters, matching current files. - Name boolean helpers
isX/shouldYand prefercfg/db/ctxas short local variables for configuration, database, and contexts.
Error Handling
- Wrap errors with
fmt.Errorf("context: %w", err)and return early. Do not swallow errors unless there is a clear action (e.g., logging + fallback). - Use
gin.Contextto respond with the appropriate HTTP status codes (c.JSON(http.StatusBadRequest, gin.H{...})). - Log warnings vs. errors via the shared
logger.Logger(h.logger.Warn(...)for expected issues,Errorfor failures,Infofor happy paths). - Avoid
panicin handlers; only panic during initialization (e.g., new logger). Instead, log and return a 5xx status. - Keep timeouts and cancellation explicit using
context.WithTimeoutwhen communicating with databases or external systems.
Logging & Observability
- Use
zap-backedlogger.NewLogger, pass service-specific names (e.g.,router,auth-handler), and attach structured pairs ("user_id", user.ID). - Allow log format and level to be configured via
CALYPSO_LOG_FORMAT/CALYPSO_LOG_LEVELif present. - Prefer adding caller info and stack traces on
Errorlevel logs when helpful. Do not sprinkle rawfmt.Printlnorlog.Print.
HTTP & Routing
- All HTTP routing lives under
internal/common/router; register handlers through route groups and middleware (auth/authZ) as seen inrouter.NewRouter. - Use Gin middleware for sessions, JWT validation, and auditing. Keep handler methods grouped by feature (auth, iam, tasks).
- Keep handler structs simple: inject shared dependencies (
db,config,logger) via constructors, then refer to them as fields. - For JSON requests/responses, mirror struct field names in
jsontags (snake_case) even if Go fields are camelCase.
Database & Migrations
- Use prepared statements or parameterized queries (see
iamandsessionstables) with$1style placeholders. - Run migrations automatically from
internal/common/database/migrations/viadatabase.RunMigrationsat startup. - Hunters: use
database.DBwrapper for connection pool handling, close connections viadefer db.Close(). - When adding new tables, drop SQL files into
db/migrations/and re-run migrations via the running service or a migration helper.
Security Notes
- JWT secrets must be strong (>=32 characters). Use environment variables, never embed secrets in code or checked-in configs.
- Database passwords, API keys, and secrets are populated via env vars (
CALYPSO_DB_PASSWORD,CALYPSO_JWT_SECRET,CALYPSO_JWT_SECRET) orconfig.yamlon the host. - All mutating endpoints should log audit events and guard via IAM roles (see
iampackage for role resolution). - Bacula client registration and capability pushes require the
bacula-adminrole; enforce it viarequireRole("bacula-admin")on/api/v1/bacula/clientsroutes.
Frontend Tooling (React + TypeScript)
Build & Run
- Work inside
frontend/. Start the dev server withnpm run dev(proxies/api→http://localhost:8080). - Production builds use
npm run build, which runstscbeforevite buildto ensure typing correctness. - Serve production output via
npm run previewif you need to smoke-test adist/snapshot.
Testing
- No automated frontend tests run currently. If you add a test harness (Jest/Vitest), ensure
npm testor equivalent is added topackage.json. - For manual verification, interact with the dev server after logging into the backend API from
localhost:3000.
Lint & Formatting
npm run lintruns ESLint across.ts/.tsxfiles with the@typescript-eslintrecommended rules andreact-hooksenforcement. It also blocks unused directives and sets--max-warnings 0.- The linter requires you to keep hooks exhaustive and avoid unused vars; prefix intentionally unused arguments with
_(e.g.,_event). tsconfig.jsonsetsstrictmode,noUnusedLocals,noUnusedParameters, andnoFallthroughCasesInSwitch. Respect these by keeping types precise and handling every branch.
Frontend Style Guidelines (TypeScript + React)
Imports & Aliases
- Use the
@/alias defined intsconfig.jsonfor slices insidesrc/(e.g.,import Layout from '@/components/Layout'). - Import React/third-party packages at the top, followed by
@/aliased modules, maintaining alphabetical order within each group. - Prefer named exports for hooks and API utilities, default exports for page components (e.g.,
export default function LoginPage()).
Formatting & Syntax
- Use single quotes for strings, omit semicolons (the repo follows Prettier/Vite defaults), and keep 2-space indentation inside JSX.
- Keep JSX clean: wrap complex class combinations and conditional fragments in template literals or helper functions, avoid inline object literal props unless necessary.
- Keep React components in kebab-case file names (e.g.,
Login.tsx,Layout.tsx) and align component names with file names.
Types & Naming
- Use
interfaceortypealiases for props and API shapes (e.g.,interface LoginRequest), and add optional fields with?. - Names for state setters, handlers, and store selectors follow camelCase (
setAuth,handleSubmit,loginMutation). - Use descriptive names for UI data (
navigation,userMenu,alerts). Keep boolean flags prefixed withis,has, orshould.
State, Hooks, & Effects
- Prefer
useState/useEffectfor local UI state andZustandstores (useAuthStore) for shared state. - Keep
useEffectdependency arrays explicit; avoid disabling exhaustive-deps rules unless documented. - Manage async server interactions with TanStack Query (
useMutation,useQuery) and centralize API clients (src/api/client.ts).
Styling & Layout
- TailwindCSS classes are used for layout (
flex,gap,bg-...). Keep className strings readable and group related classes together (spacing, color, typography). - Use utility classes for responsive behavior (
lg:hidden,px-4). For dynamic class toggling, compute the string in JS before passing it toclassName. - Keep inline styles minimal; prefer CSS utilities and shared constants (colors, text sizing) defined in tailwind config.
API & Networking
- Use
src/api/client.tsas the single Axios instance (baseURL: '/api/v1'). Attach request/response interceptors for auth token injection/401 handling. - Return typed promises from API helpers (e.g.,
Promise<LoginResponse>). Let callers handle success/errors via TanStack Query callbacks. - Use
authApi.getMe,authApi.login, etc., for all backend interactions; do not re-implement Axios calls directly in UI components.
Error Handling
- Surface backend errors by reading
error.response?.data?.error(as seen inLoginPage) and displaying friendly messages via inline UI alerts or toast components. - Clear authentication state on 401 responses using the Axios interceptor (
useAuthStore.getState().clearAuth()), then redirect to/login. - Display loading or pending states (
loginMutation.isPending) instead of disabling UI abruptly; provide visual feedback for async actions.
Repository Practices
- Keep database migration files under
db/migrations/and refer to them frominternal/common/database/migrations/for auto-run. - When adding commands or packages, update the relevant
Makefiletarget orpackage.jsonscript, and document the command in this AGENTS file. - Commit
go.mod,go.sum, andpackage-lock.json/package.jsonupdates together with code changes. - Avoid committing binaries (
bin/), coverage artifacts (coverage.out), or built frontend output (frontend/dist/). These are ignored by.gitignorebut double-check before commits.
Cursor & Copilot Rules
- There are no
.cursor/rules/,.cursorrules, or.github/copilot-instructions.mdfiles in this repository. Follow the guidelines laid out above.