Skip to main content
/

Technical Track Record

Case 06: Unit Gestao – Vertical ERP for Bespoke Manufacturing

Note: Source code is private due to enterprise compliance and non-disclosure agreements. Detailed system architecture and DevOps documentation are available for review.
Next.js 14SupabasePostgres (Triggers/RPC)TypeScriptTailwind CSS

Briefing

Small manufacturing businesses and ateliers often struggle with fragmented processes and poor financial visibility. I designed and engineered this vertical ERP to centralize the entire operational lifecycle, from order capture and material management to production scheduling and financial close. The system transformed a manual, spreadsheet-driven operation into a structured, scalable digital workflow.

Technical Deep Dive

The architecture adopts a BaaS pattern with Supabase, where I implemented critical business logic directly in the database layer using Postgres Triggers and RPCs (Remote Procedure Calls) to guarantee atomicity in complex order transactions. Security is enforced through an RBAC strategy using RLS (Row Level Security), ensuring full isolation of financial data. For output, I built a server-side PDF rendering engine that generates executive reports and production orders in real time, ensuring document consistency on any device.

Production Control

Inventory & Order Desk

Inventory800+ SKUs
Stages12
On-time+35%
Errors-40%

Documentation

Unit Gestao Beab'atelie Web system for managing orders, scheduling, customers, products, finance, and PDF reports, with Supabase authentication and a Next.js (App Router) interface. Overview Application focused on an atelier's daily flow: customer and product registration, order creation with items, delivery scheduling, monthly financial control, configurable reminders, and PDF report generation. The entire data layer runs on Supabase (Postgres + Auth + Storage), with business rules implemented via triggers, views, and RPCs. Architecture

