Files

26 KiB
Raw Permalink Blame History

ERP MVP

Интегрированный monorepo ERP MVP v1 для демонстрации базового операционного цикла: справочники, закупки, продажи, складские движения, PDF-заглушки документов, dashboard и demo data.

Структура

erp-mvp/
  backend/
  frontend/
  .env.example
  docker-compose.yml
  README.md

Запуск

Опционально можно скопировать пример переменных окружения:

cp .env.example .env

Для production обязательно замените JWT_SECRET, пароли PostgreSQL и dev credentials.

docker compose up --build

После запуска:

Backend

Backend использует переменные окружения для подключения к PostgreSQL:

  • POSTGRES_DB
  • POSTGRES_USER
  • POSTGRES_PASSWORD
  • SPRING_DATASOURCE_URL
  • SPRING_DATASOURCE_USERNAME
  • SPRING_DATASOURCE_PASSWORD
  • CORS_ALLOWED_ORIGINS
  • JWT_SECRET
  • JWT_EXPIRATION_MINUTES
  • ADMIN_EMAIL
  • ADMIN_PASSWORD
  • DEMO_DATA_ENABLED

По умолчанию frontend разрешен с http://localhost:5173.

Backend Foundation

Backend содержит базовую инфраструктуру для дальнейшей разработки ERP-модулей:

  • расширяемую package structure с common, config, health и заготовками modules;
  • единый API response envelope;
  • global exception handler;
  • базовые custom exceptions;
  • pagination DTO;
  • JPA auditing foundation через BaseEntity;
  • OpenAPI / Swagger UI;
  • Flyway migrations для системной инициализации.

Auth + Roles

