
Last updated: 2026-06-15

## General Status

EasyCash is under active development. Backend phases 0–4.6 and dashboard API (5.1) are complete.
Frontend phases 5.2–5.10, 6.1–6.4 completas. Fase 7.1 completa (backend + frontend).
Overall progress: ~59% (37 of 63 planned phases complete).

## Roadmap

### Bloque 0 — Fundamentos

- [x] Fase 0 — Fundamentos técnicos y autenticación

### Bloque 1 — Entidades base

- [x] Fase 1.1 — Organizations, permissions y roles
- [x] Fase 1.2 — Users management
- [x] Fase 1.3 — Financial units y bank accounts
- [x] Fase 1.4 — Categories, customers y suppliers

### Bloque 2 — Contratos y obligaciones

- [x] Fase 2.1 — Income Contracts CRUD
- [x] Fase 2.2 — Expense Obligations CRUD
- [x] Fase 2.3 — Frequency Engine Base
- [x] Fase 2.4 — Generación de movimientos desde income contracts
- [x] Fase 2.5 — Generación de movimientos desde expense obligations
- [x] Fase 2.6 — Regeneración controlada de movimientos futuros

### Bloque 3 — Movimientos proyectados

- [x] Fase 3.1 — Projected Movements: listado y filtros
- [x] Fase 3.2 — Projected Movements: detalle y edición manual
- [x] Fase 3.3 — Projected Movements: cancelación / soft delete
- [x] Fase 3.4 — Projected Movements: estados y transiciones
- [x] Fase 3.5 — Projected Movements: overdue calculado al vuelo

### Bloque 4 — Ejecución

- [x] Fase 4.1 — Ejecución total de movimientos
- [x] Fase 4.2 — Ejecución parcial de movimientos
- [x] Fase 4.3 — Movimiento residual pendiente
- [x] Fase 4.4 — Actualización de saldo calculado
- [x] Fase 4.5 — Optimistic locking
- [x] Fase 4.6 — Historial de ejecuciones

### Bloque 5 — Dashboard y frontend

- [x] Fase 5.1 — Dashboard financiero API
- [x] Fase 5.2 — Frontend MVP inicial
- [x] Fase 5.3 — Movimientos proyectados visuales
- [x] Fase 5.4 — Frontend: acciones sobre movimientos
- [x] Fase 5.5 — Frontend: contratos de ingreso
- [x] Fase 5.6 — Frontend: clientes y proveedores
- [x] Fase 5.7 — Frontend: proveedores y obligaciones de gasto
- [x] Fase 5.8 — Frontend: unidades financieras y cuentas bancarias
- [x] Fase 5.9 — Frontend: calendario de flujo de caja
- [x] Fase 5.10 — Dashboard: vista ejecutiva de liquidez

### Bloque 6 — Cobranza y pagos operativos

- [x] Fase 6.1 — Cobranza y pagos (vista operativa UI)
- [x] Fase 6.2 — Dashboard cuentas por cobrar / cuentas por pagar (aging + top entidades)
- [x] Fase 6.3 — Acciones rápidas de contacto: WhatsApp y llamar (solo lectura de contacto)
- [x] Fase 6.4 — Alertas en tiempo real (liquidez, vencidos, saldos, próximos vencimientos)

### Bloque 7 — Reprogramaciones

- [x] Fase 7.1 — Historial de reprogramaciones
- [ ] Fase 7.2 — Sugerencia automática de nueva fecha
- [ ] Fase 7.3 — Reprogramación en ejecución parcial

### Bloque 8 — Movimientos manuales y predefinidos

- [ ] Fase 8.1 — Registro de movimientos ejecutados manuales
- [ ] Fase 8.2 — Conceptos predefinidos

### Bloque 9 — Préstamos

- [ ] Fase 9.1 — Préstamos modo simple
- [ ] Fase 9.2 — Préstamos modo avanzado (tabla de amortización)
- [ ] Fase 9.3 — Generación automática de pagos desde préstamos

### Bloque 10 — Tipo de cambio y multi-moneda avanzada

- [ ] Fase 10.1 — Tabla de tipos de cambio CRC/USD
- [ ] Fase 10.2 — Actualización automática desde API externa
- [ ] Fase 10.3 — Equivalencias en dashboard con tipo de cambio

### Bloque 11 — Alertas

