XYLEX Group
DevelopmentResource Framework

Resource Routes

Resource routes

Describe how a table or view appears in the list and drilldown, and which behaviors are enabled. Routes are defined in packages/resource-framework/registries/resource-routes.ts. When a static entry is missing, the components can load a row from the resource_routes database table.

What a route controls

  • table and id columns, optional schema
  • search configuration (enableSearch, searchBy)
  • columns to display (and their labels, widths, links)
  • edit policy (allowed/denied columns, scope)
  • drilldown behavior (prefix, custom href, permanent edit mode)
  • creation behavior (scopes, optional dialog / onClick)
  • per‑resource caching (force_no_cache), sidebar scoping, page labels

Minimal example

export const RESOURCE_ROUTES = {
  invoices: {
    table: "invoices",
    idColumn: "invoice_id",
    enableSearch: true,
    searchBy: "invoice_nr,recipient_company,status",
  },
} as const;
```typescript

### Columns

- Use `defineColumns` for convenience or provide a raw `columns` array with `column_name` and optional display metadata.
- Optionally add `href` with `{{column}}` placeholders to link to related entities.

### Edit policy

- Enable edits with `edit.enabled: true`
- Use `allowedColumns` / `deniedColumns` to restrict which fields can be updated
- Gate edits behind a `scope` string if needed

### Caching

- Set `force_no_cache: true` to always send `Cache-Control: no-cache`
- Set `force_no_cache: false` to always allow cache
- Omit to fall back to the scope‑based default (see caching.md)

### Company ownership

- Receipts, invoices, and quotes use `author_company_id` as their company ownership key.
- Credit notes use `company_id` as their company ownership key.

You can explicitly control this per resource with `companyIdColumn` in the route definition. This determines which column is used for scoping, filtering, and mutation checks:

```typescript
export const RESOURCE_ROUTES = {
  invoices: {
    table: "invoices",
    idColumn: "invoice_id",
    companyIdColumn: "author_company_id",
  },
  quotes: {
    table: "quotes",
    idColumn: "quote_id",
    companyIdColumn: "author_company_id",
  },
  credit_notes: {
    table: "credit_notes",
    idColumn: "credit_note_id",
    companyIdColumn: "company_id",
  },
  receipts: {
    table: "receipts",
    idColumn: "receipt_id",
    companyIdColumn: "author_company_id",
  },
} as const;
```typescript

### Static vs database‑driven

- If a static entry is present, it is used as‑is
- If missing, the components try to load `resource_routes` for the current `resource_name` or `table` and map fields into `ResourceRoute`

### Categories (tabbed edit)

- Add `categories?: string[]` to declare the tabs order
- Add `category?: string` per column to group fields into those tabs on the drilldown edit page