# 02 — Diagramas de entidades (ERD)

Objetivo: tener un modelo entendible para construir MVP sin “stock en Excel” y con auditoría.

Principios (de `inputs/arquitectura_tecnica.md`):
- Nada se borra (soft delete / inmutabilidad).
- Stock se calcula por movimientos.
- Multi-tenant por `organization_id`.

---

## A) ERD — Núcleo MVP (ledger + contenedores + balanza)

```mermaid
erDiagram
  ORGANIZATION ||--o{ USER : has
  ORGANIZATION ||--o{ GENETIC : defines
  ORGANIZATION ||--o{ CONTAINER : owns
  ORGANIZATION ||--o{ MOVEMENT : records
  ORGANIZATION ||--o{ AUDIT_LOG : logs
  ORGANIZATION ||--o{ SCALE_DEVICE : has

  USER ||--o{ MOVEMENT : creates
  USER ||--o{ AUDIT_LOG : acts
  USER ||--o{ SCALE_CAPTURE : triggers

  CONTAINER_TYPE ||--o{ CONTAINER : categorizes
  GENETIC ||--o{ CONTAINER : may_hold

  MOVEMENT ||--o{ MOVEMENT_LINE : has
  CONTAINER ||--o{ MOVEMENT_LINE : from_to
  GENETIC ||--o{ MOVEMENT_LINE : references

  SCALE_DEVICE ||--o{ SCALE_CAPTURE : produces
  SCALE_CAPTURE ||--o{ MOVEMENT_LINE : referenced_by
```

Notas:
- `MOVEMENT_LINE` soporta `from_container_id` y `to_container_id` (uno puede ser NULL para IN/OUT externos).
- `SCALE_CAPTURE` es evidencia: guardar `raw_payload_json`.

---

## B) ERD — Cultivo (extensión)

```mermaid
erDiagram
  ORGANIZATION ||--o{ PLANT_BATCH : has
  ORGANIZATION ||--o{ PLANT : has
  ORGANIZATION ||--o{ CULTIVATION_EVENT : logs
  ORGANIZATION ||--o{ HARVEST : records

  GENETIC ||--o{ PLANT_BATCH : used_in
  PLANT_BATCH ||--o{ PLANT : yields
  PLANT ||--o{ CULTIVATION_EVENT : has

  HARVEST ||--o{ LOT : produces
  GENETIC ||--o{ LOT : identifies
  ORGANIZATION ||--o{ LOT : owns
  LOT ||--o{ CONTAINER : fills
```

Idea: el “lote final” conecta cultivo → inventario.

---

## C) ERD — Costeos + activos (extensión)

```mermaid
erDiagram
  ORGANIZATION ||--o{ EQUIPMENT_ASSET : owns
  ORGANIZATION ||--o{ COST_ENTRY : records
  ORGANIZATION ||--o{ COST_ALLOCATION : allocates

  EQUIPMENT_ASSET ||--o{ COST_ENTRY : may_generate
  LOT ||--o{ COST_ALLOCATION : receives
  GENETIC ||--o{ COST_ALLOCATION : receives
  PLANT_BATCH ||--o{ COST_ALLOCATION : receives
  COST_ENTRY ||--o{ COST_ALLOCATION : splits
```

---

## Campos mínimos sugeridos (para implementar)

### ORGANIZATION
- `id`, `name`, `created_at`

### USER
- `id`, `organization_id`, `email`, `name`, `role`, `created_at`

### GENETIC
- `id`, `organization_id`, `name`, `active`

### CONTAINER_TYPE / CONTAINER
- `container_type(id, name)`
- `container(id, organization_id, code, type_id, genetic_id?, lot_id?, tare_mg?, status)`

### MOVEMENT / MOVEMENT_LINE
- `movement(id, organization_id, type, effective_at, created_by, notes?)`
- `movement_line(id, movement_id, genetic_id, lot_id?, from_container_id?, to_container_id?, net_mg, waste_mg?)`

### SCALE_DEVICE / SCALE_CAPTURE
- `scale_device(id, organization_id, name, connection_type, metadata_json)`
- `scale_capture(id, organization_id, device_id, captured_by, captured_at, net_mg, stable_ms, raw_payload_json)`

### AUDIT_LOG
- `audit_log(id, organization_id, actor_id, action, entity, entity_id, at, metadata_json)`

---

## Decisiones que faltan (para cerrar modelo)
1) ¿El inventario se maneja por **genética** o por **lote** desde el día 1? (recomendación: empezar por genética y añadir lote cuando el flujo de cosecha esté claro).
2) ¿Cómo representar OUT a socio? (p.ej. `movement.related_member_id` o `movement_line.to_member_id`).
3) ¿Precisión: guardar en mg (INT) y mostrar 0,01g o 0,001g? (definir único).
