semillero-special-hotel/docs/PHASE_4_IMPLEMENTATION.md

7.9 KiB

Phase 4 Implementation & Integration Design Document

Variable Remuneration, Compensation, and Commissions System - Hoteles Estelar


This document outlines the detailed design decisions, schema mappings, API endpoints, UI layouts, and security/idempotency validations planned for Phase 4: Data Import & Integrations.

1. Architectural Strategy & Logic Flows

1.1. Excel Parser & Data Validation Flow

To prevent manual data-entry errors, the system allows authorized users (Administrators, Analysts, and Commercial Leaders) to upload Excel/CSV sheets with sales results.

Excel Spreadsheet Format Specifications

Two pre-populated spreadsheets are available under the public directory:

  1. Template spreadsheet: import_sales_template.xlsx — Clean column layout with a single dummy row reference. This template is made directly downloadable through the program's UI.
  2. Test spreadsheet: import_sales_test.xlsx — Contains mixed valid and invalid rows to verify frontend/backend validation error rendering.

The spreadsheet contains the following mandatory headers:

  • Colaborador: String representing the unique collaborator username (e.g. colaborador_mde).
  • Periodo: String matching the target period in YYYY-MM format (e.g. 2026-06).
  • Hotel: String representing the unique hotel code (e.g. EST-MDE).
  • Monto: Decimal/Numeric positive value of total sales.
  • Cantidad: Integer positive value of total sales count.
  • Id_Transaccion: String representing the external transaction tracking ID (e.g. TX-EST-MDE-001).

The server-side parsing will:

  1. Parse the uploaded .xlsx or .csv file buffer using the xlsx library.
  2. Resolve row-level records and perform Atomic Validation on all rows before write transactions.
  3. If any row contains errors, abort the entire operation and return a structured JSON report identifying the exact rows, columns, values, error codes, and translation metadata.

1.2. Multilingual "Code + Metadata" Response Pattern

To support dynamic localized UI translations, the API does not return pre-translated text strings. Instead, it enforces the Code + Metadata pattern:

  • Success Responses: Return a strict static success code alongside numeric/string variables in a metadata payload.
  • Error Responses: Return strict error codes (USER_NOT_FOUND, INVALID_PERIOD_FORMAT, etc.) with their respective parameters. The client-side application translates these keys locally using translation tables.

1.3. Two-Tier Idempotency Control (API & DB Layer)

To guarantee that duplicate uploads do not lead to duplicate commission calculations:

  1. API Header Check: The POST /api/sales/import endpoint requires a client-generated Idempotency-Key header.
  2. Key Check:
    • The backend checks if any existing sales results contain an idempotency key matching the pattern ${idempotency_key}-*.
    • True: The import is recognized as a duplicate. The server returns the cached success details of the previous import, preventing re-execution.
    • False: Processing continues.
  3. Row-level uniqueness: Each inserted row is saved with a unique database constraint idempotencyKey = ${idempotency_key}-${row_index}, guaranteeing database-level data integrity under concurrent scenarios.
graph TD
    A[Upload request with Idempotency-Key] --> B{Key already processed?}
    B -->|Yes| C[Return cached/existing import summary]
    B -->|No| D[Parse Excel/CSV Buffer]
    D --> E{Any validation error?}
    E -->|Yes| F[Abort and return detailed error list]
    E -->|No| G{N8N_WEBHOOK_URL set?}
    G -->|Yes| H[Forward rows to n8n Webhook & return 202 Accepted]
    G -->|No / Test| I[Prisma Transaction: Save rows with idempotency key + Audit Log]
    I --> J[Return 201 Created]

1.4. n8n Integration & Callback Validation

For automatic integrations (US-COM-005):

  1. Webhook Security: Next.js exposes a public-facing but secured callback endpoint /api/sales/batch-save.
  2. Signature Verification: Webhooks from n8n must include the x-n8n-signature header. The server verifies this token against N8N_WEBHOOK_SECRET before executing database updates.
  3. Async Status Polling: The frontend displays a premium progress UI. If routed through n8n, it polls GET /api/sales/import/status/[key] to check database status and update progress.

2. API Specifications

2.1. POST /api/sales/import (Upload Sales Sheet)

  • Role Restriction: admin | analyst | commercial_leader
  • Headers:
    • Idempotency-Key: Required string
  • Request Body: multipart/form-data with file field containing the spreadsheet.
  • Response:
    • 201 Created (Direct import mode):
      {
        "success": true,
        "code": "IMPORT_SUCCESSFUL",
        "metadata": {
          "count": 45,
          "totalAmount": 1563000.00
        }
      }
      
    • 202 Accepted (n8n mode):
      {
        "success": true,
        "code": "IMPORT_ACCEPTED",
        "metadata": {
          "idempotencyKey": "unique-client-key-123",
          "status": "PROCESSING"
        }
      }
      
    • 400 Bad Request (Validation errors):
      {
        "success": false,
        "error": {
          "code": "IMPORT_VALIDATION_FAILED",
          "details": [
            { 
              "row": 3, 
              "column": "Colaborador", 
              "value": "colaborador_inexistente", 
              "code": "USER_NOT_FOUND", 
              "metadata": { "username": "colaborador_inexistente" } 
            },
            { 
              "row": 4, 
              "column": "Periodo", 
              "value": "2026/06", 
              "code": "INVALID_PERIOD_FORMAT", 
              "metadata": { "expected": "YYYY-MM" } 
            }
          ]
        }
      }
      

2.2. POST /api/sales/batch-save (n8n Webhook Callback)

  • Security Check: Header x-n8n-signature === process.env.N8N_WEBHOOK_SECRET
  • Request Body:
    {
      "idempotencyKey": "unique-client-key-123",
      "uploaderId": 1,
      "sales": [
        { "username": "colaborador_mde", "hotelCode": "EST-MDE", "period": "2026-06", "amount": 15000.00, "salesCount": 3 }
      ]
    }
    
  • Response: 201 Created or 400 Bad Request.

2.3. GET /api/sales/import/status/[key] (Poll Status)

  • Response:
    {
      "idempotencyKey": "unique-client-key-123",
      "status": "SUCCESS" // PROCESSING | SUCCESS | FAILED
    }
    

3. UI Design Specifications

We will create a premium drag-and-drop loading interface at /sales/import:

  1. Interactive Drop Zone: Elegant border animation on dragover. Shows file metadata upon dropping.
  2. Template Download Link: Sleek, visible button to download the pre-formatted Excel template directly.
  3. Real-time Progress Indicator: Fluid CSS progress bar tracking parse/upload state.
  4. Inconsistency Panel: If the API returns validation errors, displays them in a sleek, scrollable log table with warning icons.
  5. Permissions Enforcement: Renders standard unauthorized page if role is not permitted.

4. Headless Puppeteer Verification Plan

We will create a new test script prisma/test-phase4-ui.js verifying:

  1. Role Enforcement: colaborador_mde is blocked from accessing the page and endpoint.
  2. Missing Header Validation: Upload fails if Idempotency-Key is missing.
  3. File Validation: Uploading an Excel file with negative values or fake users displays validation errors.
  4. Successful Direct Import: Uploading a valid Excel file imports rows, saves them, and shows success.
  5. Idempotency Prevention: Re-uploading with the same key returns the success message without modifying/inserting additional database records.
  6. n8n Webhook Callback Integrity: POSTing to /api/sales/batch-save with an invalid signature is blocked (401), while a valid signature is processed.