# Requirements Specification: GC Dashboard (Sales & Branch Management System)

**Version:** 2.0  
**Last Updated:** 2026-05-03  
**Framework:** CodeIgniter 4 · PHP 8.4 · MySQL · Tailwind CSS (Soft UI)

---

## 1. Project Overview

The **GC Dashboard** is a modular, multi-tenant Sales and Branch Management System engineered to consolidate operational data (sales, collections, inventory) across a hierarchical corporate structure of Holdings, Groups, and Branches. It provides real-time KPI visibility, goal-tracking, variance analysis, and granular Role-Based Access Control (RBAC).

### Technology Stack

| Layer | Technology |
|---|---|
| Backend Framework | CodeIgniter 4 (PHP 8.4.15) |
| Frontend / UI | Soft UI Dashboard — Tailwind CSS |
| Scripting | Vanilla JS / Alpine.js |
| Database | MySQL (relational, normalized) |
| Runtime Environment | WAMP — Windows, Apache, MySQL |
| PHP Binary | `C:\wamp64\bin\php\php8.4.15\php.exe` |
| IDE | Cursor |

---

## 2. Core Architectural Principles

| Principle | Description |
|---|---|
| **Modular Design** | Each feature is an independent, permission-gated module accessible via the sidebar. |
| **Role-Based Access Control (RBAC)** | Granular permissions toggle visibility of every sidebar section and controller action. |
| **Context-Aware Filtering** | A global `active_branch_id` session key scopes all data retrieval and insertion to the currently active branch. A higher-order `view_context` key (holding / category / zone / branch) drives dashboard-level KPI aggregation. |
| **Reusable View Partials** | Shared layouts under `app/Views/layouts/` and `app/Views/partials/` (sidenav, navbar, footer). |
| **Separation of Concerns** | Controllers are intentionally thin; complex queries live in Model helper methods or dedicated service methods. |
| **Data Integrity** | Input validation, `esc()` output encoding, prepared statements exclusively via CI4 Query Builder. |
| **Audit Traceability** | `created_at` / `updated_at` timestamps on all entity tables; explicit activity logging via `logActivity()`. |

---

## 3. System Architecture

### 3.1 Backend (MVC)

- **Controllers** (`App\Controllers`): RESTful-friendly, thin controllers that delegate query logic to Models.
- **Models** (`App\Models`): CI4 `Model` subclasses with strict `$allowedFields`, `$validationRules`, `$returnType = 'array'`, and lifecycle hooks.
- **Context Injection Hooks**:
  - `beforeInsert['injectBranchId']` — automatically stamps `sucursal_id` from `active_branch_id` session on every insert.
  - `beforeFind['filterByBranch']` — automatically scopes `findAll()` / `find()` queries to the active branch.
- **Context Controller** (`Context.php`): Dedicated AJAX-only controller with four endpoints:
  - `POST /admin/context/set-branch` — sets `active_branch_id` (clears `view_context`).
  - `POST /admin/context/set-holding` — sets `view_context = 'holding:<id>'` (preserves branch).
  - `POST /admin/context/set-category` — sets `view_context = 'category:<id>'`.
  - `POST /admin/context/set-zone` — sets `view_context = 'zone:<id>'`.
- **`applyContextFilter()`**: Private method pattern shared across `VentasModel` and `CobranzasModel` that translates the decoded `view_context` into the correct `WHERE` or `JOIN` clause.

### 3.2 Frontend

- **Tailwind CSS** utility-first classes scoped within CI4 Views (`.php` files).
- **Sidebar (`sidenav.php`)**: Collapsible mini-sidebar with icon-only collapsed state and label-reveal on hover, managed via CSS transitions + JS `is-expanded` class toggle.
- **Active state helpers**: `navLinkClass()`, `navIconClass()`, `navIconSvgClass()` — PHP functions that compare the current URL via `url_is()` and return the appropriate Tailwind/gold-gradient class.
- **Theme**: Pantone 116 Gold (`#FFCD00`) + Red (`#E4002B`) on a dark background (`gc-theme.css`).
- **Dynamic Visibility**: `hasModuleAccess($key)` helper gates every sidebar `<li>` block and controller action.

### 3.3 Database Cluster Map