code
[Browser]
  |-- UI (Next.js App Router)
  |-- Server Components (fetchApi)
  |-- Client Components (fetchApiClient)
           |
        /api/* (Route Handlers)
           |
   Repositories (src/lib/repositories)
           |
Supabase (Postgres + Auth + Storage)

Tech Stack

ComponentTechnologyVersionNotes
FrameworkNext.js14.2.5App Router + Route Handlers
UIReact18.2.0Server/Client Components
LanguageTypeScript5.5.3Typing and validation
StylesTailwind CSS3.4.7Utility-first
Backend as a ServiceSupabase JS2.45.4Auth, Postgres, Storage
ValidationZod3.23.8Input schemas
PDF@react-pdf/renderer3.4.4Server-side reports
TestsVitest1.6.0Unit tests for utils

Core Modules

ModuleResponsibilityKey Files
OrdersCreate, edit, list, and attach images to orders, with items and paymentsrc/components/pedidos, src/app/api/pedidos, src/lib/repositories/pedidos
CustomersCustomer CRUDsrc/components/clientes, src/app/api/clientes, src/lib/repositories/clients
ProductsProduct CRUD and default pricingsrc/components/produtos, src/app/api/produtos, src/lib/repositories/produtos
ScheduleAggregate deliveries by datesrc/components/agenda, src/app/api/agenda, src/lib/agenda-utils
FinanceIncoming (payments) + outgoing (expenses) and monthly summarysrc/components/financeiro, src/app/api/financeiro, src/lib/finance-utils
RemindersPer-user configuration and upcoming delivery listsrc/components/lembretes, src/app/api/lembretes, src/lib/reminder-utils
ReportsPDF for orders, schedule, and financesrc/components/relatorios, src/app/api/relatorios, src/lib/reports/pdf
SettingsTheme and reminder preferencessrc/app/(app)/configuracoes, src/components/config

Technical Flows

  1. Order creation: the form accepts existing or new customers, existing or new items, calculates total and status (Open, Partial, Paid), sends to POST /api/pedidos and uses RPC create_order_with_items to persist order and items.
  2. Schedule: lists records from the agenda_entries view, aggregates by date via buildAgendaByDate, and renders by day and time range.
  3. Finance: income entries are read from the finance_order_entries view (paid > 0 and within period) and expenses from expenses, with summary calculated in buildFinanceSummary.
  4. Reminders: the backend builds a date window with parseDaysParam + getRangeForDays, queries agenda_entries, and returns filtered summary and items.
  5. PDF reports: route handlers generate PDFs via @react-pdf/renderer and return application/pdf in Node runtime.
  6. Automated message: GET /api/mensagens/pedido/:id builds a message with items, dates, and values for client delivery.
  7. Reference images: upload via POST /api/pedidos/:id/referencias, with type/size validation, stored in Storage and recorded in order_reference_images.

Authentication and Authorization

  • Login via POST /api/auth/login using Supabase Auth (password), returning HTTP-only cookies: sb-access-token, sb-refresh-token, sb-expires-at.
  • Middleware protects non-public routes and redirects to /login when the token is missing or expired.
  • fetchApi (server) injects Authorization: Bearer <token> from the cookie.
  • fetchApiClient (browser) uses cookies and attempts POST /api/auth/refresh on 401.
  • Roles in profiles: sys-admin, admin, user.
  • RLS applies permissions by role on tables and views; finance endpoints require the admin role.
  • In development, createSupabaseRouteClient can use SUPABASE_SERVICE_ROLE_KEY when there is no token, facilitating local testing.

Database

EntityKey fieldsNotes
clientsname, phone, notesRLS enabled
productsname, description, price_default, active, control_codecontrol_code generated by year
ordersclient_id, delivery_date, total, paid, status, control_codestatus via set_order_status trigger
order_itemsorder_id, product_id, quantity, unit_pricesubtotal calculated in DB
order_reference_imagesorder_id, storage_path, file_name, content_type, sizelinked to Storage
expensesdate, description, category, valueused in finance
reminder_settingsuser_id, days_before, notify_*per-user config
reminder_logsorder_id, user_id, reminder_date, channelsend logs
profilesid, roleuser role

Rules and automations

  • set_order_status: defines status based on paid and total.
  • set_paid_date: fills paid_date when payment exists.
  • next_*_control_code: generates yearly sequences for orders and products.
  • agenda_entries: schedule view aggregating customers, products, and dates.
  • finance_order_entries: view for financial income entries.

Storage

  • Public bucket order-references for order-linked images.

API Response format

json
{ "data": { ... } }

Error

json
{ "error": { "message": "...", "details": ... } }

Auth

MethodRouteDescription
POST/api/auth/loginLogin and set cookies
POST/api/auth/logoutClear cookies
POST/api/auth/refreshRefresh session
GET/api/auth/meReturn user and role

Orders and images

MethodRouteDescription
GET/api/pedidosList orders (filters: delivery_date, client_id)
POST/api/pedidosCreate order with items
GET/api/pedidos/:idOrder detail
PATCH/api/pedidos/:idUpdate order and items
DELETE/api/pedidos/:idRemove order
POST/api/pedidos/:id/referenciasUpload images (multipart)
DELETE/api/pedidos/:id/referencias/:imageIdRemove image

Customers and products

MethodRouteDescription
GET/api/clientesList customers
POST/api/clientesCreate customer
GET/api/clientes/:idCustomer detail
PATCH/api/clientes/:idUpdate customer
DELETE/api/clientes/:idRemove customer
GET/api/produtosList products
POST/api/produtosCreate product
GET/api/produtos/:idProduct detail
PATCH/api/produtos/:idUpdate product
DELETE/api/produtos/:idRemove product

Schedule and reminders

MethodRouteDescription
GET/api/agendaSchedule by period (start_date, end_date, status, client_id)
GET/api/lembretesReminders by period (days, base_date, status, client_id)
GET/api/lembretes/configRead user settings
PATCH/api/lembretes/configUpdate user settings
POST/api/lembretes/logsRegister send log

Finance

MethodRouteDescription
GET/api/financeiroMonthly summary (admin)
GET/api/financeiro/saidasList expenses (admin)
POST/api/financeiro/saidasCreate expense (admin)

PDF reports

MethodRouteDescription
GET/api/relatorios/pedidosOrder PDF (month, status, client_id)
GET/api/relatorios/agendaSchedule PDF (month, `format=calendarlist`)
GET/api/relatorios/financeiroFinance PDF (month, `detail=summaryfull`)

Messages

MethodRouteDescription
GET/api/mensagens/pedido/:idAutomated message for customer

PDF Reports

  • Server-side rendering via @react-pdf/renderer.
  • src/lib/reports/pdf.tsx centralizes templates for orders, schedule, and finance.
  • Runtime configured as nodejs for report routes.
  • Custom fonts in public/fonts.

Reference Images

  • Allowed types: image/jpeg, image/png, image/webp, image/gif, image/avif.
  • Max size: 5MB per file.
  • Uploads use the admin client for Storage writes and metadata insertion.

Configuration Required environment variables

VariableUse
NEXT_PUBLIC_SUPABASE_URLSupabase project URL
NEXT_PUBLIC_SUPABASE_ANON_KEYAnonymous key for clients
SUPABASE_SERVICE_ROLE_KEYService role for admin operations

Optional variables (cookies)

VariableUse
AUTH_COOKIE_DOMAINCookie domain
AUTH_COOKIE_SAMESITElax, strict, or none
AUTH_COOKIE_SECUREtrue or false

Supabase local

  • npm run supabase:start starts services; npm run supabase:seed applies seeds and reset.

Scripts

  • npm run dev: development environment.
  • npm run build: production build.
  • npm run start: production Next server.
  • npm run lint: lint.
  • npm run test: vitest.
  • npm run supabase:start: start local Supabase.
  • npm run supabase:stop: stop local Supabase.
  • npm run supabase:reset: reset local database.
  • npm run supabase:seed: reset with seed.

Structure

code
src/
  app/               App Router routes and APIs
  components/        UI and domain modules
  lib/               business rules, repositories, and utils
supabase/
  deployed/          applied SQL migrations
  seed.sql           local seed
public/
  fonts/             fonts used in PDFs
tests/               unit tests (vitest)

Observability

  • logError writes console.error with scope, message, and context (ignoring tests); APIs return standardized messages with fail().

Security

  • HTTP-only session cookies with SameSite and Secure configuration; middleware blocks access without a valid session.
  • RLS enabled on core tables; image upload validates type and size before persisting.

Deploy

  1. Configure Supabase environment variables.
  2. npm run build to generate the build.
  3. npm run start to serve.
  4. Ensure Node runtime for report routes (/api/relatorios/*).

Common Issues

  • 401 accessing routes: session expired or missing cookies.
  • 403 on finance: user without admin or sys-admin role.
  • Empty PDFs: missing fonts in public/fonts or non-Node runtime.
  • Upload errors: unsupported type or file > 5MB.