Skip to main content

Database Schema

The Sales Management System uses MySQL with a relational schema designed around sales, inventory, and client management.

Overview

The database consists of 7 main tables:
  • roles - User role definitions
  • users - System user accounts
  • categories - Product categorization
  • products - Inventory items
  • clients - Customer information
  • sales - Sales transactions
  • sale_details - Line items for each sale

Schema Diagram

Table Definitions

roles

Defines user roles for access control.
CREATE TABLE roles (
    id INT AUTO_INCREMENT PRIMARY KEY,
    name VARCHAR(50) NOT NULL UNIQUE
);

INSERT INTO roles (name) VALUES ('admin'), ('employee');
ColumnTypeConstraintsDescription
idINTPRIMARY KEY, AUTO_INCREMENTUnique role identifier
nameVARCHAR(50)NOT NULL, UNIQUERole name (admin, employee)

users

Stores system user accounts with role-based access.
CREATE TABLE users (
    id BINARY(16) PRIMARY KEY,
    name VARCHAR(100) NOT NULL,
    email VARCHAR(150) NOT NULL UNIQUE,
    password VARCHAR(255) NOT NULL,
    role_id INT NOT NULL,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    FOREIGN KEY (role_id) REFERENCES roles(id)
);
ColumnTypeConstraintsDescription
idBINARY(16)PRIMARY KEYUUID stored as binary
nameVARCHAR(100)NOT NULLUser’s full name
emailVARCHAR(150)NOT NULL, UNIQUEUser email address
passwordVARCHAR(255)NOT NULLHashed password
role_idINTNOT NULL, FOREIGN KEYReference to roles.id
created_atTIMESTAMPDEFAULT CURRENT_TIMESTAMPAccount creation time
updated_atTIMESTAMPAUTO UPDATELast modification time
User passwords should be hashed using bcrypt or similar before storage.

categories