```
┌─────────────────────────────────────────────────────────┐
│  ACCESS CONTROL CLUSTER                                 │
│  users · roles · permissions · user_roles               │
│  role_permissions · user_branch_access                  │
├─────────────────────────────────────────────────────────┤
│  ORGANIZATIONAL CLUSTER                                 │
│  holdings · sucursales · sucursales_categorias          │
│  sucursal_tipos · sucursal_zonas · zonas                │
│  sucursal_marcas · sucursal_features                    │
│  sucursal_productos                                     │
├─────────────────────────────────────────────────────────┤
│  OPERATIONAL CLUSTER                                    │
│  ventas · venta_items · cobranzas                       │
│  monthly_goals                                          │
├─────────────────────────────────────────────────────────┤
│  CATALOG CLUSTER                                        │
│  marcas · marcas_categorias · marca_tipos               │
│  products · suppliers · inventory_logs                  │
└─────────────────────────────────────────────────────────┘
```

---

## 4. Branch Hierarchy Architecture (Árbol de Sucursales)

The organizational tree follows a strict four-level hierarchy:

```
Holding
  └── Group (sucursales_categorias — e.g. Retail, Distribución, Importación)
        └── Branch Type (sucursal_tipos — many-to-many pivot)
              └── Sucursal (Branch)
                    ├── Zones (sucursal_zonas)
                    ├── Brands (sucursal_marcas)
                    ├── Features (sucursal_features)
                    └── Products (sucursal_productos)
```

### 4.1 Holdings (`holdings`)

The apex organizational entity. A holding groups multiple branches under a single corporate umbrella. Holdings are managed via the **Holdings** module (`admin/holdings`).

### 4.2 Groups / Branch Categories (`sucursales_categorias`)

Each branch belongs to exactly one **Group** (referred to as `categoria_id` in the `sucursales` table). Groups are polymorphic configuration containers — they dictate which data-entry fields are enabled for member branches via boolean flags:

| Flag | Description |
|---|---|
| `billing_by_brand` | Enables per-brand billing entry in sales forms |
| `gross_profit_by_brand` | Enables per-brand gross profit entry |
| `collections_by_brand` | Enables per-brand collections entry |
| `service_revenue` | Enables a service-revenue line on the daily sales header |

Current operational groups include: **Retail**, **Distribución**, and **Importación**.

### 4.3 Branch Types (`sucursal_tipos` pivot)

A many-to-many pivot between `sucursales` and a type catalog (`tipo_id`). A single branch may carry multiple operational type tags (e.g., a branch can be both Retail and a service center). Synced via `SucursalTipoModel::syncForSucursal()`.

### 4.4 Branches / Sucursales (`sucursales`)

The leaf-level operational unit. Key fields:

| Field | Description |
|---|---|
| `holding_id` | Parent holding (FK) |
| `categoria_id` | Parent group/category (FK) |
| `nombre` | Branch display name |
| `direccion` | Physical address |
| `estado` | Lifecycle state (`active` / `inactive`) |

---

## 5. Authentication & Authorization

### 5.1 User Sessions

- Entry via `Login` page; credentials validated against `bcrypt`-hashed passwords (`password_hash()`).
- Secure, server-side CI4 session management with throttling.
- `requires_password_reset` flag forces a one-time password change on first login.
- `view_cost` flag per user governs whether cost/margin data is visible in views.

### 5.2 RBAC Model

```
users ──< user_roles >── roles ──< role_permissions >── permissions
users ──< user_branch_access >── sucursales
```

- Permissions are named string keys (e.g., `ventas`, `cobranzas`, `reportes`, `inventory`).
- `hasModuleAccess($key)` checks the logged-in user's effective permission set.
- `isSuperAdmin()` — a separate flag granting access to the **Users** and **Roles** management sections.
- Administrators can create roles, define permission sets, and assign them to users.
- Branch access is stored in `user_branch_access` — a user may be authorized for one or many branches.

---

## 6. Modules & Functional Requirements

The sidebar is organized into three navigation sections: **Panel Principal**, **Operaciones**, and **Corporativo / Usuarios**.

---

### Module 1: Panel Principal (Dashboard)
**Permission key:** `dashboard`  
**Route:** `/`

The main KPI dashboard. Provides a bird's-eye view of financial performance across the active context. Supports four context levels:

| Context Type | Session Key | Scope |
|---|---|---|
| `branch` | `active_branch_id` | Single sucursal |
| `holding` | `view_context = 'holding:<id>'` | All branches under a holding |
| `category` | `view_context = 'category:<id>'` | All branches of a group type |
| `zone` | `view_context = 'zone:<id>'` | All branches in a geographic zone |
| `all` | *(no context set)* | Super-admin global view |

