Inventory System is a production-ready, multi-tenant SaaS application built for businesses that need to manage their stock, sales pipeline, and purchasing operations in one place. Each company that signs up gets its own isolated workspace — with its own products, users, categories, and transaction history — all living in the same Neon Postgres database, separated at the data layer by a strictDocumentation Index
Fetch the complete documentation index at: https://mintlify.com/juadariasmar/inventory_project/llms.txt
Use this file to discover all available pages before exploring further.
empresaId tenant boundary. Whether you are a small retailer tracking shelf stock or a mid-size distributor coordinating purchase orders across multiple suppliers, Inventory System gives every team member the right level of access to keep operations moving.
Architecture Overview
Inventory System is built on a modern, serverless-first stack designed to scale on Vercel without managing infrastructure. Next.js App Router drives both the UI and the REST API. Every page is a React Server Component by default, with client components used only where interactivity is required. API routes undersrc/app/api/ handle all data mutations and follow a consistent pattern: parse the request body with Zod, resolve the authenticated session, enforce tenant isolation by scoping every query to empresaId, and return a typed JSON response.
Multi-tenant data model — each company is represented by an Empresa record. When a new user completes sign-up, the system automatically creates an Empresa for them and links their Usuario record to it via empresaId. Every subsequent database query in the application is filtered by this ID, so one company can never read or write another company’s data.
Neon Auth replaces NextAuth entirely. Authentication is handled by @neondatabase/auth, which provides session management, sign-in/sign-up flows, and webhook-based user sync. The middleware at src/middleware.ts uses auth.middleware() to protect all application routes, redirecting unauthenticated visitors to /auth/sign-in. Public routes (/auth/*, /invitacion) are excluded from the matcher.
Prisma 5 + Neon Postgres — the Prisma client is configured with the driverAdapters preview feature and uses @prisma/adapter-neon with a WebSocket pool for production. This allows Prisma to run efficiently inside Vercel’s serverless environment without saturating the Postgres connection limit. Migrations are applied with the direct (unpooled) connection string; the pooled connection is used at runtime.
Upstash Redis rate limiting — src/middleware.ts applies a sliding-window rate limit (5 requests per minute per IP) to all mutating POST endpoints using @upstash/ratelimit. When Upstash credentials are not configured the middleware transparently falls back to an in-memory Map, which is sufficient for local development and single-instance deployments.
Key Capabilities
Products
Create, update, and categorize products with auto-generated SKU codes, stock levels, minimum stock thresholds, and a full price-change history log.
Inventory Movements
Record manual stock entries and exits, or let movements be generated automatically when sales are confirmed or purchase orders are received.
Sales & Quotes
Create quotes that soft-reserve stock until an expiry date, then convert them to confirmed sales in one click. Full cancellation workflow included.
Purchase Orders
Draft purchase orders against any configured supplier, then mark them as received to automatically post the corresponding stock-entry movements.
Analytics
Sales trends, top-selling products, low-stock alerts, slow-moving inventory reports, and revenue breakdowns — all scoped to the current company.
Notifications
In-app notifications for low stock, critical stock, expiring quotes, accepted invitations, and new user registrations — delivered per user or company-wide.
Data Model Summary
The following table lists the core Prisma models and their role in the system. Every model that stores business data carries anempresaId foreign key to enforce tenant isolation.
| Model | Description |
|---|---|
Empresa | Represents a tenant company. Root of the multi-tenant hierarchy; all other models cascade-delete when an Empresa is deleted. |
Usuario | An authenticated user linked to exactly one Empresa. Carries a Rol, a list of fine-grained Permiso[], and an EstadoUsuario (PENDIENTE / ACTIVO / SUSPENDIDO). |
Producto | A stockable item belonging to a Categoria. Tracks current cantidad, stockMinimo, and precio. |
Categoria | Groups products within a company. Each category has a short prefijo used to generate product codes. |
Movimiento | A single stock entry (entrada) or exit (salida) event. May be linked to a Venta or an OrdenCompra. |
Venta | A confirmed sale composed of ItemVenta line items. Automatically posts salida movements on creation. |
Cotizacion | A quote with a validity date that reserves stock. Can be converted to a Venta or cancelled. |
OrdenCompra | A purchase order sent to a Proveedor. Receiving it posts entrada movements for each line item. |
Proveedor | A supplier linked to one or more OrdenCompra records within a company. |
Cliente | A customer record that can be associated with sales and quotes. |
Auditoria | Immutable audit log recording every create, update, delete, login, and failed-login event with before/after JSON snapshots. |
HistorialPrecio | Tracks every price change on a Producto, recording the previous and new price, the timestamp, and the user who made the change. |
HistorialMovimientos | Secondary audit trail scoped to stock-movement events, storing before/after JSON snapshots of the affected product record. |
Notificacion | In-app notification delivered to a user or company-wide, covering low stock, expiring quotes, invitation acceptance, and new user registrations. |
Invitacion | A token-based invitation sent to an email address to join a specific Empresa with a pre-assigned role. |
ConfiguracionEmpresa | Per-company settings such as currency, tax rate, logo URL, and contact details. One record per Empresa. |
Roles and Permissions
Inventory System uses a two-layer authorization model: a broad role that controls administrative capabilities, and a granular permissions list (Permiso[]) that controls individual feature access within that role.
| Role | Description |
|---|---|
SUPER_ADMIN | Platform-level administrator. Automatically assigned to the email address in SUPER_ADMIN_EMAIL. Can manage all companies and users across the platform. |
ADMIN | Company-level administrator. Can approve or suspend users, manage categories, invite new team members, and access all features of their own company. |
USUARIO | Standard operator. Access is restricted to the permissions explicitly granted by an ADMIN — for example, REGISTRAR_MOVIMIENTOS, REALIZAR_VENTAS, VER_ANALISIS, or EXPORTAR_REPORTES. |
Users who sign up independently (without an invitation) are automatically created with role
ADMIN and status ACTIVO, giving them immediate access to their own company workspace. Users invited by an existing ADMIN receive the role and status specified in the invitation, and may start with status PENDIENTE until the admin approves them.Tech Stack
| Layer | Technology |
|---|---|
| Framework | Next.js 16 (App Router) |
| Language | TypeScript 5 |
| UI | React 19, Radix UI, Tailwind CSS 4, Lucide React |
| ORM | Prisma 5 with @prisma/adapter-neon |
| Database | Neon Serverless Postgres |
| Authentication | Neon Auth (@neondatabase/auth) |
| Rate Limiting | Upstash Redis (@upstash/ratelimit) |
| Charts | Recharts 3 |
| Resend via Nodemailer | |
| Export | ExcelJS, pdf-lib |
| Testing | Jest 30, Playwright |
| Deployment | Vercel |