Backend содержит stateless JWT authentication foundation:

  • таблица app_users;
  • роли ADMIN, MANAGER, WAREHOUSE, FINANCE;
  • BCrypt password hashing;
  • seed admin user через Spring Boot initializer;
  • JWT Bearer auth для защищенных /api/** endpoint-ов;
  • Swagger Bearer JWT authorization scheme.

Dev credentials по умолчанию:

  • Email: admin@erp.local
  • Password: admin12345

Значения можно переопределить через переменные окружения:

  • ADMIN_EMAIL
  • ADMIN_PASSWORD
  • JWT_SECRET
  • JWT_EXPIRATION_MINUTES

API Response Format

Успешный ответ:

{
  "success": true,
  "data": {},
  "error": null,
  "timestamp": "2026-05-14T10:00:00Z"
}

Ответ с ошибкой:

{
  "success": false,
  "data": null,
  "error": {
    "code": "VALIDATION_ERROR",
    "message": "Validation failed",
    "details": []
  },
  "timestamp": "2026-05-14T10:00:00Z"
}

API URLs

Auth Endpoints

  • POST /api/auth/login
  • GET /api/auth/me
  • POST /api/auth/logout
  • GET /api/auth/protected-test

Login:

curl -X POST "http://localhost:8080/api/auth/login" \
  -H "Content-Type: application/json" \
  -d '{"email":"admin@erp.local","password":"admin12345"}'

Protected endpoint with JWT:

TOKEN="<paste-access-token>"

curl "http://localhost:8080/api/auth/protected-test" \
  -H "Authorization: Bearer $TOKEN"

Catalog Module

Catalog module содержит базовые ERP-справочники без закупок, заказов, остатков и документов:

  • Products / SKU
  • Suppliers
  • B2B Customers
  • Warehouses

Backend endpoints:

  • GET /api/catalog/products
  • GET /api/catalog/products/{id}
  • POST /api/catalog/products
  • PUT /api/catalog/products/{id}
  • DELETE /api/catalog/products/{id}
  • GET /api/catalog/suppliers
  • GET /api/catalog/suppliers/{id}
  • POST /api/catalog/suppliers
  • PUT /api/catalog/suppliers/{id}
  • DELETE /api/catalog/suppliers/{id}
  • GET /api/catalog/customers
  • GET /api/catalog/customers/{id}
  • POST /api/catalog/customers
  • PUT /api/catalog/customers/{id}
  • DELETE /api/catalog/customers/{id}
  • GET /api/catalog/warehouses
  • GET /api/catalog/warehouses/{id}
  • POST /api/catalog/warehouses
  • PUT /api/catalog/warehouses/{id}
  • DELETE /api/catalog/warehouses/{id}

List endpoints support:

?page=0&size=20&search=&active=true

Role access:

  • GET: any authenticated user.
  • POST, PUT, DELETE: ADMIN and MANAGER.
  • DELETE performs soft delete by setting active=false.

Frontend URLs:

Create product example:

LOGIN_RESPONSE=$(curl -s -X POST "http://localhost:8080/api/auth/login" \
  -H "Content-Type: application/json" \
  -d '{"email":"admin@erp.local","password":"admin12345"}')

TOKEN=$(echo "$LOGIN_RESPONSE" | jq -r '.data.accessToken')

curl -X POST "http://localhost:8080/api/catalog/products" \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $TOKEN" \
  -d '{
    "sku": "SKU-001",
    "name": "Demo product",
    "category": "General",
    "unit": "pcs",
    "barcode": "1234567890",
    "description": "Demo catalog item"
  }'

Procurement Module

Procurement module содержит простой процесс закупок без продаж, документов и оплат:

  • purchase order header;
  • supplier from Catalog;
  • optional receiving warehouse from Catalog;
  • product items from Catalog;
  • quantity, unit price, line total;
  • status flow and status history.
  • stock receipt when ORDERED moves to RECEIVED.

Backend endpoints:

  • GET /api/procurement/purchase-orders
  • GET /api/procurement/purchase-orders/{id}
  • POST /api/procurement/purchase-orders
  • PUT /api/procurement/purchase-orders/{id}
  • PATCH /api/procurement/purchase-orders/{id}/status
  • GET /api/procurement/purchase-orders/{id}/status-history
  • DELETE /api/procurement/purchase-orders/{id}

List endpoint supports:

?page=0&size=20&search=&status=DRAFT&supplierId=&fromDate=&toDate=

Statuses:

  • DRAFT
  • APPROVED
  • ORDERED
  • RECEIVED
  • CANCELLED

Allowed transitions:

  • DRAFT to APPROVED
  • APPROVED to ORDERED
  • ORDERED to RECEIVED
  • DRAFT to CANCELLED
  • APPROVED to CANCELLED
  • ORDERED to CANCELLED

Role access:

  • Read: ADMIN, MANAGER, WAREHOUSE, FINANCE.
  • Create/update/cancel: ADMIN, MANAGER.
  • Mark received: ADMIN, MANAGER, WAREHOUSE.
  • FINANCE can only read.

Frontend URLs:

Create purchase order example:

LOGIN_RESPONSE=$(curl -s -X POST "http://localhost:8080/api/auth/login" \
  -H "Content-Type: application/json" \
  -d '{"email":"admin@erp.local","password":"admin12345"}')

TOKEN=$(echo "$LOGIN_RESPONSE" | jq -r '.data.accessToken')

# Create an active supplier, warehouse, and product first in Catalog, then use their ids below.
SUPPLIER_ID="<supplier-id>"
WAREHOUSE_ID="<warehouse-id>"
PRODUCT_ID="<product-id>"

CREATE_PO_RESPONSE=$(curl -s -X POST "http://localhost:8080/api/procurement/purchase-orders" \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $TOKEN" \
  -d "{
    \"supplierId\": \"$SUPPLIER_ID\",
    \"warehouseId\": \"$WAREHOUSE_ID\",
    \"expectedDeliveryDate\": \"2026-06-01\",
    \"notes\": \"Initial procurement request\",
    \"items\": [
      {
        \"productId\": \"$PRODUCT_ID\",
        \"quantity\": 10,
        \"unitPrice\": 1250.00
      }
    ]
  }")

PO_ID=$(echo "$CREATE_PO_RESPONSE" | jq -r '.data.id')

curl -X PATCH "http://localhost:8080/api/procurement/purchase-orders/$PO_ID/status" \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $TOKEN" \
  -d '{"status":"APPROVED","comment":"Approved for ordering"}'

Sales Module

Sales module содержит простой B2B customer order process без документов, оплат и внешних интеграций:

  • customer order header;
  • customer from Catalog;
  • optional warehouse from Catalog;
  • product items from Catalog;
  • quantity, unit price, line total;
  • status flow and status history.
  • stock issue when IN_PROGRESS moves to SHIPPED.

Backend endpoints:

  • GET /api/sales/customer-orders
  • GET /api/sales/customer-orders/{id}
  • POST /api/sales/customer-orders
  • PUT /api/sales/customer-orders/{id}
  • PATCH /api/sales/customer-orders/{id}/status
  • GET /api/sales/customer-orders/{id}/status-history
  • DELETE /api/sales/customer-orders/{id}

List endpoint supports:

?page=0&size=20&search=&status=NEW&customerId=&warehouseId=&fromDate=&toDate=

Statuses:

  • NEW
  • CONFIRMED
  • IN_PROGRESS
  • SHIPPED
  • CLOSED
  • CANCELLED

Allowed transitions:

  • NEW to CONFIRMED
  • CONFIRMED to IN_PROGRESS
  • IN_PROGRESS to SHIPPED
  • SHIPPED to CLOSED
  • NEW to CANCELLED
  • CONFIRMED to CANCELLED
  • IN_PROGRESS to CANCELLED

Role access:

  • Read: ADMIN, MANAGER, WAREHOUSE, FINANCE.
  • Create/update/cancel: ADMIN, MANAGER.
  • Status changes: ADMIN, MANAGER.
  • Warehouse status changes: CONFIRMED to IN_PROGRESS, IN_PROGRESS to SHIPPED.
  • FINANCE can only read.

Frontend URLs:

Create customer order example:

LOGIN_RESPONSE=$(curl -s -X POST "http://localhost:8080/api/auth/login" \
  -H "Content-Type: application/json" \
  -d '{"email":"admin@erp.local","password":"admin12345"}')

TOKEN=$(echo "$LOGIN_RESPONSE" | jq -r '.data.accessToken')

# Create an active customer and product first in Catalog, then use their ids below.
# WAREHOUSE_ID is optional.
CUSTOMER_ID="<customer-id>"
PRODUCT_ID="<product-id>"
WAREHOUSE_ID="<warehouse-id>"

CREATE_ORDER_RESPONSE=$(curl -s -X POST "http://localhost:8080/api/sales/customer-orders" \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $TOKEN" \
  -d "{
    \"customerId\": \"$CUSTOMER_ID\",
    \"warehouseId\": \"$WAREHOUSE_ID\",
    \"requestedDeliveryDate\": \"2026-06-10\",
    \"notes\": \"Initial B2B order\",
    \"items\": [
      {
        \"productId\": \"$PRODUCT_ID\",
        \"quantity\": 5,
        \"unitPrice\": 1800.00
      }
    ]
  }")

ORDER_ID=$(echo "$CREATE_ORDER_RESPONSE" | jq -r '.data.id')

curl -X PATCH "http://localhost:8080/api/sales/customer-orders/$ORDER_ID/status" \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $TOKEN" \
  -d '{"status":"CONFIRMED","comment":"Confirmed with customer"}'

Warehouse Module

Warehouse module содержит складские остатки и историю движений без документов, оплат и внешних интеграций:

  • stock balance by warehouse and product;
  • stock movement history;
  • inbound movement when purchase order becomes RECEIVED;
  • outbound movement when customer order becomes SHIPPED;
  • manual stock adjustments;
  • insufficient stock check before shipping.

Backend endpoints:

  • GET /api/warehouse/stock-balances
  • GET /api/warehouse/stock-movements
  • POST /api/warehouse/stock-adjustments

Stock balances list supports:

?page=0&size=20&warehouseId=&productId=&search=

Stock movements list supports:

?page=0&size=20&warehouseId=&productId=&movementType=INBOUND&sourceType=PURCHASE_ORDER&sourceId=&fromDate=&toDate=

Movement types:

  • INBOUND
  • OUTBOUND
  • ADJUSTMENT_IN
  • ADJUSTMENT_OUT

Source types:

  • PURCHASE_ORDER
  • CUSTOMER_ORDER
  • MANUAL_ADJUSTMENT

Business rules:

  • PurchaseOrder must have warehouseId before marking it as RECEIVED.
  • RECEIVED creates INBOUND stock movement per PO item and increases stock.
  • CustomerOrder must have warehouseId before marking it as SHIPPED.
  • SHIPPED creates OUTBOUND stock movement per SO item and decreases stock.
  • Shipping is blocked if stock balance does not exist or quantity is insufficient.
  • Manual ADJUSTMENT_OUT is blocked if it would make stock negative.

Role access:

  • Read stock balances/movements: ADMIN, MANAGER, WAREHOUSE, FINANCE.
  • Manual stock adjustment: ADMIN, WAREHOUSE.
  • PO receipt: ADMIN, MANAGER, WAREHOUSE.
  • SO shipment: ADMIN, MANAGER, WAREHOUSE.
  • FINANCE is read-only.

Frontend URLs:

Manual adjustment example:

LOGIN_RESPONSE=$(curl -s -X POST "http://localhost:8080/api/auth/login" \
  -H "Content-Type: application/json" \
  -d '{"email":"admin@erp.local","password":"admin12345"}')

TOKEN=$(echo "$LOGIN_RESPONSE" | jq -r '.data.accessToken')

WAREHOUSE_ID="<warehouse-id>"
PRODUCT_ID="<product-id>"

curl -X POST "http://localhost:8080/api/warehouse/stock-adjustments" \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $TOKEN" \
  -d "{
    \"warehouseId\": \"$WAREHOUSE_ID\",
    \"productId\": \"$PRODUCT_ID\",
    \"type\": \"ADJUSTMENT_IN\",
    \"quantity\": 25.000,
    \"comment\": \"Opening stock balance\"
  }"

Mark PO as received:

curl -X PATCH "http://localhost:8080/api/procurement/purchase-orders/$PO_ID/status" \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $TOKEN" \
  -d '{"status":"RECEIVED","comment":"Received into warehouse"}'

Mark SO as shipped:

curl -X PATCH "http://localhost:8080/api/sales/customer-orders/$ORDER_ID/status" \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $TOKEN" \
  -d '{"status":"SHIPPED","comment":"Shipped from warehouse"}'

Documents Module

Documents module генерирует простые PDF placeholders для customer orders без email, подписей, оплат и внешних сервисов.

Document types:

  • INVOICE
  • CONTRACT
  • DELIVERY_NOTE

Backend endpoints:

  • GET /api/documents
  • GET /api/documents/{id}
  • GET /api/documents/customer-orders/{customerOrderId}
  • POST /api/documents/customer-orders/{customerOrderId}/generate
  • GET /api/documents/{id}/download

List endpoint supports:

?page=0&size=20&documentType=INVOICE&sourceType=CUSTOMER_ORDER&sourceId=&status=GENERATED&fromDate=&toDate=

Business rules:

  • Customer order must exist.
  • Documents cannot be generated for CANCELLED customer orders.
  • DELIVERY_NOTE can be generated only for SHIPPED or CLOSED orders.
  • INVOICE and CONTRACT can be generated for any status except CANCELLED.
  • Regenerating the same document type for the same customer order updates the existing PDF and keeps the document number.

Role access:

  • Read/list/download: ADMIN, MANAGER, WAREHOUSE, FINANCE.
  • Generate INVOICE and CONTRACT: ADMIN, MANAGER, FINANCE.
  • Generate DELIVERY_NOTE: ADMIN, MANAGER, WAREHOUSE.

Frontend URLs:

Generate invoice example:

LOGIN_RESPONSE=$(curl -s -X POST "http://localhost:8080/api/auth/login" \
  -H "Content-Type: application/json" \
  -d '{"email":"admin@erp.local","password":"admin12345"}')

TOKEN=$(echo "$LOGIN_RESPONSE" | jq -r '.data.accessToken')
CUSTOMER_ORDER_ID="<customer-order-id>"

GENERATE_DOCUMENT_RESPONSE=$(curl -s -X POST "http://localhost:8080/api/documents/customer-orders/$CUSTOMER_ORDER_ID/generate" \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $TOKEN" \
  -d '{"documentType":"INVOICE"}')

DOCUMENT_ID=$(echo "$GENERATE_DOCUMENT_RESPONSE" | jq -r '.data.id')

Download PDF example:

curl -L "http://localhost:8080/api/documents/$DOCUMENT_ID/download" \
  -H "Authorization: Bearer $TOKEN" \
  -o invoice-placeholder.pdf

Dashboard / Analytics

Dashboard module содержит read-only ERP analytics для руководителя без Power BI, внешней BI-системы и изменения бизнес-логики.

Backend endpoints:

  • GET /api/dashboard/summary
  • GET /api/dashboard/sales
  • GET /api/dashboard/procurement
  • GET /api/dashboard/warehouse
  • GET /api/dashboard/recent-activities
  • GET /api/dashboard/low-stock

Metrics included:

  • catalog counts: products, active products, suppliers, customers, warehouses;
  • sales: customer order counts, active orders, total sales amount, status breakdown, daily sales, top customers;
  • procurement: purchase order counts, active orders, total procurement amount, status breakdown, daily procurement, top suppliers;
  • warehouse: stock items, quantity on hand, low stock, movements, stock by warehouse, movements by type;
  • documents: total generated documents and documents by type;
  • recent activities across customer orders, purchase orders, stock movements, and documents.

Query examples:

GET /api/dashboard/sales?fromDate=2026-05-01&toDate=2026-05-31
GET /api/dashboard/procurement?fromDate=2026-05-01&toDate=2026-05-31
GET /api/dashboard/recent-activities?limit=20
GET /api/dashboard/low-stock?threshold=10&page=0&size=20

Role access:

  • ADMIN
  • MANAGER
  • WAREHOUSE
  • FINANCE

Frontend URL:

Dashboard sections:

  • KPI cards
  • Sales by Status
  • Procurement by Status
  • Warehouse Overview
  • Low Stock Items
  • Recent Activities

Summary curl example:

LOGIN_RESPONSE=$(curl -s -X POST "http://localhost:8080/api/auth/login" \
  -H "Content-Type: application/json" \
  -d '{"email":"admin@erp.local","password":"admin12345"}')

TOKEN=$(echo "$LOGIN_RESPONSE" | jq -r '.data.accessToken')

curl "http://localhost:8080/api/dashboard/summary" \
  -H "Authorization: Bearer $TOKEN"

Low stock curl example:

curl "http://localhost:8080/api/dashboard/low-stock?threshold=10&page=0&size=20" \
  -H "Authorization: Bearer $TOKEN"

Demo Data

Demo seed заполняет dev/demo окружение тестовыми данными для демонстрации ERP без ручной подготовки справочников, заказов, остатков и документов.

Seed выключен по умолчанию:

app:
  demo-data:
    enabled: ${DEMO_DATA_ENABLED:false}

Включить можно через env:

DEMO_DATA_ENABLED=true

В dev docker-compose.yml для backend уже задано:

DEMO_DATA_ENABLED: ${DEMO_DATA_ENABLED:-true}

Demo users:

  • admin@erp.local / admin12345 / ADMIN
  • manager@erp.local / manager12345 / MANAGER
  • warehouse@erp.local / warehouse12345 / WAREHOUSE
  • finance@erp.local / finance12345 / FINANCE

Seeded data:

  • catalog: 8 products, 3 suppliers, 3 customers, 2 warehouses;
  • procurement: 3 purchase orders, including one RECEIVED order that creates inbound stock movements;
  • sales: 4 customer orders, including one SHIPPED order that creates outbound stock movements;
  • warehouse: manual low-stock adjustments for Water 0.5L and Apple Juice 1L;
  • documents: invoice, contract and delivery note for shipped order; invoice and contract for confirmed order.

Idempotency:

  • users are matched by email;
  • products by SKU;
  • warehouses by code;
  • suppliers/customers by BIN or company name;
  • purchase/customer orders by DEMO-SEED-* marker in notes;
  • manual stock movements by source, warehouse, product and comment;
  • documents reuse the existing unique (sourceType, sourceId, documentType) row.

How to verify:

  1. Run docker compose up --build.
  2. Open http://localhost:5173/login.
  3. Use any demo credential button.
  4. Check Dashboard, Catalog, Purchase Orders, Customer Orders, Stock Balances, Stock Movements, and Documents.

UI / UX

Frontend содержит единый ERP-style интерфейс без внешней UI-библиотеки:

  • общий layout с grouped sidebar и top header;
  • reusable UI components в frontend/src/components/ui;
  • единые table/loading/error/empty/pagination states;
  • единые status badges для закупок, продаж, документов и складских движений;
  • форматтеры в frontend/src/utils/formatters.ts для сумм, количеств, дат, статусов, типов документов и движений;
  • role-aware UI: frontend скрывает недоступные кнопки, backend остается главным источником прав.

Available frontend routes:

  • /login
  • /dashboard
  • /catalog/products
  • /catalog/suppliers
  • /catalog/customers
  • /catalog/warehouses
  • /procurement/purchase-orders
  • /procurement/purchase-orders/{id}
  • /sales/customer-orders
  • /sales/customer-orders/{id}
  • /warehouse/stock-balances
  • /warehouse/stock-movements
  • /documents

Role-aware UI behavior:

  • FINANCE: read-only UI for catalog, purchase orders, customer orders, warehouse; can generate invoice/contract documents.
  • WAREHOUSE: no catalog create/edit UI; can receive PO, process/ship SO, create warehouse adjustments, generate delivery notes.
  • ADMIN and MANAGER: main operational actions for catalog, procurement, sales, and documents.
  • Warehouse manual ADJUSTMENT_OUT, catalog deactivate, PO cancel, and SO cancel use confirmation dialogs.

Common UI components:

  • Button, Input, Select, Textarea
  • Card, Badge, PageHeader
  • EmptyState, LoadingState, ErrorState
  • ConfirmDialog, FormField, Pagination

Debug Error Endpoint

Dev-only endpoint для проверки единого формата ошибок:

curl "http://localhost:8080/api/debug/error?type=validation"
curl "http://localhost:8080/api/debug/error?type=not-found"
curl "http://localhost:8080/api/debug/error?type=business"
curl "http://localhost:8080/api/debug/error?type=generic"

Endpoint должен быть удален или отключен перед production.

Useful Commands

Run:

docker compose up --build

Stop:

docker compose down

Reset database:

docker compose down -v
docker compose up --build

Backend logs:

docker compose logs -f backend

Frontend logs:

docker compose logs -f frontend

Postgres logs:

docker compose logs -f postgres

Server deployment compose:

docker compose -f docker-compose.server.yml up -d --build

docker-compose.server.yml does not publish app ports directly. It expects an external Docker network named common_network and an edge reverse proxy, for example nginx, to route HTTPS traffic to erp-frontend and /api traffic to erp-backend.

ERP MVP Demo Script

Pitch:

This MVP demonstrates the core ERP operating loop: catalog data, procurement, sales orders, warehouse stock movements, document generation and management dashboard in one integrated system.

5-7 minute flow:

  1. Login as Admin: admin@erp.local / admin12345.
  2. Open Dashboard and show KPI cards for catalog, sales, procurement, warehouse, documents and low stock.
  3. Open Catalog -> Products, Suppliers, Customers, Warehouses and show the seeded master data.
  4. Open Purchase Orders and open the received PO.
  5. Explain that moving PO to RECEIVED created inbound stock movements.
  6. Open Stock Balances and show updated warehouse quantities.
  7. Open Customer Orders and open the shipped order.
  8. Explain that moving SO to SHIPPED created outbound stock movements and checked available stock.
  9. Open Documents and show generated invoice, contract and delivery note placeholders.
  10. Download one PDF from Documents or Customer Order details.
  11. Return to Dashboard and show recent activities, low stock and updated analytics.

Manual QA Checklist

Backend:

  • /api/health returns UP.
  • Swagger opens at http://localhost:8080/swagger-ui/index.html.
  • Login works.
  • Catalog CRUD works.
  • Purchase order flow works.
  • Customer order flow works.
  • Stock balances update correctly.
  • Documents generate and download.
  • Dashboard loads.

Frontend:

  • Login works.
  • Sidebar navigation works.
  • Dashboard loads.
  • Forms save data.
  • Status transitions work.
  • Errors display properly.
  • Download PDF works.
  • Logout works.

Troubleshooting

PostgreSQL port already in use:

  • Stop the local PostgreSQL process or change the 5432:5432 mapping in docker-compose.yml.

Backend cannot connect to database:

  • Check docker compose logs -f backend and confirm SPRING_DATASOURCE_URL, POSTGRES_DB, POSTGRES_USER and POSTGRES_PASSWORD match.

Flyway migration failed:

  • For dev data loss is acceptable, reset with docker compose down -v and then docker compose up --build.

Frontend cannot call backend due to CORS:

  • Confirm CORS_ALLOWED_ORIGINS includes http://localhost:5173.

JWT expired or unauthorized:

  • Logout, login again, and check that requests include Authorization: Bearer <token>.

Demo data not visible:

  • Ensure DEMO_DATA_ENABLED=true, then reset the dev database if it was initialized before enabling demo data.

PDF download blocked by browser:

  • Try downloading from the Documents page again and make sure pop-up/download blocking is not preventing the file save.

Database credentials changed but old volume remains:

  • Run docker compose down -v so PostgreSQL can initialize with the new .env values.

MVP Scope

Included:

  • Auth and roles.
  • Catalog.
  • Procurement.
  • Sales.
  • Warehouse stock.
  • Documents.
  • Dashboard.
  • Demo data.

Not included in MVP v1:

  • Real 1C integration.
  • Real WMS/TMS integration.
  • Payment module.
  • Email/WhatsApp sending.
  • Electronic signature.
  • Advanced approval workflow.
  • Advanced BI/Power BI.
  • Multi-company accounting.