- [ ] Fase 11.1 — Motor de alertas: riesgo de liquidez
- [ ] Fase 11.2 — Alertas: cobros y pagos vencidos
- [ ] Fase 11.3 — Alertas: diferencia saldo real vs calculado
- [ ] Fase 11.4 — Sugerencias del asistente de tesorería

### Bloque 12 — Obligaciones fiscales y laborales

- [ ] Fase 12.1 — Tax/labor obligations module
- [ ] Fase 12.2 — Integración con datos reales de EasyTax

### Bloque 13 — Escenarios

- [ ] Fase 13.1 — Creación de escenarios
- [ ] Fase 13.2 — Movimientos ficticios por escenario
- [ ] Fase 13.3 — Vista de impacto en flujo

### Bloque 14 — Grupos consolidados

- [ ] Fase 14.1 — Consolidated groups y group_units
- [ ] Fase 14.2 — Vista de flujo consolidado multi-empresa

### Bloque 15 — Auditoría y seguridad

- [ ] Fase 15.1 — Audit log completo
- [ ] Fase 15.2 — Exportación de reportes

### Bloque 18 — Integración EasyTax

- [ ] Fase 18.1 — API EasyTax: recepción de datos fiscales
- [ ] Fase 18.2 — Flujo de decisión: mantener / sustituir / conservar ambos

---

## Completed Phases

### Phase 0 - Base, Auth, Docs and Health

Status: Complete

Validated endpoints:

* Health
* OpenAPI JSON
* Swagger UI
* Login
* Refresh
* Logout
* Me
* Profile
* Change password

Tests passed: 9/9

---

### Phase 1.1 - Organizations, Roles and Permissions

Status: Complete

Main endpoints:

* GET /organizations/current
* GET /permissions
* GET /roles
* GET /roles/{id}

Tests passed: 4/4

---

### Phase 1.2 - User Management

Status: Complete

Main features:

* Create user
* Update user
* Change user status
* Delete user
* Validate duplicate email
* Validate permissions
* Self-protection rules
* Audit log

Tests passed: 13/13

---

### Phase 1.3 - Financial Units and Bank Accounts

Status: Complete

Main features:

* Financial units
* Bank accounts
* Balance adjustment
* Tenant isolation
* FK restrictions
* Filters by financial unit

Tests passed: 19/19

---

### Phase 1.4 - Categories, Customers and Suppliers

Status: Complete

Main features:

* Categories
* Customers
* Suppliers
* Category type validation
* Color validation
* Notes
* Responsible user
* Soft delete

Tests passed: 23/23

---

### Phase 2.1 - Income Contracts

Status: Complete

Main features:

* Income contracts
* Frequency calculation
* Projected income movement generation
* Responsible user
* Customer association
* Category validation
* Bank account validation
* Movements summary
* Regeneration control

Tests passed: 24/24

---

### Phase 2.2 - Expense Obligations

Status: Complete

Approved: 2026-06-05

Main features:

* Expense obligations
* Supplier association (obligatory)
* Expense category validation
* Payment bank account validation
* Frequency calculation
* Projected expense movement generation
* Movements summary
* Regeneration control
* Soft delete
* Status update

Tests passed: 24/24

---

### Phase 2.3–2.6 - Frequency Engine and Movement Generation

Status: Complete

Main features:

* Centralized FrequencyEngine
* Generation from income contracts
* Generation from expense obligations
* Controlled regeneration of future pending movements only

---

### Phase 3.1–3.5 - Projected Movements Engine

Status: Complete

Main features:

* Projected movements list with filters (date range, type, status, currency, financial unit, bank account)
* Manual editing of projected movements
* Soft delete / cancellation
* Status transitions (pending → executed / partial / cancelled)
* effective_status calculated on-the-fly via SQL CASE: pending + projected_date < CURDATE() → overdue

---

### Phase 4.1–4.6 - Execution Engine

Status: Complete

Main features:

* Full execution of movements
* Partial execution with residual pending movement
* Calculated balance update on bank accounts
* Optimistic locking (version field)
* Execution history (movement_executions table)

---

### Phase 5.1 - Dashboard Financial API

Status: Complete

Main features:

* GET /dashboard with date_from / date_to (required), optional currency / financial_unit_id / bank_account_id
* Opening balances from active bank accounts grouped by currency
* Movement totals (income + expense) grouped by currency and effective_status
* net_flow and expected_closing_balance computed per currency
* Multi-currency: returns `currencies` map when no currency filter; flat structure when currency filter applied
* Empty currency map serialized as `{}` not `[]`
* Permission: dashboard.read
* Tenant isolation via JWT organization_id

---

### Phase 5.2 - Frontend MVP

Status: Complete

Stack: React 18 + Vite + TypeScript + Tailwind CSS 3 + React Router v6 + TanStack React Query v5 + Zustand + Axios

Main features:

* Login page with React Hook Form + Zod validation
* JWT access token in localStorage (Zustand persist)
* Refresh token in httpOnly cookie
* Axios interceptor with isRefreshing flag + refreshQueue to prevent 401 loops
* AppLayout: Sidebar + Topbar + main outlet
* Dashboard page: multi-currency blocks (CurrencyBlock) and single-currency flat view
* DashboardFilters: date range, currency selector, apply button
* StatCard component with variants (income / expense / positive / negative / accent)
* ProtectedRoute: redirects to /login when not authenticated
* AuthBootstrap: calls /auth/me on mount if token present

---

### Phase 5.3 - Movimientos Proyectados Visuales

Status: Complete

Main features:

* /movements page with full projected movements table
* MovementsFilters: date_from, date_to, movement_type, effective_status, currency, per_page selector
* MovementsTable: color-coded rows (green border = income, red border = expense), amount colors
* StatusBadge (5 colors) and TypeBadge (Cobro/Pago)
* MovementDetailDrawer: slide-in panel, instant preview from row data, full detail via useMovementById
* Pagination component with "Mostrando X–Y de Z registros"
* Sidebar: Movimientos link active state
* Empty state and skeleton loading (8 rows animate-pulse)

Tests passed: 14/14

---

### Phase 5.4 - Frontend: Acciones sobre Movimientos

Status: Complete

Main features:

* ExecuteMovementModal: full and partial execution, amber banner + child_projected_date field when executed_amount < amount_current, button text changes to "Ejecutar parcialmente"
* EditMovementModal: prefilled form with React Hook Form + Zod, editable fields (concept, projected_date, amount_current, description, invoice_number, notes, bank_account_id), filters compatible bank accounts by currency
* ConfirmCancelModal: confirmation dialog with error handling for 409 conflict
* Action buttons (Ejecutar / Editar / Cancelar) shown only when effective_status is pending or overdue
* All mutations send expected_version (optimistic locking)
* Cancel uses PATCH /projected-movements/{id}/cancel
* After any successful action: invalidates ['movements'] + ['dashboard'] queries, closes modal, closes drawer
* Modals render outside the aside element (z-60) so they overlay correctly
* Escape key closes modal first, then drawer

Tests passed: 10/10

---

### Phase 5.5 - Frontend: Contratos de Ingreso

Status: Complete

Main features:

* Income contracts list page with filters (status, date range, customer, frequency)
* ContractDetailDrawer: slide-in panel with contract details and projected movements summary
* Create / Edit income contract modal with React Hook Form + Zod validation
* Customer selector, category selector (income type), bank account selector filtered by currency
* Frequency selector with conditional fields (end date, day of month, etc.)
* Deactivate / reactivate contract actions
* Projected movements count and amount_type badge
* Sidebar: Contratos de Ingreso link active state

---

### Phase 5.6 - Frontend: Clientes y Proveedores

Status: Complete

Main features:

* Customers list page with search and status filters
* Suppliers list page with search and status filters
* Create / Edit customer and supplier modals with validation
* Customer / supplier detail drawer with contact info and notes
* Soft delete (deactivate) with confirmation
* Responsible user assignment
* Sidebar links active state for Clientes and Proveedores

---

### Phase 5.7 - Frontend: Proveedores y Obligaciones de Gasto

Status: Complete

Main features:

* Expense obligations list page with filters (status, supplier, frequency, category)
* ObligationDetailDrawer: slide-in panel with obligation details and projected movements summary
* Create / Edit expense obligation modal with React Hook Form + Zod validation
* Supplier selector, expense category selector, bank account selector
* Frequency selector with conditional fields
* Deactivate / reactivate obligation actions
* Projected movements count badge
* Sidebar: Obligaciones de Gasto link active state

---

### Phase 5.8 - Frontend: Unidades Financieras y Cuentas Bancarias

Status: Complete

Main features:

* Financial units list page with create / edit / deactivate actions
* Bank accounts list page scoped by financial unit
* Create / Edit bank account modal: name, currency, initial balance, financial unit
* Balance adjustment modal with reason field
* Calculated balance display vs initial balance
* Tenant isolation enforced via organization context
* Sidebar: Unidades Financieras and Cuentas Bancarias links active state

---

### Phase 5.9 - Frontend: Calendario de Flujo de Caja

Status: Complete

Main features:

* Monthly calendar view of projected cash flow movements
* Day cells color-coded by net flow (positive/negative/zero)
* Click on day to see movement list for that date in a side panel
* Month navigation (prev / next) with date range query updates
* Currency and financial unit filters applied to calendar data
* Summary totals (income / expense / net) for the displayed month
* Sidebar: Calendario link active state

---

### Phase 5.10 - Frontend: Dashboard Ejecutivo (Vista de Liquidez)

Status: Complete

Main features:

* Executive liquidity dashboard with KPI cards: opening balance, net flow, expected closing balance, overdue movements
* Bar chart: income vs expense by period (daily / weekly / monthly grouping)
* Line chart: balance projection over selected date range
* Overdue movements alert panel with count and total amount
* Currency and financial unit selector applied across all widgets
* Data sourced from GET /dashboard with extended date ranges
* Sidebar: Dashboard Ejecutivo link active state

---

### Phase 6.1 - Frontend: Cobranza y Pagos (Vista Operativa)

Status: Complete

Main features:

* Collections view: pending and overdue income movements grouped by customer
* Payments view: pending and overdue expense movements grouped by supplier
* Tabs to switch between Cobranza (collections) and Pagos (payments)
* Quick-action buttons per row: Execute, Edit, Cancel (same modals as Phase 5.4)
* Overdue badge with days-overdue count
* Summary totals: total pending income, total pending expense, total overdue
* Filters: date range, financial unit, currency, status (pending / overdue)
* Sidebar: Cobranza y Pagos link active state

---

### Fase 6.2 - Frontend: Cuentas por Cobrar / Cuentas por Pagar (Dashboard Analítico)

Estado: Completa

Características principales:

* Vista analítica de cartera pendiente — sin acciones operativas (solo lectura)
* KPIs: total por cobrar, total por pagar, total vencido, promedio de días de atraso
* Tabs: Por Cobrar (clientes) / Por Pagar (proveedores)
* AgingBar: barra visual de distribución por antigüedad proporcional al monto
* AgingTable: tabla de 5 buckets (por vencer / 0–7 / 8–30 / 31–60 / +60 días) con monto, cantidad y porcentaje
* TopEntitiesTable: top 10 clientes o proveedores por monto pendiente, con columna de vencido
* Fila "Otros (N)" agrupando entidades fuera del top 10
* Selector CRC/USD obligatorio — sin mezcla de monedas
* Alerta cuando totalCount >= 200 movimientos
* Días vencidos calculados normalizando hoy a medianoche local
* Sidebar: "Cuentas por Cobrar / Pagar" con ícono BarChart2

Archivos creados:

* `frontend/src/hooks/useArAp.ts`
* `frontend/src/features/ar-ap/ArApPage.tsx`
* `frontend/src/features/ar-ap/ArApFilters.tsx`
* `frontend/src/features/ar-ap/ArApKPIs.tsx`
* `frontend/src/features/ar-ap/AgingBar.tsx`
* `frontend/src/features/ar-ap/AgingTable.tsx`
* `frontend/src/features/ar-ap/TopEntitiesTable.tsx`

Archivos modificados:

* `frontend/src/routes/index.tsx` — ruta `/ar-ap`
* `frontend/src/components/layout/Sidebar.tsx` — enlace "Cuentas por Cobrar / Pagar"

---

### Fase 6.3 - Frontend: Acciones Rápidas de Contacto (WhatsApp y Llamar)

Estado: Completa

Características principales:

