Skip to content

About

No description, website, or topics provided.

Resources

Stars

2 stars

Watchers

0 watching

Forks

Repository files navigation

AniMusic_BE

AniMusic_BE is the backend service for the AniMusic ecosystem, a platform for managing, distributing, and using music visualization templates. The project is built as a modular monolith with Spring Boot: business domains are separated into modules while the system is still deployed as one backend application.

Table of Contents

Overview

The backend currently supports these major feature groups:

  • Authentication, RBAC authorization, and user management.
  • Template marketplace: creation, updates, review workflow, versioning, categories, tags, favorites, download tracking, and feedback/rating.
  • Premium template checkout through PayOS and Stripe.
  • AI chat with template-based RAG, SSE streaming, and audio profile extraction.
  • Realtime render progress tracking through WebSocket/STOMP and REST history APIs.
  • Realtime notifications and notification history.
  • Admin dashboards, including template developer evaluation.

The application uses PostgreSQL as the primary database, Flyway for schema management, Cloudflare R2 for template archives, Cloudinary for images/thumbnails, and Spring AI for OpenAI/pgvector integration.

Tech Stack

Area Technology
Runtime Java 21, Spring Boot 3.4.5
Build Maven Wrapper
Persistence Spring Data JPA, Hibernate, PostgreSQL
Migration Flyway
Security Spring Security, JWT with JJWT
Validation Jakarta Validation
API docs SpringDoc OpenAPI, Swagger UI
AI Spring AI 1.0.x, OpenAI chat/embedding, Gemini through an OpenAI-compatible endpoint
Vector store pgvector
Storage Cloudflare R2, Cloudinary
Payment PayOS SDK, Stripe Java SDK
Realtime Spring WebSocket/STOMP, WebFlux SSE
Resilience Resilience4j circuit breaker, rate limiter, retry
Test JUnit 5, Mockito, H2, OpenCSV, JaCoCo

Project Structure

src/main/java/vn/fpt/AniMusic_BE
├── config                 # Spring, AI, WebSocket, Swagger, Flyway, and seed configuration
├── exceptions             # AppException, ErrorCode, GlobalExceptionHandler
├── infrastructure         # Email, storage, payment config, websocket helper, slug service
├── modules                # Main business modules
├── payload                # ApiResponse<T>
└── security               # JWT filter/provider, principal, CORS, SecurityConfig

src/main/resources
├── application.yaml       # Default profile and .env import
├── application-dev.yaml   # Development configuration
├── application-prod.yaml  # Production configuration
├── chat                   # Python audio profile extractor
├── db/migration           # Flyway migrations
└── templates              # Email templates

Most business modules follow this structure:

controller/
service/
repository/
entity/
dto/
mapper/

Some foundational modules, such as authority, focus mainly on entities, repositories, and enums used by RBAC.

Main Modules

Module Responsibility
authenticate Login, registration, refresh token, email confirmation, forgot/reset password, app login code
authority Roles, permissions, and RBAC mappings
user User profile, password change, avatar upload, admin user management
template Template lifecycle: create, update, review, list/detail, download, delete
template_version Template version management
template_upload Multipart upload orchestration for template archives on Cloudflare R2
template_category Category CRUD and filtering
template_tag Tag CRUD and tag-template mappings
template_favorite Favorite/unfavorite and user favorite listing
template_download Download event tracking and success/failed confirmation
template_feedback Template-level feedback and rating
cart Pre-checkout cart operations
order Order lifecycle and lookup
payment Payment orchestration, PayOS/Stripe gateways, and webhooks
chat Conversations, messages, AI chat, SSE streaming, RAG, audio profile
notification Notification APIs and read/unread state
dashboard System analytics and template developer evaluation
render Render progress ingest through WebSocket and REST history APIs

Key Business Flows

Template Upload and Review

The backend supports two ways to upload template archives:

  1. Direct multipart form upload through the template/template-version APIs.
  2. Multipart presigned upload through /template-uploads/init, client-side part uploads to R2, and completion through /template-uploads/complete.

Regular users normally create or update templates into PENDING_REVIEW. Staff/Admin users can review templates and approve or reject them. Review/delete events are used to send notifications and synchronize the RAG index.

Download, Feedback, and Rating

GET /templates/{id}/download only issues a presigned URL and creates a downloadEventId; it does not increment download_count.

The client must call POST /templates/{templateId}/downloads/{downloadEventId}/confirm to confirm SUCCESS or FAILED. Only the first SUCCESS confirmation increments templates.download_count; repeated confirmations are handled idempotently.

Feedback is template-level. A user can leave one feedback entry per template only after at least one successful download. The denormalized rating_count and rating_avg values are synchronized whenever feedback is created, updated, or deleted.