**KPI Widgets:**
- Total Revenue (`total_revenue` sum)
- Total Profit (`total_profit` sum)
- Service Revenue (`service_revenue` sum)
- Total Inventory Stock
- Accounts Receivable (CxC) totals
- Sales by product category type (Cauchos type_id=2, Lubricantes type_id=1)

**Charts:**
- Bar chart — Revenue by Branch (ranked)
- Pie charts — Sales breakdown by brand category or branch (context-aware)
- CxC aging ladder (`cxc_no_vencidas`, `cxc_0_30`, `cxc_30_60`, `cxc_60_90`, `cxc_plus_90`)

**Dynamic Table:** Branch-level ranking table, grouped by category for multi-branch views.

---

### Module 2: Metas y Proyección (Goals & Projections)
**Permission key:** `goals`  
**Route:** `admin/goals`

A goal-setting and financial projection engine tied to the active view context.

**Key Entities — `monthly_goals` table:**

| Field | Description |
|---|---|
| `month` / `year` | Target period |
| `context_type` | Scope type: `branch`, `category`, `holding` |
| `context_id` | FK to the scoped entity |
| `target_amount` | Fixed monetary target for the period |
| `working_days_json` | JSON array of working day counts per branch |
| `total_working_days` | Aggregate working days for the period |
| `calculated_projection` | Server-computed daily rate × elapsed working days |

**Business Logic:**
- **Daily Projection** = `target_amount ÷ total_working_days`
- **Period Projection** = `Daily Projection × elapsed_working_days_to_date`
- **Variance** = `actual_revenue − calculated_projection`
- Goals can be defined at Branch, Group (category), or Holding level, enabling hierarchical goal aggregation.
- The module adapts its UI inputs and aggregation logic based on the current active context scope.

---

### Module 3: Reportes Generales (Reports)
**Permission key:** `reportes`  
**Route:** `admin/reportes`

A comprehensive analytical reporting engine (`ReportesModel.php`, `Reportes.php`). Reports are generated by comparing **actual daily-loaded data** against **pre-configured goals** to surface variances and yield percentages.

**Report Types:**
- **Sales & Services Report** — Conditional aggregation of specific product/service categories (tires, oil, alignments) with dynamic hierarchical grouping (by Holding, Group, or Branch).
- **Collections Report** — CxC aging analysis across branches and periods.
- **Variance / Goal-Yield Report** — Actual vs. Target with percentage attainment per branch, group, and holding.

**Filtering Dimensions:**
- Date range (with presets: current month, last month, custom)
- Hierarchy level: Holding → Group → Branch
- Branch type (Retail / Distribución / Importación)

**Key `ReportesModel` Methods:**
- Context-aware aggregate queries with `JOIN` logic matching `VentasModel::applyContextFilter()`.
- Conditional `SUM(IF(...))` aggregation for category-specific breakdowns.
- Result sets returned as arrays for rendering in Glassmorphism-styled Tailwind views.

---

### Module 4: Registro de Ingr/Egr — Ventas (Sales Entry)
**Permission key:** `ventas`  
**Route:** `admin/ventas`

The primary daily operational data-entry module for Sales (ingresos/egresos). Each record represents one day of commercial activity for the active branch.

**Header Record (`ventas` table):**

| Field | Description |
|---|---|
| `sucursal_id` | Auto-injected from session (`injectBranchId` hook) |
| `fecha` | Transaction date |
| `total_revenue` | Gross revenue for the day |
| `total_profit` | Net profit for the day |
| `service_revenue` | Service-line revenue (conditional per group config) |

**Line Items (`venta_items` table):**

Each daily record supports multiple line items decomposing revenue by brand and product category:

| Field | Description |
|---|---|
| `type_id` | FK to `marcas_categorias` (e.g., Cauchos, Lubricantes) |
| `brand_id` | FK to `marcas` |
| `product_id` | FK to `products` (optional, nullable) |
| `unit_of_measurement` | ENUM: `Monto Monetario`, `Unidades`, `Litros`, `Kilogramos` |
| `value` | Quantity or monetary amount |
| `billing` | Billing amount (conditional per group config) |
| `collections` | Collections amount (conditional per group config) |
| `gross_profit` | Gross profit for this line (conditional per group config) |