* Botón Llamar (ícono Phone) en cada fila de movimiento: enlace `tel:` que abre marcador en móvil
* Botón Copiar número (ícono Copy): copia el teléfono al portapapeles en desktop; ícono cambia a ✓ por 2 segundos
* Botón WhatsApp (ícono MessageCircle): solo en cobros (income); abre `wa.me` con mensaje prearmado
* Mensaje prearmado incluye: nombre del cliente, nombre del usuario autenticado, moneda, monto, concepto y fecha proyectada
* WhatsApp usa el campo `whatsapp` del cliente; si no existe, usa `phone` como fallback
* WhatsApp no aparece en pagos (proveedores no tienen campo whatsapp en backend)
* Botón Reprogramar (ícono Clock) visible pero deshabilitado, tooltip: "Reprogramación disponible en Fase 8.1"
* Número de teléfono visible únicamente en tooltip — no ocupa espacio en la fila
* Formato de teléfono: hint en formularios de cliente y proveedor indica código de país obligatorio (ej: 506 88001234)
* Sin cambios de backend — 100% frontend

Archivos creados:

* `frontend/src/utils/contactLinks.ts` — funciones puras `buildWhatsAppUrl` y `buildPhoneUrl`

Archivos modificados:

* `frontend/src/features/collections/CollectionMovementRow.tsx` — botones Phone, Copy, WhatsApp, Clock deshabilitado
* `frontend/src/features/collections/CollectionGroupRow.tsx` — interfaz extendida con `contactPhone` y `contactWhatsApp`
* `frontend/src/features/collections/PendingIncomePanel.tsx` — propaga phone y whatsapp del cliente al grupo
* `frontend/src/features/collections/PendingExpensePanel.tsx` — propaga phone del proveedor; whatsapp siempre null
* `frontend/src/features/customers/CustomerFormModal.tsx` — hint de formato internacional en phone y whatsapp
* `frontend/src/features/suppliers/SupplierFormModal.tsx` — hint de formato internacional en phone

Deuda técnica documentada:

* Reprogramación queda para Fase 8.1: endpoint dedicado, escritura en tabla `reschedules`, reason, auditoría e historial visible

---

### Fase 6.4 - Frontend: Alertas en Tiempo Real

Estado: Completa

Características principales:

* Página `/alerts` con alertas calculadas al vuelo desde endpoints existentes — sin backend nuevo
* Encabezado explica que las alertas son en tiempo real, no históricas ni persistentes
* Alertas rojas (críticas): cobros vencidos, pagos vencidos, riesgo de liquidez (saldo proyectado negativo)
* Alertas amarillas (advertencias): liquidez baja (<20% del saldo inicial), cobros y pagos próximos ≤7 días, diferencia saldo real vs calculado en cuentas bancarias
* Card verde "Todo en orden" cuando no hay ninguna alerta activa
* Cards ordenadas: rojas primero, luego amarillas, luego verde
* Barra de resumen: N críticas · N advertencias · Sin alertas activas
* Filtros: selector CRC/USD obligatorio + unidad financiera
* Umbral de próximos vencimientos: `UPCOMING_ALERT_DAYS = 7`
* Liquidez vía `getLiquiditySemaphore()` reutilizado desde `types/dashboard.ts`
* Saldos bancarios vía `getBalanceSemaphore()` reutilizado desde `features/bank-accounts/balanceSemaphore.ts`
* Links de acción: vencidos/próximos → `/collections`; liquidez → `/cash-flow`; saldos → `/bank-accounts`
* Sidebar badge omitido: causaría 4 consultas paralelas extra en cada navegación (decisión de fase)
* Sidebar: enlace "Alertas" con ícono Bell añadido
* Sin cambios de backend — 100% frontend

Archivos creados:

* `frontend/src/types/alerts.ts` — tipos `AlertSeverity`, `AlertType`, `AlertItem`
* `frontend/src/hooks/useAlerts.ts` — hook central que agrega 4 fuentes en paralelo
* `frontend/src/features/alerts/AlertCard.tsx` — card individual con estilos por severidad
* `frontend/src/features/alerts/AlertsSummaryBar.tsx` — barra con pills de conteo
* `frontend/src/features/alerts/AlertsFilters.tsx` — filtros CRC/USD + unidad financiera
* `frontend/src/features/alerts/AlertsPage.tsx` — página principal `/alerts`

Archivos modificados:

* `frontend/src/routes/index.tsx` — ruta `/alerts`
* `frontend/src/components/layout/Sidebar.tsx` — enlace "Alertas" con ícono Bell

---

### Fase 7.1 - Backend + Frontend: Reprogramaciones con Historial

Estado: Completa

Características principales:

* Reprogramación de movimientos proyectados `pending` u `overdue` — in-place sobre `projected_date`
* `original_date` nunca se modifica — queda como referencia histórica
* Transacción atómica: UPDATE `projected_movements.projected_date` + INSERT `reschedules` + INSERT `audit_log`
* Optimistic locking: `WHERE version = expected_version` — devuelve 409 si versión no coincide
* 6 motivos estructurados: `atraso_cliente`, `acuerdo_pago`, `falta_factura`, `atraso_pago`, `error_fecha`, `otro`
* Campo `notes` libre opcional por reprogramación
* Historial completo: múltiples reprogramaciones sobre el mismo movimiento, ordenadas `created_at DESC`
* `changed_by_name` resuelto vía JOIN a `users` — nunca desnormalizado
* `audit_log.action = 'reschedule'` con `old_value` y `new_value` por cada operación
* Permiso `projected_movements.reschedule` — nuevo; asignado a Admin y Operator mediante migración `20260615000001`
* `GET /reschedules` reutiliza permiso `projected_movements.read` (historial como parte del detalle)
* Validación: `new_date >= hoy` y `new_date ≠ projected_date` actual
* Frontend: botón Clock habilitado en `CollectionMovementRow` para movimientos accionables
* Frontend: `RescheduleModal` con referencia de fecha actual, date picker (`min=hoy`), select de motivo, notas opcionales, manejo de 409
* Frontend: `RescheduleHistory` en `MovementDetailDrawer` con flecha `fecha_anterior → nueva_fecha`, motivo, usuario, fecha
* Frontend: botón "Reprogramar" añadido al footer del drawer de Movimientos
* Frontend: `z-70` en `RescheduleModal` para renderizar correctamente sobre el drawer (`z-50` con `transition-transform`)
* Frontend: 5 invalidaciones de query tras éxito, incluido `pending-collections`
* Corrección: `ListProjectedMovementsAction::formatItem()` ahora incluye `version` y `updated_by` en la respuesta del listado

Archivos creados (backend):

* `src/Domain/Entities/Reschedule.php`
* `src/Domain/Repositories/RescheduleRepositoryInterface.php`
* `src/Infrastructure/Repositories/PdoRescheduleRepository.php`
* `src/Application/Actions/Reschedules/CreateRescheduleAction.php`
* `src/Application/Actions/Reschedules/ListReschedulesAction.php`
* `src/Infrastructure/Database/Migrations/20260615000001_AddReschedulePermission.php`

Archivos modificados (backend):

* `src/Domain/Repositories/ProjectedMovementRepositoryInterface.php` — añadido `rescheduleWithLock()`
* `src/Infrastructure/Repositories/PdoProjectedMovementRepository.php` — implementado `rescheduleWithLock()`
* `src/Application/Actions/ProjectedMovements/ListProjectedMovementsAction.php` — añadido `version` y `updated_by` al formatItem
* `src/Infrastructure/Database/Seeds/PermissionsSeed.php` — añadido `reschedule` al catálogo de `projected_movements`
* `config/container.php` — registradas nuevas clases
* `config/routes.php` — 2 rutas nuevas
* `openapi/openapi.yaml` — 2 operaciones + schema `RescheduleItem`

Archivos creados (frontend):

* `src/types/reschedules.ts`
* `src/api/endpoints/reschedules.ts`
* `src/hooks/useRescheduleActions.ts`
* `src/hooks/useReschedules.ts`
* `src/features/reschedules/RescheduleModal.tsx`
* `src/features/reschedules/RescheduleHistory.tsx`

Archivos modificados (frontend):

* `src/features/collections/CollectionMovementRow.tsx` — Clock habilitado, prop `onReschedule`
* `src/features/collections/CollectionGroupRow.tsx` — prop `onReschedule` propagado
* `src/features/collections/PendingIncomePanel.tsx` — estado + modal
* `src/features/collections/PendingExpensePanel.tsx` — estado + modal
* `src/features/movements/MovementDetailDrawer.tsx` — botón Reprogramar + historial + modal
* `tailwind.config.ts` — registrados `z-60` y `z-70`

---

## Documentation Checklist

Before approving a phase:

* Code completed
* Tests passed
* Validation cases passed
* Permission cases passed
* Tenant isolation verified
* OpenAPI updated
* CLAUDE.md updated if architecture or global rules changed
* PROJECT_STATUS.md updated
* Graphify regenerated if structure changed significantly
* Sensitive files excluded