Payment and Order

Main checkout flow:

cart/items -> create PENDING order -> select PAYOS or STRIPE gateway -> receive checkout URL -> webhook confirmation -> complete payment/order

Available webhook endpoints:

  • PayOS: /payments/webhook/payos
  • PayOS webhook URL confirmation: /payments/webhook/payos/confirm
  • Stripe: /payments/webhook/stripe

AI Chat and RAG

AI chat uses Spring AI. Metadata from APPROVED and PUBLIC templates is converted into vector documents in pgvector and retrieved as contextual data for chat responses. Both non-streaming and SSE streaming chat are supported.

The audio profile extractor runs as a Python script at src/main/resources/chat/audio_profile_extractor.py. Extracted audio profile data is runtime-only and is not persisted to the database.

Render Telemetry

The desktop client sends render progress updates through the WebSocket destination /app/render/update. The backend stores render processes and samples, then exposes REST APIs for authenticated users to view render history.

Environment Requirements

  • JDK 21.
  • Maven Wrapper, already included in the repository.
  • Docker and Docker Compose if running with containers.
  • PostgreSQL with the pgvector extension if running the database outside Docker.
  • Python 3 if using the audio profile extractor outside Docker.

Python packages required by the audio extractor are listed in requirements.txt:

librosa
numpy
soundfile
scipy
setuptools

Environment Configuration

The application reads .env through this Spring configuration:

spring.config.import: optional:file:.env[.properties]

Create a .env file in the project root. Minimal local development example:

SPRING_PROFILES_ACTIVE=dev
CLIENT_URL=http://localhost:5173

DATABASE_NAME=animusic
DATABASE_URL=jdbc:postgresql://localhost:5433/animusic
DATABASE_USERNAME=animusic
DATABASE_PASSWORD=animusic

APP_ADMIN_USERNAME=admin
APP_ADMIN_EMAIL=admin@example.com
APP_ADMIN_PHONE=0900000001
APP_ADMIN_PASSWORD=ChangeMe123!

APP_USER_USERNAME=user
APP_USER_EMAIL=user@example.com
APP_USER_PHONE=0900000002
APP_USER_PASSWORD=ChangeMe123!
APP_USER_DEFAULT_AVATAR=https://example.com/avatar.png

APP_STAFF_USERNAME=staff
APP_STAFF_EMAIL=staff@example.com
APP_STAFF_PHONE=0900000003
APP_STAFF_PASSWORD=ChangeMe123!

APP_DEVELOPER_USERNAME=developer
APP_DEVELOPER_EMAIL=developer@example.com
APP_DEVELOPER_PHONE=0900000004
APP_DEVELOPER_PASSWORD=ChangeMe123!

CORS_ALLOWED_ORIGINS=http://localhost:5173
CORS_ALLOWED_METHODS=GET,POST,PUT,PATCH,DELETE,OPTIONS
CORS_ALLOWED_HEADERS=*

EMAIL_USERNAME=your-email@gmail.com
EMAIL_PASSWORD=your-app-password
EMAIL_VERIFICATION_EXPIRATION=3600

JWT_SECRET_KEY=replace-with-a-long-random-secret-key
JWT_DURATION=3600
JWT_REFRESH_DURATION=604800

CLOUDFLARE_R2_ENDPOINT=https://your-account-id.r2.cloudflarestorage.com
CLOUDFLARE_R2_ACCESS_KEY=your-r2-access-key
CLOUDFLARE_R2_SECRET_KEY=your-r2-secret-key
CLOUDFLARE_R2_BUCKET=your-bucket
CLOUDFLARE_R2_DOWNLOAD_PRESIGNED_URL_DURATION=3600

CLOUDINARY_CLOUD_NAME=your-cloud-name
CLOUDINARY_API_KEY=your-api-key
CLOUDINARY_API_SECRET=your-api-secret

PAYOS_CLIENT_ID=your-payos-client-id
PAYOS_API_KEY=your-payos-api-key
PAYOS_CHECKSUM_KEY=your-payos-checksum-key
PAYOS_RETURN_URL=http://localhost:5173/payment/success
PAYOS_CANCEL_URL=http://localhost:5173/payment/cancel

STRIPE_SECRET_KEY=sk_test_xxx
STRIPE_WEBHOOK_SECRET=whsec_xxx
STRIPE_RETURN_URL=http://localhost:5173/payment/success
STRIPE_CANCEL_URL=http://localhost:5173/payment/cancel

OPENAI_API_KEY=sk-xxx
GOOGLE_AI_API_KEY=

