# RF-REPORT-003: Report Builder

## Identificacion

| Campo | Valor |
|-------|-------|
| **ID** | RF-REPORT-003 |
| **Modulo** | MGN-009 Reports |
| **Titulo** | Report Builder |
| **Prioridad** | P1 - Alta |
| **Estado** | Draft |
| **Fecha** | 2025-12-05 |

---

## Descripcion

El sistema debe proporcionar una interfaz visual para que usuarios avanzados creen reportes personalizados sin necesidad de escribir SQL, seleccionando tablas, campos, filtros y agregaciones.

---

## Requisitos Funcionales

### RF-REPORT-003.1: Modelo de Datos Expuesto

Definicion de tablas y campos accesibles:

```typescript
interface DataModel {
  entities: EntityDefinition[];
  relationships: Relationship[];
}

interface EntityDefinition {
  name: string;              // Nombre tecnico
  label: string;             // Nombre UI
  description: string;
  fields: FieldDefinition[];
  category: string;          // Modulo
  permissions: string[];     // Permisos requeridos
}

interface FieldDefinition {
  name: string;
  label: string;
  type: FieldType;
  format?: string;
  aggregable: boolean;       // Puede usarse en SUM, AVG
  filterable: boolean;
  sortable: boolean;
}

interface Relationship {
  from: { entity: string; field: string };
  to: { entity: string; field: string };
  type: 'one-to-one' | 'one-to-many' | 'many-to-many';
  label: string;
}
```

### RF-REPORT-003.2: Definicion de Reporte Custom

```typescript
interface CustomReport {
  id: UUID;
  tenantId: UUID;
  createdBy: UUID;
  name: string;
  description?: string;
  entities: string[];         // Tablas usadas
  fields: ReportField[];      // Campos seleccionados
  filters: ReportFilter[];    // Filtros
  groupBy?: string[];         // Agrupacion
  orderBy?: OrderBy[];        // Ordenamiento
  limit?: number;
  isPublic: boolean;          // Compartido en tenant
  createdAt: TIMESTAMPTZ;
  updatedAt: TIMESTAMPTZ;
}

interface ReportField {
  entity: string;
  field: string;
  alias?: string;             // Nombre personalizado
  aggregate?: 'sum' | 'avg' | 'count' | 'min' | 'max';
  format?: string;
  visible: boolean;
}

interface ReportFilter {
  entity: string;
  field: string;
  operator: FilterOperator;
  value: any;
  isParameter: boolean;       // Es parametro dinamico
  parameterName?: string;
}

enum FilterOperator {
  EQ = 'eq',
  NE = 'ne',
  GT = 'gt',
  GTE = 'gte',
  LT = 'lt',
  LTE = 'lte',
  LIKE = 'like',
  IN = 'in',
  NOT_IN = 'not_in',
  IS_NULL = 'is_null',
  IS_NOT_NULL = 'is_not_null',
  BETWEEN = 'between'
}
```

### RF-REPORT-003.3: Interfaz Visual

Componentes del builder:

| Componente | Funcion |
|------------|---------|
| Entity Explorer | Arbol de tablas disponibles |
| Field Selector | Drag & drop de campos |
| Filter Builder | Constructor de filtros |
| Group By | Selector de agrupacion |
| Sort | Ordenamiento multiple |
| Preview | Vista previa de resultados |
| SQL View | Ver query generado (readonly) |

### RF-REPORT-003.4: Validaciones

```typescript
interface ReportValidation {
  isValid: boolean;
  errors: ValidationError[];
  warnings: ValidationWarning[];
  estimatedRows?: number;
  complexity: 'low' | 'medium' | 'high';
}

interface ValidationError {
  type: 'field_required' | 'invalid_filter' | 'permission_denied';
  message: string;
  field?: string;
}

interface ValidationWarning {
  type: 'large_result' | 'missing_index' | 'complex_query';
  message: string;
  suggestion?: string;
}
```

### RF-REPORT-003.5: Permisos de Datos

El builder respeta permisos:

- Solo muestra entidades permitidas al usuario
- Filtra automaticamente por tenant_id (RLS)
- Campos sensibles requieren permisos especiales
- No permite JOINs a tablas no permitidas

---

## Operaciones

### Obtener Modelo de Datos

```typescript
GET /api/v1/reports/builder/model

Response:
{
  "entities": [
    {
      "name": "contacts",
      "label": "Contactos",
      "category": "catalogs",
      "fields": [
        { "name": "name", "label": "Nombre", "type": "string", "aggregable": false },
        { "name": "total_sales", "label": "Ventas Totales", "type": "currency", "aggregable": true }
      ]
    }
  ],
  "relationships": [
    {
      "from": { "entity": "orders", "field": "contact_id" },
      "to": { "entity": "contacts", "field": "id" },
      "type": "many-to-one",
      "label": "Cliente"
    }
  ]
}
```

### Validar Reporte

```typescript
POST /api/v1/reports/builder/validate
{
  "entities": ["orders", "contacts"],
  "fields": [
    { "entity": "contacts", "field": "name" },
    { "entity": "orders", "field": "total", "aggregate": "sum" }
  ],
  "groupBy": ["contacts.name"]
}

Response:
{
  "isValid": true,
  "errors": [],
  "warnings": [
    { "type": "large_result", "message": "Puede retornar > 10,000 filas" }
  ],
  "estimatedRows": 15000,
  "complexity": "medium"
}
```

### Preview de Reporte

```typescript
POST /api/v1/reports/builder/preview
{
  "entities": [...],
  "fields": [...],
  "filters": [...],
  "limit": 10
}

Response:
{
  "columns": [...],
  "data": [...],
  "sql": "SELECT ... FROM ... WHERE ..."  // Solo lectura
}
```

### Guardar Reporte

```typescript
POST /api/v1/reports/custom
{
  "name": "Ventas por Cliente",
  "entities": ["orders", "contacts"],
  "fields": [...],
  "filters": [...],
  "isPublic": true
}

Response:
{
  "id": "uuid",
  "name": "Ventas por Cliente",
  "code": "custom_ventas_cliente_1234"
}
```

---

## Reglas de Negocio

| ID | Regla | Severidad |
|----|-------|-----------|
| BR-001 | Max 10 tablas en un reporte | Performance |
| BR-002 | Preview limitado a 100 filas | Performance |
| BR-003 | Solo campos permitidos visibles | Security |
| BR-004 | RLS aplicado automaticamente | Security |
| BR-005 | Query timeout de 30 segundos | Performance |

---

## Criterios de Aceptacion

- [ ] Interfaz drag & drop para campos
- [ ] Constructor visual de filtros
- [ ] Soporte para JOINs automaticos
- [ ] Agregaciones (SUM, AVG, COUNT)
- [ ] Preview en tiempo real
- [ ] Guardar reportes personalizados
- [ ] Compartir reportes en tenant

---

## Historial

| Version | Fecha | Autor | Cambios |
|---------|-------|-------|---------|
| 1.0 | 2025-12-05 | Requirements-Analyst | Creacion inicial |
