
StockShift Backend is the REST API that powers StockShift, a multi-tenant inventory and warehouse management application. It handles authentication, tenant isolation, warehouse-scoped authorization, product catalog data, batches, stock movements, transfers, sales, reporting, file uploads, payment webhooks, and audit trails.
The application is served under the /stockshift context path. In local development, the API base URL is usually http://localhost:8080/stockshift.
- Manages tenants, users, roles, permissions, and warehouse-scoped access.
- Stores products, brands, categories, batches, and stock quantities per warehouse.
- Records stock movements and keeps an inventory ledger for traceability.
- Supports warehouse-to-warehouse transfers with execution, validation, discrepancy reports, and validation logs.
- Exposes sales workflows, sales dashboards, and InfinitePay payment confirmation/webhook handling.
- Generates operational reports for dashboards, stock, low-stock products, expiring batches, and movement trends.
- Uploads product images and company logos to S3-compatible storage.
- Can analyze product images with OpenAI to suggest product metadata.
- Writes audit events and exports audit data as CSV or XLSX.
This backend follows a conventional Spring Boot layered architecture:
HTTP clients
-> controllers
-> services
-> repositories
-> PostgreSQL
Cross-cutting layers:
security filters -> JWT, tenant context, warehouse context, audit context
migrations -> Flyway SQL scripts
cache/ephemeral -> Redis token denylist and rate limiting
adapters -> S3-compatible storage, InfinitePay, OpenAI
jobs -> reconciliation and temporary upload cleanup
- A request reaches the API under
/stockshift/api/**. SecurityConfigapplies stateless Spring Security rules.JwtAuthenticationFilterreads the JWT from theaccessTokencookie first, then from theAuthorization: Bearer ...header.- The filter validates the token, checks the Redis-backed denylist, verifies the user and tenant, then sets
TenantContextandWarehouseContext. - Controllers validate and map HTTP input into DTOs.
- Services enforce business rules, permissions, tenant boundaries, warehouse boundaries, and transactional behavior.
- Repositories persist tenant-scoped entities through Spring Data JPA.
- Flyway owns database schema evolution.
- The request context is cleared after each request to avoid tenant or warehouse leakage.
| Path | Responsibility |
|---|---|
src/main/java/br/com/stockshift/controller |
REST endpoints and HTTP response shaping |
src/main/java/br/com/stockshift/service |
Business rules for auth, catalog, inventory, transfers, reports, sales, storage, audit, and integrations |
src/main/java/br/com/stockshift/security |
JWT auth, user principal, tenant context, warehouse context, permission guards, and rate limiting |
src/main/java/br/com/stockshift/model/entity |
JPA entities and tenant-aware base models |
src/main/java/br/com/stockshift/model/enums |
Domain enums for permissions, movements, transfers, sales, payments, and validations |
src/main/java/br/com/stockshift/repository |
Spring Data JPA repositories |
src/main/java/br/com/stockshift/dto |
Request and response contracts |
src/main/java/br/com/stockshift/config |
Spring, security, CORS, Redis, storage, OpenAPI, and client configuration |
src/main/resources/db/migration |
Flyway migrations |
docs/endpoints |
Functional endpoint documentation |
src/test/java/br/com/stockshift |
Unit, integration, security, and regression tests |
- Java 17
- Spring Boot 4.0.1
- Spring Web
- Spring Security with stateless JWT authentication
- Spring Data JPA and Hibernate
- PostgreSQL 16
- Flyway
- Redis
- Bucket4j for login rate limiting
- OpenAPI/Swagger through Springdoc
- AWS SDK S3 client for S3-compatible storage, including Supabase Storage
- OpenAI API integration for product image classification
- InfinitePay checkout and webhook integration
- Apache POI and OpenPDF for report exports
- JUnit 5, Spring Security Test, Testcontainers, MockWebServer, and JaCoCo
- Docker and Docker Compose for local infrastructure
- Java 17
- Docker and Docker Compose
- A working Docker daemon for local services and Testcontainers
- The Gradle wrapper included in this repository
Create a local development configuration from the example file:
cp src/main/resources/application-dev.example.yml src/main/resources/application-dev.ymlStart PostgreSQL and Redis:
docker compose -f docker-compose.local.yml up -d postgres redisRun the application:
./gradlew bootRunThe API will be available at:
- API base URL:
http://localhost:8080/stockshift - Swagger UI:
http://localhost:8080/stockshift/swagger-ui/index.html - Health check:
http://localhost:8080/stockshift/actuator/health
To start pgAdmin as well:
docker compose -f docker-compose.local.yml --profile tools up -dpgAdmin runs at http://localhost:5050 with the local defaults from docker-compose.local.yml.
The default active profile is dev. Local development settings should live in src/main/resources/application-dev.yml, which is intentionally derived from application-dev.example.yml.
Important environment variables:
| Variable | Purpose | Local default |
|---|---|---|
DB_HOST |
PostgreSQL host | localhost |
DB_PORT |
PostgreSQL port | 5432 |
DB_NAME |
PostgreSQL database | stockshift |
DB_USER |
PostgreSQL username | postgres |
DB_PASSWORD |
PostgreSQL password | postgres |
REDIS_HOST |
Redis host | localhost |
REDIS_PORT |
Redis port | 6379 |
REDIS_PASSWORD |
Redis password | empty |
JWT_SECRET |
HMAC secret used to sign JWTs | dev-only example value |
JWT_ACCESS_EXPIRATION |
Access token lifetime in milliseconds | 900000 |
JWT_REFRESH_EXPIRATION |
Refresh token lifetime in milliseconds | 604800000 |
ALLOWED_ORIGINS |
CORS allowlist | local frontend and proxy origins |
FRONTEND_URL |
Frontend URL used in redirects | set per environment |
API_BASE_URL |
Public API base URL | set per environment |
STORAGE_ENDPOINT |
S3-compatible storage endpoint | empty |
STORAGE_ACCESS_KEY |
Storage access key | empty |
STORAGE_SECRET_KEY |
Storage secret key | empty |
STORAGE_BUCKET_NAME |
Storage bucket name | stockshift |
STORAGE_PUBLIC_URL |
Public URL used to serve uploaded files | empty |
HCAPTCHA_SECRET_KEY |
hCaptcha verification secret | empty |
OPENAI_API_KEY |
OpenAI API key for image classification | empty |
OPENAI_API_URL |
OpenAI API base URL | https://api.openai.com |
OPENAI_MODEL |
OpenAI model used by the classifier | gpt-4.1-nano |
STOCKSHIFT_BOT_API_KEY |
Shared secret accepted by internal Telegram bot endpoints | empty |
STOCKSHIFT_BOT_TENANT_ID |
Tenant UUID used for internal Telegram bot queries | empty |
Production uses SPRING_PROFILES_ACTIVE=prod, requires real secrets, enables secure JWT cookies, disables Swagger/OpenAPI, and expects all required database, storage, hCaptcha, and OpenAI variables to be provided by the runtime environment.
Flyway runs automatically on startup and loads migrations from:
src/main/resources/db/migration
The schema is tenant-aware. Core domain tables include tenants, warehouses, products, categories, brands, batches, roles, permissions, users, stock movements, inventory ledger entries, transfers, sales, audit events, uploaded product images, and product prompts.
To run migrations explicitly:
./gradlew flywayMigrateThe API is stateless. Authentication uses signed JWTs and supports:
accessTokenHTTP-only cookieAuthorization: Bearer <token>header- Redis-backed token denylist for logout and token revocation
- Login rate limiting through Bucket4j and Redis
- Method-level authorization through
@PreAuthorize - Permission checks such as
products:read,batches:create,transfers:validate, andreports:read - Warehouse-scoped access for operations that must stay inside the selected warehouse
Public endpoints are limited to Swagger in development, health checks, auth login/refresh/register, and the tokenized InfinitePay webhook endpoint.
When running with the development profile, Swagger UI is available at:
http://localhost:8080/stockshift/swagger-ui/index.html
Endpoint documentation is also kept in the repository:
- Authentication
- Brands
- Categories
- Products
- Batches
- Warehouses
- Users
- Stock movements
- Transfers
- Reports
- Frontend authentication guide
Run the full test suite:
./gradlew testRun the complete quality gate used by CI:
./gradlew checkGenerate the JaCoCo report:
./gradlew test jacocoTestReportThe CI workflow runs ./gradlew check --no-daemon on pushes and pull requests to main.
Build the application image:
docker build -t stockshift-backend .Run local infrastructure:
docker compose -f docker-compose.local.yml up -d postgres redisThe Dockerfile builds the Spring Boot jar with the Gradle wrapper, then runs it on Eclipse Temurin 17 JRE Alpine as a non-root stockshift user.
- Use
SPRING_PROFILES_ACTIVE=prod. - Provide a strong
JWT_SECRET; do not use the development default. - Serve the API behind HTTPS because production cookies are secure.
- Configure
ALLOWED_ORIGINSto the deployed frontend origin. - Provide production PostgreSQL, Redis, storage, hCaptcha, OpenAI, and payment-related settings.
- Keep Flyway migrations immutable after release.
- Swagger and OpenAPI are disabled by the production profile.
This project is licensed under the PolyForm Internal Use License 1.0.0.