APP_LOGIN_CODE_EXPIRATION=300
APP_SEED_ENABLED=true

Notes:

  • Do not commit .env or real secrets.
  • Leave GOOGLE_AI_API_KEY empty if Gemini is not used.
  • If audio profile extraction is not needed locally, avoid calling the audio endpoint from the client. Otherwise, install the Python dependencies.
  • For RAG, the embedding dimension must stay synchronized across Spring AI configuration, pgvector configuration, and database migration definitions.

Running the Project

Option 1: Run the Database with Docker and the App with Maven

Start PostgreSQL pgvector:

docker compose up -d postgres

Run the backend:

./mvnw spring-boot:run

On Windows PowerShell:

.\mvnw.cmd spring-boot:run

The application runs by default at:

http://localhost:8080

Option 2: Run Everything with Docker Compose

docker compose up --build

Docker Compose builds the backend image, installs the Python runtime for the audio extractor, starts PostgreSQL pgvector, and exposes the backend on port 8080.

Build the Jar

./mvnw clean package

Run the jar:

java -jar target/AniMusic_BE-0.0.1-SNAPSHOT.jar

API Documentation

Swagger UI:

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

OpenAPI JSON:

http://localhost:8080/v3/api-docs

Main endpoint groups:

Group Base path
Auth /auth
Users /users
Templates /templates
Template upload /template-uploads
Template versions /template-versions
Template categories /template-cats
Template tags /template-tags
Template favorites /template-favorites
Cart /carts
Orders /orders
Payments /payments
Chat /chat
Chat admin /chat/admin
Notifications /notifications
Dashboard /dashboards
Render history /render-processes
WebSocket docs /ws-docs

WebSocket endpoint:

/ws

STOMP conventions:

  • Application destination prefix: /app
  • User destination prefix: /user
  • Simple broker prefix: /queue

Database and Migrations

Flyway migrations are stored in:

src/main/resources/db/migration

Migration naming convention:

V{number}__description.sql

Important constraints:

  • spring.jpa.hibernate.ddl-auto=none; schema changes are managed by Flyway.
  • open-in-view=false; lazy data must be fetched or initialized explicitly in services.
  • The pgvector schema is owned by migrations, not by Spring AI automatic initialization.
  • The vector embedding column must use the same dimension as:
    • spring.ai.openai.embedding.options.dimensions
    • spring.ai.vectorstore.pgvector.dimensions
    • the database column definition.

AI, RAG, and Audio Profile

Main chat APIs:

  • POST /chat/send: non-streaming response.
  • POST /chat/send/stream: SSE stream.
  • POST /chat/audio/keywords: extracts audio keywords/profile.
  • POST /chat/admin/reindex: admin-triggered RAG index rebuild.

RAG only indexes and returns templates that are:

  • APPROVED
  • PUBLIC

Audio extractor configuration:

  • Script: src/main/resources/chat/audio_profile_extractor.py
  • Python path: APP_CHAT_AUDIO_PYTHON_PATH
  • Script path override: APP_CHAT_AUDIO_PYTHON_SCRIPT_PATH
  • Default limits: 25 MB, 180 seconds, 12 keywords.

Testing

Run all tests:

./mvnw test

Run tests with coverage report generation:

./mvnw verify

The test profile uses H2 and CSV fixtures under:

src/test/resources/testdata

Tests can use CsvTestDataLoader to load module-specific fixtures.

Development Conventions

  • Use ResponseEntity<ApiResponse<T>> for regular REST APIs.
  • Use Flux<ChatResponse> for chat SSE streaming.
  • Use AppException or module-specific exceptions with ErrorCode; avoid raw string error responses.
  • Check ErrorCode.java before adding a new error type.
  • Use DTO validation with jakarta.validation.
  • Keep entity/DTO mapping in dedicated mapper classes.
  • Keep Swagger annotations on controller endpoints.
  • Apply @PreAuthorize consistently for method-level RBAC.
  • Apply @RateLimiter to public or sensitive endpoints.
  • Add a new Flyway migration for schema changes.
  • Add or update tests when behavior changes.
  • Preserve both template upload paths: direct multipart and multipart presigned upload.
  • Do not increment templates.download_count when only issuing a download URL; increment it only after a download event is confirmed as SUCCESS.
  • Keep rating_count and rating_avg synchronized whenever feedback changes.

Additional Documentation

  • docs/cloudflare-r2-multipart-upload.md: Cloudflare R2 multipart upload checklist for CORS, lifecycle cleanup, and validation.
  • AGENTS.md: architecture and convention notes for AI agents working in this repository.

About

No description, website, or topics provided.

Resources

Stars

2 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages