252 lines
10 KiB
Markdown
252 lines
10 KiB
Markdown
# Architecture and System Design
|
|
|
|
**Variable Remuneration, Compensation, and Commissions System - Hoteles Estelar**
|
|
|
|
---
|
|
|
|
## 1. Technical Stack
|
|
|
|
* **Frontend**: Next.js App Router (React + TypeScript).
|
|
* **Styling**: Vanilla CSS utilizing **CSS Modules** (`*.module.css`) for component-level style isolation, paired with a global variables system (`globals.css`) defining the design tokens.
|
|
* **Backend**: Next.js API Routes (Node.js runtime).
|
|
* **ORM**: Prisma ORM (providing type-safe database queries and automated schema migrations).
|
|
* **Database**: PostgreSQL (decoupled, configured via environment variables to run on any host/network).
|
|
* **Workflow Engine**: **n8n** (external service triggered via API Webhooks). Runs the actual calculation steps, anomaly checks, AI-assisted audits, and notifications. This allows live monitoring of tasks and flexible AI model switching (e.g., swapping OpenAI/Anthropic/Ollama models within n8n nodes without rebuilding the Next.js codebase).
|
|
* **Auditing**: Ready-to-use, community-proven **`@explita/prisma-audit-log`** Prisma Client Extension. It automatically intercepts database mutations (create, update, delete), tracks changes (old vs new state), handles sensitive field masking (e.g. passwords), and records logs into the `AuditLog` table. This approach is database-agnostic, requires no native OS dependencies, and runs purely inside the runtime.
|
|
|
|
---
|
|
|
|
## 2. Decoupled Network & Environment Independence
|
|
|
|
The project is structured to run in any isolated Docker environment. All parameters are fed via environment variables to cleanly partition production and development configurations:
|
|
|
|
### 2.1. Environment Variables
|
|
* **Core Variables (Both Env)**:
|
|
* `DATABASE_URL`: Connection string for the active database (Production or Development).
|
|
* `NEXT_PUBLIC_APP_URL`: The domain or local host path of the running application.
|
|
* `NEXTAUTH_SECRET`: Secret key for JWT session validation.
|
|
* **Development-Exclusive Test Variables**:
|
|
* `TEST_DATABASE_URL`: Connection string to the secondary sandbox/test database.
|
|
* `N8N_TEST_WEBHOOK_URL`: The n8n testing webhook entry point. Used by development services and test runners.
|
|
* `N8N_WEBHOOK_SECRET`: Token to authorize and verify n8n webhook payload signatures locally.
|
|
|
|
### 2.2. Component Interaction:
|
|
```mermaid
|
|
graph TD
|
|
User([User Client]) -->|HTTPS| WebApp[Next.js App Router]
|
|
|
|
subgraph Isolated Network
|
|
WebApp -->|Prisma Client| DB[(PostgreSQL Main)]
|
|
WebApp -.->|Prisma Client - Test Env| DBTest[(PostgreSQL Test)]
|
|
WebApp -->|HTTP POST Webhook /webhook-test| n8n[n8n Workflow Engine]
|
|
n8n -->|IF Webhook Path Match| DBTest
|
|
n8n -->|Else| DB
|
|
n8n -->|HTTP POST Callback| WebApp
|
|
end
|
|
```
|
|
|
|
---
|
|
|
|
## 3. Database Schema Design (Entity-Relationship Diagram)
|
|
|
|
```mermaid
|
|
erDiagram
|
|
REGIONS ||--o{ HOTELS : contains
|
|
HOTELS ||--o{ USERS : houses
|
|
USERS ||--o{ GOALS : achieves
|
|
USERS ||--o{ SALES_RESULTS : generates
|
|
USERS ||--o{ SETTLEMENTS : receives
|
|
|
|
COMPENSATION_PLANS ||--o{ CALCULATION_RULES : dictates
|
|
COMPENSATION_PLANS ||--o{ SETTLEMENTS : calculates
|
|
|
|
USERS ||--o{ AUDIT_LOGS : executes
|
|
USERS ||--o{ NOTIFICATIONS : receives
|
|
|
|
REGIONS {
|
|
int id PK
|
|
string name
|
|
string code
|
|
}
|
|
|
|
HOTELS {
|
|
int id PK
|
|
string name
|
|
string code
|
|
int region_id FK
|
|
string status
|
|
}
|
|
|
|
USERS {
|
|
int id PK
|
|
string username
|
|
string email
|
|
string password_hash
|
|
string role "ADMIN | DIRECTOR | GERENTE | LIDER | ANALISTA | CONSULTA | COLABORADOR"
|
|
int hotel_id FK
|
|
string area
|
|
string status "ACTIVE | INACTIVE"
|
|
datetime created_at
|
|
}
|
|
|
|
COMPENSATION_PLANS {
|
|
int id PK
|
|
string name
|
|
string code UK
|
|
datetime validity_start
|
|
datetime validity_end
|
|
string type "PERCENTAGE | SCALE | CONDITIONAL | FIXED"
|
|
string formula "JSON or string representation"
|
|
decimal meta_amount
|
|
decimal percentage_rate
|
|
decimal max_cap
|
|
string status "DRAFT | ACTIVE | INACTIVE"
|
|
int version
|
|
int created_by FK
|
|
datetime created_at
|
|
}
|
|
|
|
CALCULATION_RULES {
|
|
int id PK
|
|
int plan_id FK
|
|
string type "TIER | BONUS"
|
|
decimal min_achievement "percentage"
|
|
decimal max_achievement "percentage"
|
|
decimal rate "multiplier or percentage"
|
|
decimal payout_amount "fixed payment"
|
|
}
|
|
|
|
GOALS {
|
|
int id PK
|
|
string target_type "INDIVIDUAL | TEAM | HOTEL"
|
|
int target_id "user_id, team_id, or hotel_id"
|
|
string period "YYYY-MM"
|
|
decimal amount
|
|
datetime created_at
|
|
}
|
|
|
|
SALES_RESULTS {
|
|
int id PK
|
|
string source "EXCEL | API"
|
|
int hotel_id FK
|
|
int user_id FK "colaborador"
|
|
string period "YYYY-MM"
|
|
decimal amount
|
|
int sales_count
|
|
string status "PENDING | PROCESSED"
|
|
int uploaded_by FK
|
|
datetime created_at
|
|
}
|
|
|
|
SETTLEMENTS {
|
|
int id PK
|
|
string period "YYYY-MM"
|
|
int plan_id FK
|
|
int user_id FK
|
|
decimal sales_amount
|
|
decimal goal_amount
|
|
decimal achievement_percentage
|
|
decimal calculated_commission
|
|
decimal calculated_bonus
|
|
decimal total_payout
|
|
string status "SIMULATED | PENDING | APPROVED | REJECTED"
|
|
int approved_by FK
|
|
datetime approved_at
|
|
string rejection_reason
|
|
datetime created_at
|
|
}
|
|
|
|
AUDIT_LOGS {
|
|
int id PK
|
|
int user_id FK
|
|
string action "CREATE | UPDATE | DELETE | APPROVE | REJECT | LOGIN"
|
|
string target_table
|
|
int target_id
|
|
json previous_value
|
|
json new_value
|
|
string ip_address
|
|
datetime created_at
|
|
}
|
|
|
|
NOTIFICATIONS {
|
|
int id PK
|
|
int user_id FK
|
|
string title
|
|
string message
|
|
string status "UNREAD | READ"
|
|
string type "EMAIL | PUSH"
|
|
datetime sent_at
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## 4. Workflows & n8n Integration Model
|
|
|
|
By offloading calculations and integrations to n8n, we achieve a highly visual, modular, and editable workflow architecture.
|
|
|
|
### 4.1. Sales Data Import Workflow
|
|
1. **Trigger**: Next.js calls `POST /api/n8n/import-sales` which forwards the parsed Excel payload to n8n's webhook URL.
|
|
2. **n8n Processing**:
|
|
- Iterates through sales records.
|
|
- Queries Next.js APIs to validate collaborator codes and hotel IDs.
|
|
- Cleanses data and identifies duplicates.
|
|
- Uses an LLM node (with configurable models: GPT-4, Claude 3.5, Gemini, etc.) to perform semantic anomaly checks (e.g., flag sales values that deviate more than 2.5 standard deviations from the collaborator's monthly average).
|
|
3. **Response**: n8n POSTs the sanitized/flagged list back to `POST /api/sales/batch-save` in Next.js to update the database.
|
|
|
|
### 4.2. Settlement Calculation Workflow
|
|
1. **Trigger**: Next.js calls n8n to execute the calculation for period `YYYY-MM`.
|
|
2. **n8n Processing**:
|
|
- Pulls active plans, individual goals, and actual sales from the Next.js API.
|
|
- Evaluates the mathematical formulas.
|
|
- Evaluates rule scales and applies caps.
|
|
- Generates notifications (via email or push notifications) using n8n integrations.
|
|
3. **Response**: Updates database records via the Next.js API and completes the task.
|
|
|
|
### 4.3. Test Webhook Branching & Database Isolation in n8n
|
|
To ensure complete isolation of production data, all n8n workflows must follow a strict testing branch architecture:
|
|
1. **Webhook Entry Node**: n8n listens on two webhook path variants:
|
|
- Production calls hit: `/webhook/calculate-commissions`
|
|
- Test suite calls hit: `/webhook-test/calculate-commissions`
|
|
2. **Conditional Path Routing**:
|
|
- An `IF` node immediately checks if the webhook request path contains `webhook-test`.
|
|
- **True (Test Mode)**: The workflow overrides its database credential node configurations to connect to `TEST_DATABASE_URL` (the secondary test sandbox database) and makes API callbacks back to the Next.js test instance.
|
|
- **False (Prod Mode)**: The workflow executes against the main `DATABASE_URL` and interacts with the production Next.js instance.
|
|
|
|
---
|
|
|
|
## 5. Security & Access Control Model (RBAC)
|
|
|
|
We define role-based access restrictions as follows:
|
|
|
|
| Role | Access Level | Restrictions |
|
|
| :--- | :--- | :--- |
|
|
| **Administrador** | Full system write & read. | None. |
|
|
| **Director Comercial** | Reads all dashboards & reports. Can configure metadata. | Cannot calculate or approve. |
|
|
| **Gerente Hotel** | Reads data, sales, and settlements for their specific Hotel. | Restricted to `hotel_id`. |
|
|
| **Líder Comercial** | Triggers simulations, views dashboards. Approves/Rejects settlements. | Restricted to their region/team. |
|
|
| **Analista Financiero** | Reviews calculations. Exports consolidated PDF/Excel reports. | Cannot approve. |
|
|
| **Consulta** | Read-only. | No mutations allowed. |
|
|
| **Colaborador** | Consults own history & dashboard. | Restricted to `user_id`. |
|
|
|
|
---
|
|
|
|
## 6. Dual-Environment Docker Deployment Model
|
|
|
|
We design the containerized architecture to run two distinct instances of the application concurrently from the same codebase, ensuring clean division.
|
|
|
|
### 6.1. Service Configurations
|
|
* **Production Container (`app-prod`)**:
|
|
* **Network Port**: Exposed on port `3000` (mapped via Caddy to `special-hotel.yourdomain.com`).
|
|
* **Database**: Bound to the production `DATABASE_URL`.
|
|
* **Logs**: Prefixed with `[PROD]` inside the container engine.
|
|
* **Development Container (`app-dev`)**:
|
|
* **Network Port**: Exposed on port `3001` (mapped via Caddy to `special-hotel-dev.yourdomain.com`).
|
|
* **Database**: Bound to `TEST_DATABASE_URL` (acting as its main `DATABASE_URL` for test isolated migrations).
|
|
* **Logs**: Prefixed with `[DEV]` for easy debugging contrast.
|
|
|
|
### 6.2. Graceful Dev Failure Model
|
|
The development instance utilizes a validation startup hook. If any development-exclusive environment variables (like `TEST_DATABASE_URL`) are omitted:
|
|
1. The `app-dev` container logs a clear notification: `[DEV] Missing required development variables. Gracefully shutting down development service.`
|
|
2. The entrypoint script exits with **exit code 0**.
|
|
3. Docker or the compose orchestrator registers the container as cleanly stopped (not crashed). The production stack is completely unaffected, avoiding restart-loop penalties or deployment failures.
|