Files
optima/.github/copilot-instructions.md
T
2026-02-17 21:53:14 -06:00

8.1 KiB

Copilot / AI Agent Instructions for ttscm-api

Purpose: make AI coding agents immediately productive in this repository by describing architecture, conventions, workflows, and helpful code pointers.

-- Big picture: This is a TypeScript API service (runs on Bun) using the Hono framework. The HTTP surface is implemented in src/api where small router files are mounted on a versioned router in src/api/server.ts (see the /v1 mount). Typical request flow is:

  • router (in src/api/routers/*) → controller (in src/controllers/*) → manager (in src/managers/*) → module / generated/prisma for persistence and external integrations.

  • Keep each layer focused: routers handle routing & middleware, controllers handle request validation and high-level orchestration, managers encapsulate domain/persistence logic, modules provide shared utilities (external API clients, helpers).

  • Runtime / tooling: The project runs on Bun. Dev command: npm run dev (runs bun --watch src/index.ts). DB tooling uses Prisma; generated client lives under generated/prisma (do NOT edit generated files). Key scripts in package.json:

    • dev — start the server with Bun in watch mode
    • db:genprisma generate
    • db:pushprisma migrate dev --skip-generate
  • Data layer: Prisma schema is at prisma/schema.prisma. The app imports the generated Prisma client from generated/prisma/client.ts (or generated/prisma/browser.ts in browser contexts). Always run the db:gen script after updating schema.prisma.

  • Routing & controllers: Example flow: a request hits a router in src/api/routers/* → router delegates to a controller in src/controllers/* → controller calls a manager in src/managers/* for domain/persistence logic. Important concrete patterns:

    • src/api/server.ts mounts v1 and uses v1.route("/auth", require("./routers/authRouter").default) style requires; preserve this shape when adding routes.
    • Router files export a default Hono router object (CommonJS module.exports/export default mixture is used across the codebase).
    • Controllers are single-export modules named like CompanyController.ts with named methods per action (e.g., fetch, update). Prefer small methods that call into managers/*.
    • Managers are thin domain layers (e.g., managers/companies.ts) that wrap generated/prisma calls and other I/O. Keep side effects here, keep controllers pure orchestration.
    • Use src/modules/api-utils/apiResponse.ts for every HTTP response shape (successful/created/error/internalError/zodError).
    • Use Zod schemas in controllers for request validation; server-level app.onError maps ZodError to apiResponse.zodError.

API layout & conventions (how to add a new endpoint)

  • Add router: create src/api/routers/<thing>Router.ts exporting a Hono router and mount it in src/api/server.ts under the v1 router.
  • Add controller: create src/controllers/<Thing>Controller.ts exporting functions for each action. Controllers should validate input with Zod, call managers, and return apiResponse.* results.
  • Add manager: create src/managers/<things>.ts for persistence/domain logic. Use the generated Prisma client (generated/prisma/client.ts) here; do not import Prisma directly in controllers.
  • Add modules/types: if needed, add helpers to src/modules/* and runtime types to src/types/*.
  • Middleware & auth: use src/api/middleware/authorization.ts for protecting routes; follow existing token/session patterns from src/controllers/SessionController.ts and src/Errors/*.
  • Error handling: throw repository-specific errors from src/Errors/* (include status, name, message, optional cause) and let src/api/server.ts map them via apiResponse.error.
  • Naming: prefer plural manager filenames (companies.ts) and singular controller names (CompanyController.ts) — follow existing files.

Examples & notable files

  • src/api/server.ts — mounts v1, registers cors, central onError handler and notFound response.

  • src/api/routers/companyRouter.ts and src/controllers/CompanyController.ts — canonical example for adding company endpoints.

  • src/api/user/@me/* — nested route example (use Hono sub-routers for subpaths).

  • src/modules/cw-utils/* — external API integrations; keep interfaces stable and return domain objects consumed by managers.

  • Validation & errors: Zod is used for input validation; Zod errors are handled centrally in src/api/server.ts via apiResponse.zodError. Application errors use custom error classes in src/Errors/* (e.g., AuthenticationError.ts, GenericError.ts). When creating errors, follow the shape used in existing errors (include status, name, message, and optional cause).

  • Response pattern: Use the apiResponse helpers in src/modules/api-utils/apiResponse.ts for formatting responses and status codes (successful, created, error, internalError, zodError).

  • Auth & external integrations: Microsoft OAuth flow is under src/api/auth/* and src/modules/fetchMicrosoftUser.ts. If touching authentication, follow existing redirect/refresh patterns in src/api/auth and preserve token-refresh semantics.

  • ConnectWise integration: Utilities for ConnectWise interactions live in src/modules/cw-utils/* (e.g., fetchCompanyConfigurations.ts). These modules often call external APIs and return domain data; preserve the module contracts (input types and returned shapes) when refactoring.

  • Generated files and CI: generated/ is a build artifact. Do not modify. When updating Prisma models, run npm run db:gen and commit changes to generated/prisma only if that's the established workflow.

  • Files to inspect for context / examples:

    • src/api/server.ts — central error handling, router mounting, CORS and not-found handling.
    • src/modules/api-utils/apiResponse.ts — response shaping used across controllers.
    • src/controllers/CompanyController.ts — example controller calling managers.
    • src/modules/cw-utils/fetchCompanyConfigurations.ts — example external integration utility.
    • generated/prisma/client.ts — generated Prisma client imports; avoid editing.
  • Coding conventions & patterns specific to this repo:

    • Prefer the existing layered architecture: routers → controllers → managers → modules.
    • Use the apiResponse helpers for all HTTP responses.
    • Throw or propagate repository-specific custom errors (from src/Errors/*) rather than returning bare objects.
    • Keep TypeScript types in src/types/* and use Zod for runtime checks.
    • Avoid else statements — prefer ternary operators, early returns, or other control flow patterns. Only use else if there is absolutely no other way.
  • Local dev / quick checks:

    • Start dev server: npm run dev
    • Regenerate Prisma client: npm run db:gen
    • Apply DB migrations locally: npm run db:push
  • When editing generated or infra files: if you need to change generated/prisma/* (rare), explain why in the PR and show commands used to regenerate.

  • Documentation sync (IMPORTANT): Whenever you add, remove, or modify API routes or permission nodes, you must update all three of the following files to keep them in sync:

    1. src/types/PermissionNodes.ts — the single source of truth for all permission node definitions, categories, descriptions, and usedIn references.
    2. PERMISSIONS.md — human-readable documentation of all permission nodes; must strictly reflect the data in PermissionNodes.ts.
    3. API_ROUTES.md — comprehensive documentation of all API routes, including method, path, auth requirements, permissions, request/response examples. Always verify that new routes have their required permissions listed in PermissionNodes.ts, that PERMISSIONS.md tables match the TS file exactly, and that API_ROUTES.md includes full documentation for every mounted route. Run through all three files at the end of any route or permission change to catch discrepancies.

If anything here is unclear or you'd like more examples (e.g., a walk-through editing a controller + manager + test run), tell me which area to expand and I'll iterate.