> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://cla-demo.postmansolutions.com/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://cla-demo.postmansolutions.com/_mcp/server.

# coding conventions

## General Coding Conventions

* **Language:** Use TypeScript with ES modules (`import ... from ...`), always including `.js` for local imports.
* **Error Handling:**
  * Do not use `process.env` directly. Always use `app.lookup(ENV_KEYS.KEY)` for configuration and secrets.
  * In `catch` blocks, use `unknown` as the error type. Only access `.message` if `error instanceof Error`.
  * Use custom error classes from `src/middleware/error.ts` for HTTP errors.
* **Logging:**
  * Use `app.log` for all logging. Never use `console.log`.
* **Dependency Injection:**
  * Register services and controllers in the DI container in `src/index.ts`.
  * Use `asClass` for classes and `asFunction` for factories.
  * Controllers and services should receive dependencies via constructor injection.
* **Validation:**
  * Use validation constants/types from `src/constants/validation.ts` and `src/types/validation.ts`.
  * Report validation errors using problem types from `src/constants/problemTypes.ts`.
* **Messaging & Pub/Sub:**
  * Use `SubscriptionHandler` and `SubscriptionMessageHandlers` patterns for Service Bus subscriptions.
  * Use `app.lookup(ENV_KEYS.KEY)` for all topic and subscription names.
  * Use the utility in `src/utils/serviceBusMessageUtils.ts` for sending messages.
* **File/Blob Utilities:**
  * Use `src/utils/blobUtils.ts` and `src/utils/fileUtils.ts` for blob/file operations.
  * Use `BlobStorageService` for Azure Blob Storage operations.
* **Controllers:**
  * Extend `BaseController` and use its `authenticate` and `authorize` methods.
  * Do not access the DI container directly in controllers; use constructor injection.
* **Formatting & Linting:**
  * Follow the ESLint rules in `eslint.config.ts`.
  * Do not use `console.log` or `process.env`.
  * Use single quotes, 4-space indentation, and trailing commas for multiline objects/arrays.
* **Testing:**
  * Use Vitest for tests. Place unit tests in `test/unit/`, service tests in `test/service/`, and contract tests in `test/contract/`.
* **Documentation:**
  * Add JSDoc comments for all public functions and classes.

## File/Folder Structure

* Place all source code in `src/`.
* Place configuration constants in `src/constants/`.
* Place type definitions in `src/types/`.
* Place utility functions in `src/utils/`.
* Place controllers in `src/controllers/`.
* Place services in `src/services/`.
* Place middleware in `src/middleware/`.
* Place subscriptions in `src/subscriptions/`.

## Example Patterns

* **Getting a config value:**

```typescript
const connectionString = await app.lookup(
  ENV_KEYS.AZURE_SERVICE_BUS_CONNECTION_STRING
);
```

* **Error handling in async functions:**

```typescript
try {
  // ...code...
} catch (error: unknown) {
  if (error instanceof Error) {
    app.log.error(error.message);
  } else {
    app.log.error("Unknown error", error);
  }
  throw error;
}
```

* **Registering a service in DI:**

```typescript
frameworkApp.server.diContainer.register({
  fileService: asClass(FileService).scoped(),
});
```

## applyTo

applyTo: \[ "**/\*.ts", "**/\*.js" ]

---

For more details, see [Copilot custom instructions documentation](https://docs.github.com/en/copilot/how-tos/custom-instructions/adding-repository-custom-instructions-for-github-copilot).