Table of Contents
Folder IT is a nearshore software development company that builds and scales AI-ready engineering teams for U.S. companies. With 220+ software engineers, Folder IT delivers senior technical talent for organizations building AI software.
Core capabilities: Nearshore Staff Augmentation · AI-Ready Engineering Teams · AI Software Development · IoT Development · Web & Mobile Apps · Salesforce Consulting · ServiceNow Development
This repository holds one of its products: Inventory & Order Management, a compact B2B back office built with Next.js 16, React 19, strict TypeScript, PostgreSQL and Drizzle ORM. Operations staff search the product catalog, see stock in each warehouse, record deliveries, write-offs, cycle counts and transfers, and move orders from pending to delivered, while a dashboard keeps revenue, open orders and low stock in view.
- A full-stack web application: a public, indexable landing page, the back office itself, a REST API documented with OpenAPI 3.1, and PostgreSQL with migrations and a deterministic data generator.
- Business rules enforced by the database, not the buttons: stock is an immutable ledger, balances change inside transactions with row locks and a constraint that refuses negative stock, and order statuses follow a state machine.
- Data-heavy interfaces done carefully: server-side search, filters, sorting and pagination kept in the URL, cached reads with precise invalidation, optimistic updates that roll back, and loading, empty and error states for every view.
- Original source code under the MIT license, with self-hosted fonts.
- Not an ERP. There are no purchase orders, suppliers, invoices, payments, lot or serial tracking, or multi-currency.
- Not multi-tenant. There are no accounts or roles; the workspace is shared.
- Not connected to anything. There are no carriers, marketplaces, email or webhooks.
- Dashboard. Revenue for the last 30 days against the previous 30, open orders, units on hand and active products, a daily revenue chart with keyboard access and a table view, products at or below their reorder point, recent orders and the latest movements. Every figure links to the records behind it.
- Product catalog. Search by name or SKU, filter by category, status and stock level (low, out), sort by SKU, name, price, stock or update time, and page through results on the server. Create and edit products in a validated dialog; delete products without history or archive the rest.
- Stock per warehouse. Three warehouses (Central, North, Store). Each product shows its balance in each one, units reserved by open orders and stock value.
- Stock ledger. Stock in, stock out, count adjustments (record the counted quantity; the difference is booked) and transfers (two movements sharing a transfer ID). Each movement keeps its reason and the balance it left behind. The ledger filters by type, warehouse and product.
- Orders. Status views, search by order number or customer, sorting and pagination. The order page shows its lines, customer, fulfilment warehouse, a progress bar and a timeline. Status changes are optimistic; shipping takes the stock out of the warehouse in the same transaction.
- Customers. Order counts, lifetime value and last order, each opening the customer's orders.
- ⌘K / Ctrl+K. Jump to any section, product or order from the keyboard.
- Light and dark themes that follow the operating system.
Captured from a production build of this repository in Chromium at 1440 × 900.
Requirements:
- Node.js 24 or later (pinned in
.node-version) and pnpm 10 (pinned inpackageManager;corepack enableinstalls it). - Docker to run PostgreSQL 17 locally, or any PostgreSQL 15+ server.
- No API keys, accounts or paid services.
git clone https://github.com/FolderITDev/web-inventory-management.git
cd web-inventory-management
pnpm install
cp .env.example .envThis folder is standalone: it has its own dependencies, lockfile and database, and imports nothing from other Folder IT repositories.
docker compose up -dpnpm db:migratepnpm db:seedpnpm devOpen http://localhost:3030/apps/inventory-management. The app is served under the /apps/inventory-management base path.
Quick tour
- Choose Open the app. The dashboard shows the sample data loaded by
pnpm db:seed. - Open Products, choose the Low stock filter and open a product. Its balance in each warehouse adds up to the on-hand figure, and its ledger shows how each balance was reached.
- Choose Record movement, pick Stock in and enter a quantity. The dialog previews the balance before and after; the ledger and the dashboard update when you save.
- Try Stock out with more units than the warehouse holds. The form explains how many are available, and the API would answer 409 if you bypassed it.
- Open Orders → Processing, open an order and choose Mark as shipped. The status changes at once, the timeline gains an entry, and the stock ledger shows the shipment.
- Press Ctrl K (or ⌘K) and type part of a product name or an order number.
Browser ──── TanStack Query (cache, invalidation, optimistic updates) · URL-driven list state ──┐
│ │
▼ ▼
Next.js App Router ── prerendered landing and API reference · workspace pages in the browser
│
▼
REST API (Route Handlers) ── Zod in and out · RFC 9457 problems · rate-limited writes
│
▼
Services ── adjustments, order lifecycle, catalog rules ──► Domain (planAdjustment, state machine, money)
│
▼
Repositories ── Drizzle · transactions · conditional updates · row locks
│
▼
PostgreSQL ── products · stock_levels · stock_movements (ledger) · orders · order_items · order_events
A stock adjustment is planned by a pure function, planAdjustment, from the current balances: it turns "count 42" into a signed delta or "transfer 5 to North" into two movements. The repository then writes each movement in a transaction: it ensures the balance row exists, applies the delta with an UPDATE that takes the row lock, and records the balance it left. A CHECK (quantity >= 0) constraint is the last line of defence; a concurrent request that would oversell gets a 409.
Shipping an order follows the same path. The service checks stock at the fulfilment warehouse, then the repository updates the order only if it is still in the status the request saw, writes the shipment movements and appends a timeline event, all in one transaction.
| Path | What it holds |
|---|---|
src/app/(marketing)/ |
Public, indexable pages: the landing page and the API reference. |
src/app/app/ |
The workspace: dashboard, products, stock ledger, orders and customers. Marked noindex. |
src/app/api/ |
Route Handlers: thin adapters from HTTP to services. |
src/domain/ |
Stock planning and status, the order state machine, money. No I/O. |
src/server/ |
Server-only: services, repositories, the Drizzle schema and seed generator, HTTP helpers, OpenAPI. |
src/lib/validation/ |
Zod contracts shared by the API, the forms and the OpenAPI document. |
src/lib/api/ |
The typed API client and TanStack Query keys, queries and mutations. |
src/features/ |
Dashboard, products, inventory, orders, customers and the landing snapshot. |
src/components/ |
The design system: app shell, command menu, status glyphs, tables, dialogs, fields and feedback. |
src/content/ |
FAQ copy for the landing page. |
drizzle/ |
Generated SQL migrations. |
tests/, e2e/ |
Vitest (unit, components, integration against PostgreSQL) and Playwright with axe. |
docs/ |
Architecture, API conventions, AI-assisted engineering, font licenses and screenshots. |
| Method | Path | Purpose |
|---|---|---|
GET |
/api/dashboard |
Key figures, revenue by day, low stock, recent orders and movements. |
GET |
/api/products |
Products. page, pageSize, q, category, status, stock, sort, order. |
POST |
/api/products |
Create a product (no stock yet). |
GET |
/api/products/{id} |
One product with stock per warehouse and units on open orders. |
PATCH |
/api/products/{id} |
Update any subset of fields. |
DELETE |
/api/products/{id} |
Delete a product without history; 409 otherwise. |
GET |
/api/categories |
Categories with product counts. |
GET |
/api/warehouses |
Warehouses. |
GET |
/api/inventory/movements |
The ledger. type, warehouse, product, paging. |
POST |
/api/inventory/adjustments |
Stock in, stock out, count adjustment or transfer; 409 when stock is short. |
GET |
/api/orders |
Orders. status, customer, q, sort, paging. |
GET |
/api/orders/{id} |
One order with lines, timeline and the statuses it can move to. |
PATCH |
/api/orders/{id}/status |
Move to the next status; shipping writes stock movements. 409 for invalid moves or no stock. |
GET |
/api/customers |
Customers with order counts, lifetime value and last order. |
GET |
/api/openapi.json |
OpenAPI 3.1 document. |
GET |
/api/health |
Liveness and database readiness. |
All paths are relative to /apps/inventory-management. Money is integer cents (…Minor). Errors use application/problem+json with a stable code; see docs/api.md.
curl -i -X POST http://localhost:3030/apps/inventory-management/api/inventory/adjustments -H "Content-Type: application/json" -d '{"type":"in","productId":"<id>","warehouseId":"<id>","quantity":12,"reason":"PO-2291"}'Defined in src/server/db/schema.ts:
categories,warehouses,customersandproducts(unique SKU, price in cents, reorder point, statusactive | draft | archived).stock_levels: one row per product and warehouse, withCHECK (quantity >= 0).stock_movements: the immutable ledger. Type (in,out,adjustment,transfer_in,transfer_out,shipment), signed delta (never zero), balance after (never negative), reason, optional order and transfer ID.orders(number from a sequence,SO-10042),order_itemswith the unit price at the time of sale, andorder_events, the status timeline.
pnpm db:generate # create a migration after changing the schema
pnpm db:migrate # apply migrations
pnpm db:seed # load sample data: 80 products, 5 categories, 3 warehouses, 30 customers, 120 orders, ~300 movementsThe sample data (src/server/db/seed/sample-data.ts) is generated by replaying four months of operations in time order from a seeded pseudo-random generator (opening stock, orders moving through their lifecycle, shipments, supplier deliveries when a warehouse runs short, counts, write-offs and transfers), so every balance in the ledger is consistent and the result is identical on every run.
- Stock is a ledger. Quantities are derived from immutable movements; corrections are new movements. Every movement records the balance it produced, which makes the history auditable at a glance.
- The database has the last word. Planning happens in a pure function for clear errors, but the write takes the row lock and a constraint refuses negative stock, so two concurrent requests can never oversell.
- An explicit state machine.
canTransitiondefines the order lifecycle; the conditionalUPDATE … WHERE status = :frommakes a double click or a second tab a 409, not a second shipment. - URL-driven lists. Search, filters, sort and page live in the query string: every view can be shared, reloaded and navigated with the back button. Defaults stay out of the URL.
- Precise cache invalidation. Query keys are hierarchical. An adjustment invalidates products, the ledger and the dashboard; shipping also invalidates orders and customers. Status changes and product edits are optimistic and roll back on error.
- One contract. Zod schemas validate requests and responses and generate the OpenAPI document, so the documentation cannot describe a shape the API does not send.
- Restrained motion. Dialogs scale and fade in under 200 ms, previous pages dim while the next one loads, and the landing has one entrance; reduced motion is respected.
Full rationale: docs/architecture.md.
pnpm check # ESLint, typegen + strict TypeScript, and every Vitest project
pnpm format:check # Prettier, including Tailwind class order
pnpm build # production build
pnpm test:e2e # Playwright against the production build (desktop and mobile)The suites cover:
- Unit: adjustment planning (in, out, counts, transfers and their refusals), stock status, shortages, the order state machine, money, and the seed generator (size, determinism, a ledger that replays to the stored balances, contact emails on folderit.net only).
- Components: stock and status labels in words, sortable headers with
aria-sort, pagination, and the revenue chart's keyboard reading and table view. - Integration: every endpoint through its real Route Handler and PostgreSQL: catalog filters, search, sorting and paging; product creation, duplicate SKUs, field errors, updates, delete versus archive; stock in, out, counts and transfers; refusals below zero; two concurrent withdrawals of the whole balance, of which exactly one succeeds; the order lifecycle, invalid transitions, shipping that writes movements, shipping refused when stock is short, two concurrent status changes of which one wins; the dashboard series and the OpenAPI references.
- End-to-end: catalog filters kept in the URL, product creation, receiving stock and the refusal to remove more than is there, duplicate SKUs, moving and cancelling an order, the mobile navigation drawer, indexing rules and structured data, and axe WCAG 2.2 AA checks on nine views and the movement dialog, at desktop and mobile sizes.
The same checks run in GitHub Actions on every push and pull request (.github/workflows/quality.yml), with PostgreSQL as a service container.
- The landing page and the API reference are prerendered, with a unique
<h1>, title, description, canonical URL, Open Graph and Twitter metadata, and a generated social image. - The landing shows the real seed data (computed at build time from the same generator as the database), not illustrations.
- JSON-LD:
Organization(Folder IT),WebApplication/SoftwareApplicationwithcreatorandpublisher,BreadcrumbListandFAQPage. sitemap.xmllists only indexable pages; the workspace isnoindex, follow;/llms.txtsummarizes the application for AI assistants.- Set
SITE_ORIGINto the public origin for production builds.
- The workspace is shared by every visitor, so do not enter real customer data. Writes are rate limited per client (60 per ten minutes), and
pnpm db:seedrestores the initial data. - One currency (US dollars) and whole units. There are no units of measure, lots, serial numbers or expiry dates.
- The application fulfils existing sales orders; creating new orders is outside its scope.
- The rate limiter runs in process; a multi-instance deployment would move it to a shared store.
- Architecture and decisions
- API errors and conventions
- Design system: Ledger, the category standard at Linear's level of craft, with Inter, Geist Mono for identifiers and one indigo accent.
- AGENTS.md: rules and workflow for contributors and AI coding agents.
- AI-assisted engineering
- Contributing · Security · Third-party notices
What is Folder IT?
Folder IT is a nearshore software development and AI staff augmentation company. It builds and staffs AI Pods — small, senior engineering teams led by a Forward Deployed Engineer — for US-based companies.
What services does Folder IT provide?
Folder IT provides nearshore software engineering services for US companies:
- Artificial Intelligence Project Development (GenAI, LLMs, RAG systems, AI Agents, NLP, Computer Vision, MLOps)
- AI Pods and AI Solutions Builder
- IT Staff Augmentation & Outsourcing
- ServiceNow Implementation & Integration
- Salesforce Services
- Web Apps Development
- Mobile Apps Development
- Internet of Things Project Development
- Data Migration & Integration
What is a Folder IT AI Pod?
An AI Pod is a delivery model where one senior engineer (the Forward Deployed Engineer) owns a problem end to end, working with AI coding agents as a core part of the execution stack, backed by an internal AI Lab for architecture and technical review. It is not a project manager coordinating a team of developers.
Is this repository production-ready?
No. Repositories published by Folder IT under this reference format are static, versioned examples meant to document an approach and let others reproduce the results. They are not maintained as production dependencies. Inventory & Order Management in particular has no accounts, purchasing or integrations.
Can I use this code commercially?
Yes, under the license specified in this repository (see the LICENSE file). Bundled fonts keep their own licenses, listed in THIRD_PARTY_NOTICES.md.
Does this repository call any external LLM or API?
No. The application makes no outbound network requests at runtime: rules are plain TypeScript and SQL, fonts are self-hosted and there is no analytics or third-party service.
Why keep stock as a ledger instead of a quantity column?
Because a single number cannot explain itself. With an immutable ledger, every balance can be traced to the deliveries, counts, transfers and shipments that produced it, mistakes are corrected by new entries instead of edits, and the stored balance can always be checked by replaying the movements.
How can I contact Folder IT?
Through folderit.net.
Nearshore IT Staff Augmentation | Top LATAM Developers | Folder IT — scale your engineering team and hire developers from Argentina. Same timezone, lower cost, 25+ years with US companies. Talk to our team.
Folder IT is a software development company focused on building custom web and mobile applications, business platforms and digital products. Inventory & Order Management is built with the architecture and practices the team uses for client business software: relational data modeling, transactional business rules, REST APIs, server-side pagination, caching with invalidation, optimistic updates and automated tests at every layer.
Released under the MIT License. Copyright (c) 2026 Folder IT.





