Skip to content

iarturo/enterprise-sales-api

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

16 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

n8n Supabase PostgreSQL Redis Status License

🏒 Enterprise Sales β€” n8n Backend Reference

A reference implementation of an enterprise-style Sales Management API, built entirely on n8n workflows.
Demonstrates production patterns: authentication, rate limiting, idempotency, atomic transactions, and observability β€” without writing a single line of backend server code.

About β€’ Quick Start β€’ Architecture β€’ API Reference β€’ Security Patterns β€’ Deployment


πŸ“– About This Project

This repository is a portfolio piece demonstrating how far n8n can be pushed as a backend platform. It is a fully functional reference implementation β€” every endpoint works, every validation runs, every workflow is wired end-to-end β€” but it has not been deployed to serve real users in production.

It exists to showcase a specific set of skills:

  • Designing REST APIs with proper auth, rate limiting, and idempotency
  • Modeling atomic database transactions for inventory + sales flows
  • Composing observability and operational tooling (health checks, logging, backups)
  • Architecting layered security (defense in depth)
  • Documenting an API to a level where a third party could integrate against it

If you are evaluating this repo for hiring or collaboration purposes, the code, workflow, and documentation here represent how I approach backend design problems. Happy to walk through any design decision in detail.


🎯 Overview

Enterprise Sales transforms n8n from a simple automation tool into a structured REST API backend. It exposes webhook endpoints that handle the full lifecycle of a sales operation β€” from user authentication to invoice generation β€” while enforcing rate limiting, idempotency, input sanitization, and atomic database transactions.

What this project demonstrates

Conventional Approach This Reference Implementation
Months building a custom Express/FastAPI backend A single n8n workflow handles HTTP routing & orchestration
Writing auth middleware from scratch Supabase Auth with JWT validation, wired through n8n nodes
Manual rate limiting implementation Redis-backed rate limiting per IP + User-Agent
Custom idempotency layer Redis SETNX with 24h TTL
Boilerplate transaction handling PostgreSQL stored function for atomic sale + inventory update

✨ Features Implemented

πŸ” Authentication & Authorization

  • Supabase Auth integration with JWT-based access & refresh tokens
  • Role-based access control (admin, seller, custom roles)
  • Multi-tenant support via company_id scoping
  • CORS configuration with environment-driven allowed origins

πŸ›‘οΈ Security Patterns

  • Redis-powered rate limiting β€” 5 requests/minute per IP + User-Agent fingerprint
  • Idempotency keys β€” prevent duplicate sale creation with Redis SETNX + 24h TTL
  • Input sanitization β€” HTML/SQL injection protection on all user-supplied strings
  • Parameterized SQL β€” zero raw string interpolation in database queries
  • Request validation β€” strict type checking, range enforcement, format validation
  • HTTP timeouts β€” 10s timeouts on all external service calls

πŸ’° Sales Processing

  • Atomic sale creation with PostgreSQL stored function (create_sale_with_inventory_update)
  • Real-time inventory verification with row-level locking (SELECT ... FOR UPDATE)
  • Race condition detection with HTTP 409 responses
  • Automatic tax calculation with configurable tax rates
  • Auto-generated invoice numbers (F-YYYY-XXXXXX-XXX)
  • Validation for up to 100 line items per sale, quantities up to 10,000 units

πŸ“Š Reporting & Export

  • Paginated sales queries with date range filtering (up to 10,000 records)
  • Excel/PDF export via CloudConvert API integration
  • Async report generation with execution job tracking

πŸ”„ Operational Patterns

  • Health check endpoint β€” monitors PostgreSQL + Redis connectivity
  • Scheduled backup workflow β€” pg_dump on cron, with audit logging to backup_logs table
  • Centralized error logging β€” failures forwarded to Datadog for observability

πŸ—οΈ Architecture

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                        CLIENT APPLICATION                          β”‚
β”‚                    (Web App / Mobile / cURL)                        β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                               β”‚ HTTPS
                               β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                         n8n WORKFLOW ENGINE                         β”‚