**Data-Entry Configuration (Feature Flags):**  
Which fields appear in the sales entry form is controlled by the **group-level flags** on `sucursales_categorias`:
- `billing_by_brand` → shows the `billing` column per line item
- `gross_profit_by_brand` → shows the `gross_profit` column per line item
- `collections_by_brand` → shows the `collections` column per line item
- `service_revenue` → shows a service revenue field on the daily header

These configurations can be further scoped at the **Branch**, **Group**, or **User** level, ensuring that each operator sees only the data-entry fields relevant to their operational context.

**Validation:** `required|valid_date`, `required|numeric` on header; per-field rules on items including `in_list` ENUM guard for `unit_of_measurement`.

**Massive Load:** Bulk CSV import capability (`SucursalesCategorias` controller) for batch data entry scenarios.

---

### Module 5: Cuentas por Cobrar — Cobranzas (Collections)
**Permission key:** `cobranzas`  
**Route:** `admin/cobranzas`

Daily data-entry module for Accounts Receivable (CxC) collections. Tracks the aging structure of outstanding customer balances per branch.

**`cobranzas` table fields:**

| Field | Description |
|---|---|
| `sucursal_id` | Auto-injected from session |
| `fecha` | Entry date |
| `empresa` | Client company name |
| `monto_cobranza_general` | Total collections amount for the day |
| `cxc_no_vencidas` | Not-yet-due receivables |
| `cxc_0_30` | 0–30 days overdue |
| `cxc_30_60` | 31–60 days overdue |
| `cxc_60_90` | 61–90 days overdue |
| `cxc_plus_90` | 90+ days overdue |

Collections data feeds directly into Dashboard CxC widgets and the Reports module aging analysis.

---

### Module 6: Sucursales (Branch Management)
**Permission key:** `sucursales`  
**Route:** `admin/sucursales`

Full CRUD management of branches and their associated configurations.

**Branch configuration includes:**
- Basic data: `nombre`, `direccion`, `estado`, `holding_id`, `categoria_id`
- **Brand assignments** (`sucursal_marcas`): Defines exactly which `marcas` a branch is authorized to operate with. Synced atomically via `SucursalMarcaModel::syncForSucursal()`.
- **Feature flags** (`sucursal_features`): Key-value feature toggles per branch. Synced via `SucursalFeatureModel::syncForSucursal()`.
- **Branch types** (`sucursal_tipos`): Many-to-many type tagging. Synced via `SucursalTipoModel::syncForSucursal()`.
- **Zone assignments** (`sucursal_zonas`): Geographic zone membership for regional context filtering.
- **Product catalog** (`sucursal_productos`): Branch-specific product availability.

---

### Module 7: Holdings (Corporate Entity Management)
**Permission key:** `holdings`  
**Route:** `admin/holdings`

CRUD management of top-level holding entities. Holdings are the root of the branch hierarchy and drive the `holding`-level view context for multi-branch KPI aggregation on the dashboard.

---

### Module 8: Grupos (Group / Branch Category Management)
**Permission key:** `categorias`  
**Route:** `admin/categorias`

Management of **Groups** (`sucursales_categorias`). Each group defines:
- A display name and description.
- Boolean feature flags that configure data-entry forms for all member branches (see §Module 4).

This is the primary configuration engine that governs **what specific sales/collection data fields** can be entered by operators in a given group of branches.

---

### Module 9: Productos/Servicios — Marcas (Brand & Product Management)
**Permission key:** `marcas`  
**Route:** `admin/marcas`

Catalog management for the Brands and Products domain:

**Brands (`marcas`):**
- Simple name-based catalog. Each brand entry is the authoritative identifier used in `venta_items.brand_id` and `sucursal_marcas.marca_id`.

**Product Categories (`marcas_categorias`):**
- Defines the top-level product/service type (e.g., Cauchos, Lubricantes, Servicios).
- Carries a `unit_of_measure` ENUM (`Unidades`, `Litros`, `Kilogramos`) that propagates as a default to line items.

**Products (`products`):**
- Full catalog with: `sku`, `name`, `brand_id`, `type_id`, `stock`, `unit_cost`, `sale_price`, `measurement`, `rubric`, `reference`, `literage`, `supplier_id`, `additional_category`.
- SKU uniqueness enforced at model validation level.

**Branch–Brand Authorization:**
- The `sucursal_marcas` pivot table explicitly authorizes which brands each branch may sell.
- When a user enters a daily sales line item, only brands authorized for the active branch are presented.
- This ensures operational data integrity and prevents cross-brand contamination between branches.

---

### Module 10: Inventario (Inventory Management)
**Permission key:** `inventory`  
**Route:** `admin/inventory`

