← All projects

Salesbook

Full-stack sales management system — Spring Boot REST API with PostgreSQL and a Vue 3 + Vuetify dashboard.

  • Java
  • Spring Boot
  • PostgreSQL
  • Flyway
  • Vue 3
  • Vuetify
  • REST API
  • CI/CD

· github.com/carloscardoso05/salesbook

Overview

Salesbook is a point-of-sale management system that keeps a store’s customers, products, payments, and orders in sync. The backend is a Spring Boot REST API backed by PostgreSQL (schema managed by Flyway), and the frontend is a Vue 3 + Vuetify single-page app.

The interesting part isn’t the CRUD — it’s the business rules that mutate state across entities (orders moving money and stock) and the engineering practices around them: vertical-slice architecture, optimistic locking, an audit trail, and a CI/CD pipeline that deploys to AWS EC2.

Screenshots

Customers dashboard

Order detail

Product catalog

Features

  • Customers — CRUD with case-insensitive unique name and a balance that reflects real money movement.
  • Products — CRUD with stock control (stock >= 0).
  • Payments — increase a customer’s balance; updates and removals adjust it accordingly.
  • Orders & Order Items — nested resource; creating an item deducts its price from the customer balance and decrements product stock. Orders below stock fail with 400.
  • BalanceAdjustment audit trail — every manual balance edit is recorded as an immutable, read-only record.
  • Concurrency safety — optimistic locking (@Version) on Customer and Product; conflicts return 409 Conflict.
  • Swagger UI — OpenAPI docs at /swagger-ui.html.

Business rules

  • Payment adds value to customer.balance on create, adjusts by the difference on update, subtracts on delete.
  • OrderItem subtracts price from the balance and decrements product.stock by 1 on create; a price update adjusts the balance by the difference; a delete refunds the price and restocks.
  • Deleting an Order refunds the balance and restocks all of its items via DB cascade.
  • Manual balance edits create a BalanceAdjustment with value = newBalance - oldBalance (no adjustment when unchanged).
  • Customer and product names are unique case-insensitively (lower(name) unique index).

Architecture

Browser ──> Vue 3 + Vuetify (ui/) ──> REST API ──> Spring Boot (api/) ──> PostgreSQL

                                       └── Flyway migrations (V1..V3)

Backend features follow a vertical slice pattern — each feature is a self-contained package:

customer/    payment/    product/    order/    orderitem/    adjustment/    shared/
   │             │           │          │           │             │            │
   └─ entity → repository → service → controller → dto/          exceptions + error handler
  • Every service method is @Transactional (reads are readOnly).
  • Centralized exception handling maps errors to 400/404/409.
  • Monetary fields use numeric(12, 2) / BigDecimal.

Tech stack

Layer Technology
Backend Java 21, Spring Boot 4, Gradle
Database PostgreSQL 18, Flyway migrations
Frontend Vue 3, Vuetify 4, Pinia, Vue Router, TypeScript, Vite, Tailwind CSS
API docs springdoc-openapi (Swagger UI)
Infra Docker Compose (local Postgres), GitHub Actions → AWS EC2 (systemd)

Testing

  • Unit suites per vertical slice with JUnit 5, Mockito (strict stubs) and AssertJ — entity guard tests plus service-layer tests.
  • CI runs the full ./gradlew build on every push to main and deploys the bootable jar to an EC2 instance via GitHub Actions.

Running locally

Prerequisites: Docker, JDK 21, bun.

# 1. Backend
cd api
cp .env.example .env      # fill in DB_URL, DB_USERNAME, DB_PASSWORD
docker compose up -d      # start PostgreSQL
./gradlew bootRun         # API at http://localhost:8080

# 2. Frontend (new terminal)
cd ui
bun install
bun dev                   # UI at http://localhost:3000 (proxies /api to :8080)

Swagger UI: http://localhost:8080/swagger-ui.html

Why this project?

It demonstrates the practices that matter on real backend teams: database migrations instead of Hibernate auto-DDL, domain-driven mutations with guarded setters, optimistic locking for concurrent stock/balance updates, audit trails for financial data, and a pipeline that takes code to production automatically.