β”‚                                                                     β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚
β”‚  β”‚  /api/auth   β”‚  β”‚  /api/sales  β”‚  β”‚ /api/    β”‚  β”‚  /api/health β”‚ β”‚
β”‚  β”‚   /login     β”‚  β”‚  (POST)      β”‚  β”‚ reports/ β”‚  β”‚  (GET)       β”‚ β”‚
β”‚  β”‚  (POST)      β”‚  β”‚              β”‚  β”‚  sales   β”‚  β”‚              β”‚ β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”˜  β””β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”˜  β””β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”˜  β””β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚
β”‚         β”‚                 β”‚               β”‚               β”‚         β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”  β”Œβ”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”  β”Œβ”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”  β”Œβ”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”β”‚
β”‚  β”‚   Validate   β”‚  β”‚  Validate    β”‚  β”‚ Validate β”‚  β”‚    Check     β”‚β”‚
β”‚  β”‚    Input     β”‚  β”‚   Token      β”‚  β”‚  Token   β”‚  β”‚  Services    β”‚β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”˜  β””β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”˜  β””β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”˜  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜β”‚
β”‚         β”‚                 β”‚               β”‚                         β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”  β”Œβ”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”       β”‚                        β”‚
β”‚  β”‚ Rate Limit   β”‚  β”‚ Idempotency  β”‚       β”‚                        β”‚
β”‚  β”‚  (Redis)     β”‚  β”‚   (Redis)    β”‚       β”‚                        β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”˜  β””β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”˜       β”‚                        β”‚
β”‚         β”‚                 β”‚               β”‚                        β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”  β”Œβ”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”  β”Œβ”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”                 β”‚
β”‚  β”‚  Supabase    β”‚  β”‚  Inventory   β”‚  β”‚  Query   β”‚                 β”‚
β”‚  β”‚    Auth      β”‚  β”‚ Verification β”‚  β”‚  + Export β”‚                 β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β””β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”˜  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜                 β”‚
β”‚                           β”‚                                        β”‚
β”‚                    β”Œβ”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”                                β”‚
β”‚                    β”‚   Atomic     β”‚                                β”‚
β”‚                    β”‚ Transaction  β”‚                                β”‚
β”‚                    β”‚ (PL/pgSQL)   β”‚                                β”‚
β”‚                    β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜                                β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                               β”‚
            β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
            β”‚                  β”‚                  β”‚
      β”Œβ”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”   β”Œβ”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”   β”Œβ”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”
      β”‚ PostgreSQL  β”‚   β”‚    Redis    β”‚   β”‚   Supabase   β”‚
      β”‚ (Data)      β”‚   β”‚ (Cache/     β”‚   β”‚   (Auth)     β”‚
      β”‚             β”‚   β”‚  Rate Limit)β”‚   β”‚              β”‚
      β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜   β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜   β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Workflow Pipelines

Pipeline Trigger Key Nodes Purpose
Auth Login POST /api/auth/login Validate Input β†’ Redis Rate Limit β†’ Supabase Auth β†’ Process Auth Authenticate users, return JWT
Create Sale POST /api/sales Validate Token β†’ Supabase Verify β†’ Redis Idempotency β†’ Verify Inventory β†’ Process Sale β†’ Atomic Transaction Create a new sale with inventory update
Sales Report GET /api/reports/sales Validate Token β†’ Supabase Verify β†’ PostgreSQL Query β†’ CloudConvert Export Generate & export sales reports
Health Check GET /api/health PostgreSQL Ping β†’ Redis Ping β†’ Aggregate Status Monitor infrastructure health
Scheduled Backup Cron 0 2 * * * Execute pg_dump β†’ Log Backup Database backup workflow

πŸš€ Quick Start

Prerequisites

Service Minimum Version Purpose
n8n v1.0+ Workflow engine
PostgreSQL 14+ Primary data store
Redis 6+ Rate limiting & idempotency cache
Supabase Free tier Authentication provider

1. Clone the Repository

git clone https://github.com/iarturo/enterprise-sales-api.git
cd enterprise-sales-api

2. Set Up the Database

-- Create the database
CREATE DATABASE ventas_enterprise;
CREATE USER ventas_app WITH PASSWORD 'your_secure_password';
GRANT ALL PRIVILEGES ON DATABASE ventas_enterprise TO ventas_app;

Then run the stored function required for atomic sale transactions:

-- File: Function.txt
-- Creates the `create_sale_with_inventory_update` PL/pgSQL function
-- Handles inventory locking, stock validation, and sale insertion atomically
\i Function.txt

3. Configure Environment Variables

Set the following environment variables in your n8n instance:

# ── Supabase ──────────────────────────────────────
SUPABASE_URL=https://your-project.supabase.co
SUPABASE_ANON_KEY=your-anon-key

# ── Database ──────────────────────────────────────
DB_HOST=localhost
DB_USER=postgres
DB_NAME=ventas_enterprise
DB_PASSWORD=your-db-password

# ── Monitoring ────────────────────────────────────
DATADOG_API_KEY=your-datadog-api-key

# ── Business Logic ────────────────────────────────
TAX_RATE=0.16
PAYMENT_METHODS=cash,card,transfer,check
FRONTEND_URL=https://app.yourdomain.com

# ── Reporting (Optional) ─────────────────────────
CLOUDCONVERT_API_KEY=your-cloudconvert-key

4. Import the Workflow

  1. Open your n8n instance
  2. Click Import from file
  3. Select enterprise-sales.json
  4. Assign credentials to each node group:
    • PostgreSQL nodes β†’ your PostgreSQL credential
    • Redis nodes β†’ your Redis credential
    • Supabase HTTP nodes β†’ Header Auth credential
    • CloudConvert nodes β†’ Header Auth credential
    • Datadog nodes β†’ Header Auth credential
  5. Toggle the workflow to Active βœ…

5. Create Your First User

-- In the Supabase SQL Editor:
INSERT INTO auth.users (email, encrypted_password, email_confirmed_at, created_at, updated_at)
VALUES ('admin@yourcompany.com', crypt('strong_password_here', gen_salt('bf')), NOW(), NOW(), NOW());

UPDATE auth.users
SET raw_user_meta_data = '{"role": "admin", "company_id": 1, "profile": {"name": "Admin User"}}'
WHERE email = 'admin@yourcompany.com';

πŸ“‘ API Reference

Authentication

POST /api/auth/login

Authenticate a user and receive JWT tokens.

Request:

curl -X POST https://your-n8n.com/webhook/api/auth/login \
  -H "Content-Type: application/json" \
  -d '{
    "email": "admin@yourcompany.com",
    "password": "strong_password_here"
  }'

Response 200 OK:

{
  "success": true,
  "user": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "email": "admin@yourcompany.com",
    "role": "admin",
    "company_id": 1,
    "profile": { "name": "Admin User" }
  },
  "tokens": {
    "accessToken": "eyJhbGciOiJIUzI1NiIs...",
    "refreshToken": "v1.MjQ1NjM4..."
  },
  "expiresIn": 3600
}

Error Responses:

Status Code Description
400 Bad Request Missing or invalid email/password format
401 Unauthorized Invalid credentials
429 Too Many Requests Rate limit exceeded (5 req/min)

Sales

POST /api/sales

Create a new sale with automatic inventory management.

Headers:

Header Required Description
Authorization βœ… Bearer <access_token>
Idempotency-Key βœ… Unique UUID to prevent duplicate submissions
Content-Type βœ… application/json

Request:

curl -X POST https://your-n8n.com/webhook/api/sales \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIs..." \
  -H "Idempotency-Key: 550e8400-e29b-41d4-a716-446655440000" \
  -d '{
    "customer_info": {
      "name": "Jane Doe",
      "email": "jane@example.com",
      "phone": "+1-555-123-4567"
    },
    "items": [
      { "product_id": 1, "quantity": 2, "unit_price": 49.99 },
      { "product_id": 5, "quantity": 1, "unit_price": 129.00 }
    ],
    "payment_method": "card"
  }'

Response 200 OK:

{
  "success": true,
  "invoiceNumber": "F-2026-847293-042",
  "totalAmount": 228.98,
  "message": "Sale registered successfully"
}

Validation Constraints:

Field Rule
items 1–100 items per sale
items[].quantity 1–10,000 units
items[].unit_price $0.01–$1,000,000
customer_info.name Required, max 255 chars, sanitized
customer_info.email Optional, validated format
payment_method One of: cash, card, transfer, check (configurable)

Error Responses:

Status Code Description
400 Bad Request Validation error or insufficient inventory
401 Unauthorized Missing or invalid token
409 Conflict Idempotency key already processed / Race condition detected

Reports

GET /api/reports/sales

Retrieve paginated sales data with optional date filtering.

Query Parameters:

Parameter Default Description
company_id 1 Company scope
start_date 30 days ago ISO date YYYY-MM-DD
end_date Today ISO date YYYY-MM-DD
limit 1000 Max 10000
offset 0 Pagination offset