Product stock tracking with an auditable adjustment ledger.

**Features:**
- Product listing with current stock levels (sourced from `products.stock`).
- Stock adjustments with mandatory reason logging.
- Bulk CSV import for mass inventory data entry.

**Adjustment Ledger (`inventory_logs`):**
- Records every increment/decrement with: `product_id`, `user_id`, `quantity_before`, `quantity_after`, `delta`, `reason`, `timestamp`.
- Enforces audit traceability — no stock change is permitted without a recorded justification.

**KPI:** `ProductModel::getTotalStock()` — aggregate stock sum exposed on the dashboard.

---

### Module 11: Gestión de Usuarios (User Administration)
**Visibility:** Super-Admin only (`isSuperAdmin()`)  
**Route:** `admin/users`

Full lifecycle management of user accounts:
- Create, edit, deactivate users.
- Assign one or many roles.
- Assign branch access (`user_branch_access` pivot).
- Toggle `view_cost` permission (controls cost/margin data visibility in views).
- Force password reset on next login (`requires_password_reset` flag).

---

### Module 12: Roles y Permisos (Roles & Permissions)
**Visibility:** Super-Admin only  
**Route:** `admin/roles`

- Define named roles.
- Attach/detach permission keys from roles.
- Effective permissions are evaluated at runtime via `hasModuleAccess()`.

---

## 7. Context & Branch Persistence Engine

The Context Engine is the system's most critical cross-cutting concern. It operates via two parallel session dimensions:

| Session Key | Set By | Cleared By | Purpose |
|---|---|---|---|
| `active_branch_id` | `Context::setBranch()` | Never (sticky per session) | Scopes all operational writes (Ventas, Cobranzas inserts) and reads via `beforeFind` hook |
| `active_branch_name` | `Context::setBranch()` | Never | Display label in navbar |
| `view_context` | `Context::set{Holding,Category,Zone}()` | `Context::setBranch()` | Drives KPI aggregation scope on Dashboard and Reports |
| `view_context_label` | Same as above | Same as above | Display label for the active aggregation context |

**Design invariant:** Setting a holding/category/zone context deliberately **does not overwrite** `active_branch_id`. This ensures that navigating to Ventas or Cobranzas always respects the last explicitly chosen concrete branch, while the Dashboard can simultaneously display a broader aggregated view.

---

## 8. Security & Architectural Constraints

| Constraint | Implementation |
|---|---|
| **Password Hashing** | `password_hash()` / `password_verify()` — Bcrypt/Argon2 exclusively. MD5/SHA1 strictly forbidden. |
| **CSRF Protection** | CI4 built-in CSRF tokens enforced on all POST routes; regenerated on each AJAX response. |
| **Input Validation** | CI4 Validation library with `$validationRules` per model before any DB write. |
| **XSS Prevention** | `esc()` wrapper on all user-supplied data rendered in views. |
| **Query Safety** | 100% CI4 Query Builder / prepared statements. Raw SQL string concatenation is forbidden. |
| **Access Control** | Every controller method checks `hasModuleAccess()` or `isSuperAdmin()` before processing. |
| **Activity Logging** | `logActivity()` helper records branch changes, holding activations, and other critical events. |
| **Pagination** | All list views paginate results to constrain memory and payload size. |

---

## 9. Database Migrations Inventory

| Migration File | Purpose |
|---|---|
| `2026-04-14_RbacSetup` | Initial RBAC schema (users, roles, permissions, pivots) |
| `2026-04-15_CreateVentasTable` | Core `ventas` table |
| `2026-04-15_CreateSucursalesTables` | `sucursales`, `holdings`, `zonas` |
| `2026-04-18_RefactorSucursalesAddBrands` | `sucursal_marcas`, `sucursal_features`, category feature flags |
| `2026-04-18_AddUserBranchAccess` | `user_branch_access`, super-admin flag |
| `2026-04-20_TranslateProductUnits` | Unit of measure translation |
| `2026-04-23_MoveUoMToCategories` | UoM moved to `marcas_categorias` |
| `2026-04-23_CreateMarcaTiposTable` | `marca_tipos` catalog |
| `2026-04-23_AddDynamicFieldsToVentaItems` | `billing`, `collections`, `gross_profit` on `venta_items` |
| `2026-04-23_CreateSucursalProductosTable` | Branch-specific product mapping |
| `2026-04-24_AddServiceRevenue` | `service_revenue` on categories and `ventas` |
| `2026-04-25_CreateCobranzasTable` | `cobranzas` CxC table |
| `2026-04-30_CreateInventoryLogsTable` | Adjustment ledger |
| `2026-04-30_CreateMonthlyGoalsTable` | Initial `monthly_goals` table |
| `2026-05-02_AddViewCostToUsers` | `view_cost` user flag |
| `2026-05-03_UpdateMonthlyGoalsTable` | Refactor to `context_type` / `context_id` model |

