Principles

Engineering Principles

Owner: Engineering Last reviewed: 2026-Q2

These principles guide how we design, build, and operate software at WorkOpti. They reflect our product needs and the stack in this repo (FastAPI + PostgreSQL + React + Azure).

1) Customer Impact > Output

  • Build the smallest valuable slice; ship iteratively.
  • Prefer changes that improve end-to-end flow (frontend → API → DB) over local optimizations.
  • Validate with metrics and feedback, not opinions.

2) Ownership Across the Stack

  • Developers own features from UX to API and data.
  • Keep contracts explicit: OpenAPI drives the TypeScript client (frontend/orval.config.ts).
  • When changing an API route or schema, update OpenAPI and regenerate clients (npm run orval).

3) Security by Default

  • Enforce secure defaults (see backend/py/main.py SecurityHeadersMiddleware; HSTS for non-dev).
  • Validate uploads strictly (file size, MIME, extensions in backend/py/core/config.py).
  • Scope access via our dual-auth model (Clerk JWT + local user, ADR-001). Avoid cross-user data leaks.
  • Never log secrets or PII. Use structured logs and trace IDs.

4) Reliability and Observability

  • Health endpoints (/health/*) must reflect actual dependencies (DB, storage, external APIs) as appropriate.
  • Instrument services with OpenTelemetry; export to Azure Monitor (see requirements and config).
  • Write idempotent and retry-safe integrations. Prefer deterministic keys (e.g., content_hash).

5) Explicit Architecture Decisions

  • Record significant decisions as ADRs (backend/py/docs/adr/*).
  • Capture context, options, decision, and consequences. Keep them short and practical.

6) Small, Reviewable Changes

  • Favor small PRs with clear intent, passing CI, and updated docs.
  • Include tests touching the changed surface: unit for pure logic, integration for routes/services.
  • Keep changes scoped; avoid opportunistic refactors unless directly improving the work at hand.

7) Paved Paths > Cleverness

  • Use established patterns in this repo (FastAPI routers, service layer, Pydantic schemas, React Query on the client).
  • Prefer composition over inheritance, functions over magic.
  • Optimize for readability; the next engineer should understand it quickly.

8) Performance with Guardrails

  • Measure first; optimize the hot path only.
  • Cache and batch external calls where safe (e.g., embeddings batching).
  • For list endpoints, paginate by default and bound query costs (indexes, selective projections).

9) Consistent Interfaces

  • Backend: Pydantic response models live in backend/py/schemas/; route groups use stable tags and prefixes.
  • Frontend: generated API clients in frontend/src/api/generated, queries via TanStack Query, errors via useApiError.
  • Keep DTOs and types synchronized through OpenAPI.

Resolving Trade-Offs

When principles conflict, use this order:

  1. Security and data isolation outrank speed, convenience, and visual polish.
  2. Reliability outranks new capability when a change risks data loss, broken auth, or failed deploys.
  3. Customer impact outranks internal elegance when both options are safe and maintainable.
  4. Consistent interfaces outrank local shortcuts when the change affects multiple clients or teams.
  5. Small changes outrank broad refactors unless the refactor is required to make the change safe.

Example: a small feature that needs a new sharing permission must first use the established authorization helpers and tests, even if a direct query would be faster to write. After that, keep the product slice narrow and defer unrelated cleanup.

10) Operational Excellence

  • CI builds containers; CD targets Azure Web Apps with commit-based tags.
  • Rollouts are incremental per environment (dev → showcase → prod). Use health + logs to verify.
  • On incidents: fix forward safely, then write a brief postmortem + action items.

Checklist for changes

  • Update OpenAPI and regenerate clients if API surface changes.
  • Add/adjust tests for new behavior.
  • Update ADRs if the change reflects a lasting architectural decision.
  • Verify security: authZ boundaries, input validation, secrets handling.
  • Ensure observability: logs, traces, and health checks cover the change.