> ## Documentation Index
> Fetch the complete documentation index at: https://docs-kfhye.zochil.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Code Style & Conventions

> Coding standards and conventions for Zochil API development

## Naming Conventions

### Files and Directories

* **Routes**: Use kebab-case for route files: `user-profiles/routes.ts`
* **Services**: Use PascalCase for service files: `UserProfileService.ts`
* **Directories**: Use kebab-case: `user-api/`, `merchant-profiles/`
* **API Endpoints**: Use kebab-case in URLs: `/user-profiles/`, `/merchant-settings/`

### Code Elements

* **Classes**: PascalCase - `UserService`, `ProductCatalogService`
* **Methods**: camelCase - `getUserProfile()`, `createProduct()`
* **Variables**: camelCase - `userId`, `productData`, `isAuthenticated`
* **Constants**: UPPER\_SNAKE\_CASE - `DATABASE_URL`, `JWT_SECRET`
* **Interfaces/Types**: PascalCase - `DBConnection`, `ApiRequest`

### Database Schema

* **Tables**: snake\_case - `user_profiles`, `product_categories`
* **Columns**: snake\_case - `user_id`, `created_at`, `merchant_id`
* **Multi-tenancy**: Always include `shop_id` or `merchant_id`

## Import Organization

Organize imports in the following order with blank lines between groups:

```typescript theme={null}
// 1. Standard library imports
import { Router } from "express";
import { body as checkBody } from "express-validator";

// 2. Core modules (using 'core' alias)
import APIService from "core/base/service";
import { DBConnection, ID } from "core/types";
import { authenticateUser } from "core/auth/middlewares";

// 3. Shared libraries (using 'lib' alias)
import { CustomError } from "lib/errors/custom_error";
import kv from "lib/connectors/redis";

// 4. Local modules (relative imports)
import SomeService from "./service";
import { validateInput } from "../utils/validation";
```

## Module Structure

### Service Class Pattern

All service classes must extend `APIService` and follow this pattern:

```typescript theme={null}
import APIService from "core/base/service";
import { DBConnection, ID } from "core/types";

export default class ModuleService extends APIService {
  constructor(db: DBConnection) {
    super(db, "table_name");
  }

  async list(filters = {}, pagination = {}) {
    return await this.findForList(filters, pagination);
  }

  async detail(id: ID) {
    return await this.findOneOrThrow(id);
  }

  async create(data: any) {
    // Validation logic
    return await this.create(data);
  }
}
```

### Route Handler Pattern

Route files must export a function that accepts `DBConnection`:

```typescript theme={null}
import { Router } from "express";
import { body as checkBody } from "express-validator";
import ModuleService from "./service";
import { DBConnection } from "core/types";

export default (db: DBConnection) => {
  const routes: any = Router();
  const service = new ModuleService(db);

  routes.get(
    "/list",
    service.handleOk(
      async (req) =>
        await service.list(req.query, {
          page: parseInt(req.query.page as string) || 1,
          limit: parseInt(req.query.limit as string) || 50
        })
    )
  );

  return routes;
};
```

## Error Handling

### Custom Error Usage

Always use `CustomError` from the shared library:

```typescript theme={null}
import { CustomError } from "lib/errors/custom_error";

// In service methods
if (!user) {
  throw new CustomError("USER_NOT_FOUND", "User not found with given ID", {
    userId: id
  });
}

if (!req.currentUser.is_super) {
  throw new CustomError("FORBIDDEN", "Super admin access required");
}
```

### Response Handling

Use the `service.handleOk()` pattern for consistent responses:

```typescript theme={null}
routes.post(
  "/create",
  [checkBody("name").notEmpty()],
  service.handleOk(async (req) => {
    const result = await service.create(req.body);
    return { message: "Created successfully", data: result };
  })
);
```

## Database Access

### Multi-tenancy Pattern

Always filter by merchant/shop ID for data isolation:

```typescript theme={null}
async getUsersByShop(shopId: ID) {
  return await this.connector.db("users")
    .where("shop_id", shopId)
    .select("*");
}

async createProduct(data: any, merchantId: ID) {
  return await this.connector.db("products")
    .insert({
      ...data,
      shop_id: merchantId,
      created_at: new Date()
    });
}
```

### Query Patterns

Use Knex.js patterns consistently:

```typescript theme={null}
// List with pagination
async findForList(filters = {}, pagination = { page: 1, limit: 50 }) {
  const query = this.connector.db(this.tableName);

  // Apply filters
  if (filters.status) {
    query.where("status", filters.status);
  }

  // Apply pagination
  const offset = (pagination.page - 1) * pagination.limit;
  query.offset(offset).limit(pagination.limit);

  return await query;
}
```

## Authentication & Authorization

### Request Context Usage

Access user context from authenticated requests:

```typescript theme={null}
routes.get(
  "/profile",
  service.handleOk(async (req) => {
    // User data available after authentication
    const userId = req.currentUser.id;
    const merchantId = req.merchant_id;

    return await service.getUserProfile(userId, merchantId);
  })
);
```

### Role-based Access

Check permissions using user context:

```typescript theme={null}
// Check super admin status
if (!req.currentUser.is_super) {
  throw new CustomError("FORBIDDEN", "Super admin required");
}

// Check specific roles
const hasPermission = req.currentUser.roles.includes("merchant_manager");
if (!hasPermission) {
  throw new CustomError("FORBIDDEN", "Insufficient permissions");
}
```

## Event Publishing

### Domain Events

Publish events for important domain actions:

```typescript theme={null}
async createOrder(orderData: any) {
  const order = await this.create(orderData);

  // Publish domain event
  await this.publishEvent("order.created", {
    orderId: order.id,
    merchantId: order.merchant_id,
    amount: order.total,
    timestamp: new Date()
  });

  return order;
}
```

## TypeScript Usage

### Type Safety

Use proper typing throughout:

```typescript theme={null}
import { ID, ApiRequest } from "core/types";

interface CreateProductRequest {
  name: string;
  price: number;
  category_id: ID;
  merchant_id: ID;
}

async createProduct(data: CreateProductRequest): Promise<Product> {
  return await this.create(data);
}
```

### Path Aliases

Use configured path aliases for imports:

```typescript theme={null}
// Use 'core' alias for @core modules
import APIService from "core/base/service";
import { DBConnection } from "core/types";

// Use 'lib' alias for lib modules
import { CustomError } from "lib/errors/custom_error";
import kv from "lib/connectors/redis";
```