---

## 10. Model Reference

| Model | Table | Key Purpose |
|---|---|---|
| `VentasModel` | `ventas` | Daily sales header; context-aware KPI helpers |
| `VentaItemModel` | `venta_items` | Sales line items by brand/type; `syncForVenta()` |
| `CobranzasModel` | `cobranzas` | CxC daily collections; aging aggregation |
| `MonthlyGoalModel` | `monthly_goals` | Hierarchical goal storage and projection data |
| `ReportesModel` | (multi-table) | Complex aggregate reports with context filtering |
| `SucursalModel` | `sucursales` | Branch CRUD |
| `SucursalCategoriaModel` | `sucursales_categorias` | Group/type definitions with feature flags |
| `SucursalMarcaModel` | `sucursal_marcas` | Branch–brand authorization pivot |
| `SucursalFeatureModel` | `sucursal_features` | Branch-level feature flag pivot |
| `SucursalTipoModel` | `sucursal_tipos` | Branch type many-to-many pivot |
| `SucursalZonaModel` | `sucursal_zonas` | Branch–zone membership pivot |
| `SucursalProductoModel` | `sucursal_productos` | Branch-specific product catalog |
| `MarcaModel` | `marcas` | Brand catalog |
| `MarcaCategoriaModel` | `marcas_categorias` | Product/service type categories with UoM |
| `MarcaTipoModel` | `marca_tipos` | Brand type classification |
| `ProductModel` | `products` | Full product catalog with stock and pricing |
| `SupplierModel` | `suppliers` | Product supplier reference data |
| `InventoryLogModel` | `inventory_logs` | Stock adjustment audit ledger |
| `HoldingModel` | `holdings` | Corporate holding entities |
| `ZonaModel` | `zonas` | Geographic zone entities |
| `UserModel` | `users` | User accounts with RBAC and branch access |
| `UserBranchAccessModel` | `user_branch_access` | User–branch authorization pivot |
| `RoleModel` | `roles` | Role definitions |
| `PermissionModel` | `permissions` | Permission key catalog |
| `RolePermissionModel` | `role_permissions` | Role–permission pivot |
| `UserRoleModel` | `user_roles` | User–role pivot |

---

## 11. Future Enhancements

- **REST API Layer** — Tokenized endpoints for external consumption by mobile or third-party tools.
- **Report Export Utilities** — Excel (`.xlsx`) and PDF exports for all report types.
- **Multi-currency Support** — Exchange rate configuration and automated currency conversion on sales data.
- **Push Notification System** — Threshold-based alerts when actuals fall below a defined percentage of goal.
- **Deep-Dive Analytics** — Expanded charting: trend lines, period-over-period comparisons, goal attainment heat maps per branch.
- **Comprehensive Audit Log Viewer** — Admin UI for browsing the `logActivity()` event stream with filtering by user, event type, and date range.

---

## 12. Acceptance Criteria

- [ ] Secure authentication environment; no weak credential mechanisms permitted.
- [ ] RBAC fully operational — role assignments correctly toggle module access and sidebar visibility.
- [ ] `active_branch_id` context scopes all Ventas and Cobranzas reads/writes automatically.
- [ ] `view_context` drives Dashboard KPI aggregation across branch, category, holding, and zone scopes without overwriting the operational branch.
- [ ] All sales entry forms render only fields enabled by the branch's group feature flags.
- [ ] Branch–brand authorization (`sucursal_marcas`) correctly limits brand options in the sales line-item form.
- [ ] Goal projections correctly calculate daily rates and variance against actuals.
- [ ] Reports render correct aggregations with proper context filtering at all hierarchy levels.
- [ ] Inventory adjustments are rejected without a mandatory reason; all changes appear in the audit log.
- [ ] All inputs validated server-side before any DB write; all output escaped with `esc()`.
- [ ] PSR-12 coding standard enforced across all PHP files.
- [ ] Consistent Tailwind UI — Gold/Dark theme applied uniformly across all modules.
