REST API for a vinyl-record store, built with Spring Boot, Java 25, MyBatis, MySQL, JWT, and Flyway.
Requirements: JDK 25 and a local MySQL instance. Copy .env.example to .env, supply the required values, then expose those values in your shell or IDE run configuration.
.\gradlew.bat clean build
.\gradlew.bat bootRunThe API starts on port 4242; Swagger UI is available at /swagger-ui/index.html.
Swagger/OpenAPI is public at /swagger-ui/index.html and /v3/api-docs. Send the JWT as Authorization: Bearer <token> for protected endpoints. Core v1 responses use { "success", "message", "data" }; errors use { "success": false, "error", "message" } with the appropriate HTTP status.
| Method | Route | Access | Notes |
|---|---|---|---|
| POST | /api/v1/auth/login |
Public | Login |
| POST | /api/v1/auth/google-login |
Public | Google OAuth login callback |
| POST | /api/v1/auth/register |
Public | Register by email query parameter |
| POST | /api/v1/auth/refresh-token |
Public | Refresh JWT |
| GET | /api/v1/products |
Public | Supports existing filtering/paging query parameters |
| GET | /api/v1/categories |
Public | Product categories |
| GET | /api/v1/users/me |
Authenticated | Current JWT account; no email query parameter |
| PUT | /api/v1/users/profile |
Authenticated | Updates current JWT account; request id is ignored |
| PUT | /api/v1/users/change-password |
Authenticated | Changes current JWT account password; request userID is ignored |
| GET | /api/v1/users |
Admin | All users |
| GET | /api/v1/users/email?address= |
Admin | Find user by email |
| GET | /api/v1/users/{id} |
Admin | Find user by id |
| POST | /api/v1/orders/place-order |
Authenticated | Server sets customer and prices; send only contact fields and items[].productId, items[].quantity |
| GET | /api/v1/orders/me |
Authenticated | Current user's orders |
| GET | /api/v1/orders/{id} |
Owner or admin | A customer may view only their own order |
| GET | /api/v1/orders/user/{userId} |
Same user or admin | Kept for compatibility; prefer /orders/me |
| GET | /api/v1/orders |
Admin | All orders |
| GET | /api/v1/order-items |
Admin | All order line items |
| POST | /api/v1/payments/create |
Order owner or admin | Requires orderId, method, and unique idempotencyKey |
| GET | /api/v1/payments/{orderId} |
Order owner or admin | Returns the safe payment-status view only |
| POST | /api/v1/payments/webhook/{provider} |
Public | Provider callback; signature, amount and idempotency verified server-side |
| POST | /api/v1/admin/catalog-imports/voc |
Admin | Imports VOC catalog; optional limit |
| POST | /api/v1/admin/catalog-imports/voc/product |
Admin | Imports one sourceUrl |
| GET | /api/v1/test/hello |
Admin | Diagnostic endpoint |
| GET | /actuator/health/** |
Public | Health probes only |
| GET | /actuator/** |
Admin | Metrics, environment and diagnostics |
Important compatibility changes: all existing application route names remain available, except that GET /api/v1/orders/me is new and collection routes now also accept the no-trailing-slash form. Clients must stop sending or relying on customerId, totalPrice, and item price when placing an order. Payment creation no longer accepts a client-provided amount or return URL.
For browser clients, set CORS_ALLOWED_ORIGINS to a comma-separated allowlist (for example https://portfolio.example.com). The local defaults are http://localhost:3000,http://localhost:5173.
- The application has no Docker or Redis runtime dependency.
- Database schema changes run through Flyway migrations in
src/main/resources/db/migration. - Run the test suite with
.\gradlew.bat test.