Organizes products into categories.
CREATE TABLE categories (
    id INT AUTO_INCREMENT PRIMARY KEY,
    name VARCHAR(100) NOT NULL UNIQUE,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
ColumnTypeConstraintsDescription
idINTPRIMARY KEY, AUTO_INCREMENTUnique category identifier
nameVARCHAR(100)NOT NULL, UNIQUECategory name (min 3 chars)
created_atTIMESTAMPDEFAULT CURRENT_TIMESTAMPCreation timestamp
Example categories: bebidas, alfajores, galletas

products

Stores inventory items with pricing and stock information.
CREATE TABLE products (
    id BINARY(16) PRIMARY KEY,
    name VARCHAR(150) NOT NULL,
    description TEXT,
    price DECIMAL(10,2) NOT NULL,
    stock INT NOT NULL DEFAULT 0,
    category_id INT,
    is_deleted BOOLEAN DEFAULT FALSE,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    FOREIGN KEY (category_id) REFERENCES categories(id)
);
ColumnTypeConstraintsDescription
idBINARY(16)PRIMARY KEYUUID for product
nameVARCHAR(150)NOT NULLProduct name (min 3 chars)
descriptionTEXT-Detailed description (min 10 chars)
priceDECIMAL(10,2)NOT NULLPrice with 2 decimal places
stockINTNOT NULL, DEFAULT 0Available quantity
category_idINTFOREIGN KEYReference to categories.id
is_deletedBOOLEANDEFAULT FALSESoft delete flag
created_atTIMESTAMPDEFAULT CURRENT_TIMESTAMPCreation time
updated_atTIMESTAMPAUTO UPDATELast update time
Example:
{
  "id": "b6da7bbc-14b9-11f1-9fcd-2418c6c96a00",
  "name": "Coca cola",
  "description": "Bebida gasificada de 2ltr",
  "price": "3000.00",
  "stock": 40,
  "category_id": 1
}

clients

Stores customer information.
CREATE TABLE clients(
    id BINARY(16) PRIMARY KEY,
    name VARCHAR(100) NOT NULL,
    email VARCHAR(150) NOT NULL UNIQUE
);
ColumnTypeConstraintsDescription
idBINARY(16)PRIMARY KEYUUID for client
nameVARCHAR(100)NOT NULLClient’s full name
emailVARCHAR(150)NOT NULL, UNIQUEClient email address
Example:
{
  "id": "036c71c5-14e0-11f1-9fcd-2418c6c96a00",
  "name": "Mark Zuckemberg",
  "email": "markz@facebook.com"
}

sales

Records sales transactions.
CREATE TABLE sales (
    id BINARY(16) PRIMARY KEY,
    clients_id BINARY(16) NOT NULL,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    FOREIGN KEY (clients_id) REFERENCES clients(id)
);
ColumnTypeConstraintsDescription
idBINARY(16)PRIMARY KEYUUID for sale
clients_idBINARY(16)NOT NULL, FOREIGN KEYReference to clients.id
created_atTIMESTAMPDEFAULT CURRENT_TIMESTAMPSale timestamp
A sale cannot be deleted if the client has associated sales records. Handle client deletion carefully.

sale_details

Stores line items for each sale transaction.
CREATE TABLE sale_details (
    id BINARY(16) PRIMARY KEY,
    sale_id BINARY(16) NOT NULL,
    product_id BINARY(16) NOT NULL,
    quantity INT NOT NULL,
    FOREIGN KEY (sale_id) REFERENCES sales(id) ON DELETE CASCADE,
    FOREIGN KEY (product_id) REFERENCES products(id)
);
ColumnTypeConstraintsDescription
idBINARY(16)PRIMARY KEYUUID for sale detail
sale_idBINARY(16)NOT NULL, FOREIGN KEYReference to sales.id
product_idBINARY(16)NOT NULL, FOREIGN KEYReference to products.id
quantityINTNOT NULLQuantity sold
ON DELETE CASCADE ensures that when a sale is deleted, all its line items are automatically removed.

Relationships

One-to-Many Relationships

  1. roles → users: One role has many users
    • Enforced by: users.role_idroles.id
  2. categories → products: One category has many products
    • Enforced by: products.category_idcategories.id
    • Constraint: Cannot delete category if products exist with that category
  3. clients → sales: One client has many sales
    • Enforced by: sales.clients_idclients.id
    • Constraint: Cannot delete client if they have sales
  4. sales → sale_details: One sale has many line items
    • Enforced by: sale_details.sale_idsales.id
    • Cascade: Deleting a sale deletes all its details
  5. products → sale_details: One product appears in many sales
    • Enforced by: sale_details.product_idproducts.id
    • Constraint: Cannot delete product if it appears in sales

UUID Usage

The system uses BINARY(16) to store UUIDs efficiently:
  • Tables using UUIDs: users, clients, products, sales, sale_details
  • Tables using integers: roles, categories

Working with UUIDs

MySQL provides functions to convert between UUID strings and binary:
-- Convert UUID string to binary for INSERT
INSERT INTO clients (id, name, email) 
VALUES (UUID_TO_BIN('550e8400-e29b-41d4-a716-446655440000'), 'John', 'john@example.com');

-- Convert binary to UUID string for SELECT
SELECT BIN_TO_UUID(id) as id, name, email FROM clients;
The API handles UUID conversion automatically in model files (e.g., src/model/categorie.model.js:33).

Stock Management

When a sale is created:
  1. Product stock is validated (must have sufficient quantity)
  2. Stock is decremented by the quantity sold
  3. Transaction is recorded in sale_details
Example: Before sale:
{"stock": 40}
After selling 10 units:
{"stock": 30}

Soft Deletes

The products table uses a soft delete pattern:
  • is_deleted field marks products as deleted without removing them
  • Preserves referential integrity with existing sales
  • Products can be filtered in queries: WHERE is_deleted = FALSE

Indexes

Primary Keys (Automatically Indexed)

  • All id columns are indexed as primary keys

Unique Indexes

  • roles.name
  • users.email
  • categories.name
  • clients.email

Foreign Key Indexes (Automatically Created)

  • users.role_id
  • products.category_id
  • sales.clients_id
  • sale_details.sale_id
  • sale_details.product_id

Database Size Considerations

TableEstimated Size per Row
roles~60 bytes
users~500 bytes
categories~120 bytes
products~300 bytes
clients~270 bytes
sales~50 bytes
sale_details~50 bytes
Actual size varies based on data length. TEXT fields in products can significantly increase row size.

Next Steps

Architecture

Learn how the API interacts with the database

API Reference

See how to query and modify data

Error Handling

Handle foreign key constraint errors

Configuration

Configure database connection

Build docs developers (and LLMs) love