# Descoberta automática de rotas (`report-routes-runtime`)

Módulo independente para aplicações Node/Express que organizam relatórios em pastas `*Report`.

## Convenção

| Pasta | Rota (com `basePath: '/'`) |
|---|---|
| `lotes/dicon/termo/cienciaReport` | `/lotes/dicon/termo/ciencia` |
| `financeiro/extratoReport` | `/financeiro/extrato` |
| `vendas/pedidoClienteReport` | `/vendas/pedidoCliente` |

- Varre recursivamente `rootDir`.
- Considera pasta de relatório se o nome **termina com `Report`** (sufixo configurável).
- Remove **apenas** esse sufixo do segmento da pasta do relatório (pastas intermediárias como `lotes` permanecem iguais).
- Por padrão exige `controller.js` dentro da pasta.

## API

```js
const {
  discoverReportRoutes,
  mountReportRoutes,
  createReportRouter,
  toRoutePath,
  stripReportSuffix
} = require('@crystal-node/runtime');

// ou:
// const routes = require('@crystal-node/runtime/report-routes-runtime');
```

### `discoverReportRoutes(rootDir, options?)`

Retorna array:

```js
{
  folderName: 'cienciaReport',
  absolutePath: '/abs/.../cienciaReport',
  relativePath: 'lotes/dicon/termo/cienciaReport',
  route: '/lotes/dicon/termo/ciencia',
  controllerPath: '/abs/.../controller.js',
  hasController: true
}
```

### `mountReportRoutes(appOrRouter, options)`

Registra cada controller no Express (`app.post(route, handler)` por padrão).

### `createReportRouter(options)`

Atalho que cria um `express.Router()` e monta as rotas nele.  
Requer `express` instalado na app hospedeira: https://www.npmjs.com/package/express

### Opções

| Opção | Default | Descrição |
|---|---|---|
| `rootDir` | — | Pasta raiz a varrer (**obrigatório**) |
| `basePath` | `'/'` | Prefixo da rota (`'/api'`, `'/reports'`, …) |
| `method` / `methods` | `'post'` | Verbo(s) HTTP |
| `suffix` | `'Report'` | Sufixo que identifica a pasta |
| `controllerFile` | `'controller.js'` | Arquivo do handler |
| `requireController` | `true` | Ignora pasta sem controller |
| `stripReportFromAllSegments` | `false` | Se `true`, remove `Report` de qualquer segmento do caminho |
| `ignore` | `['node_modules','.git','puppeteer-debug']` | Pastas ignoradas |
| `onConflict` | lança erro | Callback se duas pastas gerarem a mesma rota |
| `loadController` | `require(path)` | Customiza o carregamento do handler |

## Exemplos

### Montar na raiz do app

```js
mountReportRoutes(app, {
  rootDir: path.join(__dirname, 'src/core'),
  method: 'post'
});
```

### Prefixo `/api` + GET e POST

```js
mountReportRoutes(app, {
  rootDir: path.join(__dirname, 'src/core'),
  basePath: '/api',
  methods: ['get', 'post']
});
```

### Router isolado

```js
const reportRouter = createReportRouter({
  rootDir: path.join(__dirname, 'src/core'),
  basePath: '/' // relativo ao ponto de mount
});
app.use('/reports', reportRouter);
// cienciaReport vira POST /reports/lotes/dicon/termo/ciencia
```

## Conflitos

Se duas pastas diferentes produzirem a mesma rota, a descoberta lança erro.  
Isso costuma indicar pastas renomeadas de forma ambígua (ex.: `fooReport` e `foo` + algo que colida). Use `onConflict` só se souber o que está fazendo.

## Uso sem Express

`discoverReportRoutes` é agnóstico de framework. Você pode iterar o resultado e registrar no Fastify, Koa, etc.:

```js
const found = discoverReportRoutes(rootDir);
for (const item of found) {
  const handler = require(item.controllerPath);
  // fastify.post(item.route, handler) etc.
}
```