Request:

curl "https://your-n8n.com/webhook/api/reports/sales?start_date=2026-01-01&end_date=2026-05-21&limit=50" \
  -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIs..."

Health

GET /api/health

Check the status of all infrastructure dependencies.

Request:

curl https://your-n8n.com/webhook/api/health

Response 200 OK:

{
  "status": "healthy",
  "timestamp": "2026-05-21T18:43:00.000Z",
  "services": {
    "database": { "status": "healthy" },
    "redis": { "status": "healthy" }
  }
}

πŸ”’ Security Patterns

This implementation applies defense-in-depth across multiple layers:

Request ──▢ Rate Limiting ──▢ Input Validation ──▢ JWT Verification ──▢ Idempotency ──▢ Business Logic
              (Redis)          (Regex + Type)       (Supabase)           (Redis SETNX)    (Parameterized SQL)
Layer Mechanism Details
Rate Limiting Redis INCR + EXPIRE 5 req/min per IP + User-Agent fingerprint
Input Validation Regex + type assertions Email format, numeric ranges, string sanitization
Authentication Supabase Auth JWT token validation via Supabase /auth/v1/user
Idempotency Redis SETNX Atomic set-if-not-exists with 24h TTL
SQL Injection Parameterized queries All queries use $1, $2, ... placeholders
XSS Prevention Input sanitization Strip < > ' " \ from user-supplied strings
Race Conditions SELECT ... FOR UPDATE Row-level locks during inventory checks
Timeouts 10s on all HTTP calls Prevents hanging connections
Error Logging Datadog integration All errors forwarded to centralized logging
CORS Environment-driven Access-Control-Allow-Origin set via FRONTEND_URL

🚒 Deployment

If you wanted to take this from reference implementation to actual production, here is how I'd approach scaling it.

Option 1 β€” Lightweight VPS (small teams)

Component Service Cost
Compute DigitalOcean Droplet ~$6/mo
Database Supabase (PostgreSQL + Auth) Free
Cache Redis (self-hosted) Included
Workflow n8n (self-hosted) Free

Option 2 β€” Fully Managed

Component Service Cost
Auth + Database Supabase Pro ~$25/mo
Cache Redis Cloud Free–$7/mo
Workflow n8n Cloud ~$20/mo

Option 3 β€” Kubernetes (Enterprise scale)

For 1,000+ concurrent users. PostgreSQL, Redis, and n8n would deploy as separate services behind an ingress controller with horizontal pod autoscaling.

Scaling Considerations

Users Auth Cache Workflow
10–100 Supabase Free Redis single n8n single
100–1,000 Supabase Pro Redis cluster n8n + load balancer
1,000+ Supabase Enterprise Redis Enterprise n8n on Kubernetes

πŸ“ Project Structure

enterprise-sales-api/
β”œβ”€β”€ enterprise-sales.json              # n8n workflow export
β”œβ”€β”€ Function.txt                       # PL/pgSQL stored function
β”œβ”€β”€ GUIA_CONFIGURACION_FUNCIONAL.md    # Setup guide (Spanish)
β”œβ”€β”€ LICENSE                            # MIT License
└── README.md                          # ← You are here

πŸ—ΊοΈ Possible Extensions

If I were to take this further, the natural next steps would be:

  • Two-factor authentication (TOTP via Supabase)
  • Webhook notifications on sale creation (Slack / WhatsApp Business)
  • PDF invoice generation with branded templates
  • Multi-currency support
  • Advanced analytics dashboard endpoint
  • OpenAPI / Swagger specification
  • Automated integration test suite

πŸ’¬ Feedback Welcome

This is a personal portfolio project. If you're reviewing it for hiring, collaboration, or just curiosity, I'm happy to walk through any architectural decision, trade-off, or extension idea. Open an issue or reach out directly.

πŸ“§ arturo66@gmail.com πŸ”— LinkedIn


πŸ“„ License

Released under the MIT License. See LICENSE for details.

Built by Arturo Ortega Salinas β€” Mexico City.

About

A production-grade, security-first Sales Management API built entirely on n8n workflows.

Resources

License

MIT, Unknown licenses found

Licenses found

MIT
LICENSE
Unknown
LICENSE.md

Stars

Watchers

Forks

Packages

 
 
 

Contributors