Prompt file imported from toastmoartl/Celticus (
.github/prompts/plan-physioExerciseManagement.prompt.md). Fill in{{token}},{{API_BASE_URL}},{{endpoint}},{{response_status}}before use. Copyright stays with the author.
Physio Fitness Exercise Management System
Overview
Build a full-stack application with Java Spring Boot backend and vanilla HTML frontend for managing physio exercises, user plans, and tracking completion. Use PostgreSQL for storage, Docker for deployment, and a clean layered architecture focused on maintainability and extensibility.
Tech Stack
Backend
- Java 21 with Spring Boot 3.2+
- PostgreSQL - Best balance of features, reliability, and low maintenance
- Spring Data JPA with Hibernate
- Spring Security for authentication
- Flyway for database migrations
- Lombok for boilerplate reduction
- MapStruct for entity-DTO mapping
Frontend
- Vanilla HTML/CSS/JavaScript with modern ES6+ features
- Tailwind CSS for styling
- Fetch API for REST calls
- Keep it simple - no build tools needed initially
Infrastructure
- Docker Compose for local development (backend + PostgreSQL)
- Docker for production deployment
Project Structure (Monorepo)
Celticus/
├── backend/ # Spring Boot application
│ ├── src/
│ │ ├── main/
│ │ │ ├── java/com/celticus/
│ │ │ │ ├── CelticusApplication.java
│ │ │ │ ├── config/ # Security, CORS, JPA configs
│ │ │ │ ├── domain/ # Entities
│ │ │ │ │ ├── Exercise.java
│ │ │ │ │ ├── User.java
│ │ │ │ │ ├── WeeklyPlan.java
│ │ │ │ │ ├── ExerciseCompletion.java
│ │ │ │ │ └── Tag.java
│ │ │ │ ├── repository/ # Spring Data JPA repositories
│ │ │ │ ├── service/ # Business logic
│ │ │ │ ├── dto/ # Data Transfer Objects
│ │ │ │ ├── controller/ # REST controllers
│ │ │ │ └── exception/ # Custom exceptions & handlers
│ │ │ └── resources/
│ │ │ ├── application.yml
│ │ │ ├── application-dev.yml
│ │ │ ├── application-prod.yml
│ │ │ └── db/migration/ # Flyway migrations
│ │ └── test/
│ ├── Dockerfile
│ └── pom.xml (or build.gradle)
│
├── frontend/ # Static HTML/CSS/JS
│ ├── index.html
│ ├── login.html
│ ├── css/
│ │ └── styles.css
│ ├── js/
│ │ ├── api.js # API client wrapper
│ │ ├── auth.js # Authentication logic
│ │ ├── exercises.js # Exercise CRUD
│ │ ├── plans.js # Weekly plans
│ │ └── dashboard.js # Completion tracking
│ └── assets/
│ └── videos/ # Or store URLs to external storage
│
├── docker-compose.yml # Local dev setup
├── docker-compose.prod.yml # Production setup
└── README.md
Core Domain Model
Entities
User
- id (Long, primary key)
- username (String, unique)
- email (String, unique)
- password (String, hashed with BCrypt)
- role (Enum: ADMIN, THERAPIST, PATIENT)
- createdDate (LocalDateTime)
Exercise
- id (Long, primary key)
- title (String)
- description (Text)
- videoUrl (String, URL or path)
- createdDate (LocalDateTime)
- updatedDate (LocalDateTime)
- tags (ManyToMany with Tag)
Tag
- id (Long, primary key)
- name (String, unique)
- exercises (ManyToMany with Exercise)
WeeklyPlan
- id (Long, primary key)
- user (ManyToOne with User)
- weekStartDate (LocalDate)
- exercises (ManyToMany with Exercise)
- createdDate (LocalDateTime)
ExerciseCompletion
- id (Long, primary key)
- user (ManyToOne with User)
- exercise (ManyToOne with Exercise)
- completedDate (LocalDateTime)
- notes (String, optional)
Relationships
- User 1:N WeeklyPlan
- WeeklyPlan N:M Exercise
- Exercise N:M Tag
- User + Exercise → ExerciseCompletion (tracking)
Architectural Patterns
1. Layered Architecture
Controller Layer
- REST endpoints
- Request validation with @Valid
- Response formatting
- HTTP status codes
Service Layer
- Business logic
- Transaction management with @Transactional
- Orchestration between repositories
Repository Layer
- Data access via Spring Data JPA
- Custom query methods
- Pagination and sorting support
Domain/Entity Layer
- JPA entities with proper annotations
- Entity relationships
- Validation constraints
2. DTO Pattern
Separate DTOs for:
- Request DTOs (for creating/updating)
- Response DTOs (for API responses)
- Never expose entities directly in REST APIs
- Use MapStruct for entity-DTO conversion
Example:
@Mapper(componentModel = "spring")
public interface ExerciseMapper {
ExerciseResponseDTO toResponseDTO(Exercise exercise);
Exercise toEntity(ExerciseCreateDTO dto);
}
3. Repository Pattern
@Repository
public interface ExerciseRepository extends JpaRepository<Exercise, Long> {
List<Exercise> findByTagsContaining(Tag tag);
Page<Exercise> findByTitleContainingIgnoreCase(String title, Pageable pageable);
@Query("SELECT e FROM Exercise e WHERE :tag MEMBER OF e.tags")
List<Exercise> findByTag(@Param("tag") Tag tag);
}
4. Service Layer Pattern
@Service
@Transactional
@RequiredArgsConstructor
public class ExerciseService {
private final ExerciseRepository exerciseRepository;
private final TagRepository tagRepository;
private final ExerciseMapper exerciseMapper;
public ExerciseResponseDTO createExercise(ExerciseCreateDTO dto) {
// Business logic here
}
}
5. Exception Handling
Global exception handler:
@ControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(ResourceNotFoundException.class)
public ResponseEntity<ErrorResponse> handleResourceNotFound(ResourceNotFoundException ex) {
return ResponseEntity.status(HttpStatus.NOT_FOUND)
.body(new ErrorResponse(ex.getMessage()));
}
}
REST API Endpoints
Exercise Management
GET /api/exercises- List all exercises (paginated, filterable by tags)GET /api/exercises/{id}- Get single exercisePOST /api/exercises- Create new exercisePUT /api/exercises/{id}- Update exerciseDELETE /api/exercises/{id}- Delete exercise
Tag Management
GET /api/tags- List all tagsPOST /api/tags- Create new tagPUT /api/tags/{id}- Update tagDELETE /api/tags/{id}- Delete tag
User Management
GET /api/users- List all users (admin only)GET /api/users/{id}- Get user profilePOST /api/users- Create new userPUT /api/users/{id}- Update userDELETE /api/users/{id}- Delete user
Weekly Plan Management
GET /api/plans- List all plans for current userGET /api/plans/{id}- Get specific planPOST /api/plans- Create new weekly planPUT /api/plans/{id}- Update planDELETE /api/plans/{id}- Delete plan
Exercise Completion Tracking
GET /api/completions- Get completions for current user (filterable by date range)POST /api/completions- Mark exercise as completedGET /api/dashboard/stats- Get dashboard statistics
Authentication
POST /api/auth/login- User login (returns JWT token)POST /api/auth/register- User registrationPOST /api/auth/logout- User logout
Key Dependencies (Spring Boot)
<!-- Core -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
<!-- Database -->
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.flywaydb</groupId>
<artifactId>flyway-core</artifactId>
</dependency>
<!-- Utilities -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct</artifactId>
<version>1.5.5.Final</version>
</dependency>
<!-- JWT -->
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-api</artifactId>
<version>0.12.3</version>
</dependency>
Docker Configuration
Development (docker-compose.yml)
version: '3.8'
services:
db:
image: postgres:16-alpine
container_name: celticus-db
environment:
POSTGRES_DB: celticus
POSTGRES_USER: celticus
POSTGRES_PASSWORD: dev_password
ports:
- "5432:5432"
volumes:
- postgres_data:/var/lib/postgresql/data
networks:
- celticus-network
backend:
build: ./backend
container_name: celticus-backend
ports:
- "8080:8080"
depends_on:
- db
environment:
SPRING_PROFILES_ACTIVE: dev
SPRING_DATASOURCE_URL: jdbc:postgresql://db:5432/celticus
SPRING_DATASOURCE_USERNAME: celticus
SPRING_DATASOURCE_PASSWORD: dev_password
networks:
- celticus-network
volumes:
postgres_data:
networks:
celticus-network:
Backend Dockerfile
FROM eclipse-temurin:17-jdk-alpine AS build
WORKDIR /app
COPY pom.xml .
COPY src ./src
RUN ./mvnw clean package -DskipTests
FROM eclipse-temurin:17-jre-alpine
WORKDIR /app
COPY --from=build /app/target/*.jar app.jar
EXPOSE 8080
ENTRYPOINT ["java", "-jar", "app.jar"]
Frontend Structure
Key Pages
login.html
- Simple login form
- JWT token storage in localStorage
- Redirect to index.html on success
index.html
- Main dashboard
- Weekly plan overview
- Quick stats (exercises completed this week)
- Navigation to other sections
exercises.html
- List all exercises with search/filter by tags
- Add/edit/delete exercises (admin/therapist only)
- View exercise details with video
plans.html
- View current weekly plan
- Check off completed exercises
- View past plans
dashboard.html
- Completion statistics over time
- Charts showing progress (can use Chart.js)
- Streak tracking
Frontend JavaScript Modules
api.js - API client wrapper
const API_BASE_URL = 'http://localhost:8080/api';
async function request(endpoint, options = {}) {
const token = localStorage.getItem('jwt_token');
const headers = {
'Content-Type': 'application/json',
...(token && { 'Authorization': `Bearer {{token}}` }),
...options.headers
};
const response = await fetch(`{{API_BASE_URL}}{{endpoint}}`, {
...options,
headers
});
if (!response.ok) {
throw new Error(`HTTP error! status: {{response_status}}`);
}
return response.json();
}
Implementation Steps
Phase 1: Backend Foundation
- Initialize Spring Boot project with dependencies
- Configure application.yml (dev/prod profiles)
- Set up PostgreSQL connection
- Create domain entities with JPA annotations
- Implement repositories
- Create Flyway migration scripts
Phase 2: Backend Business Logic
- Implement service layer for each entity
- Create DTOs and mappers
- Build REST controllers
- Add validation and exception handling
- Configure Spring Security with JWT
- Add CORS configuration
Phase 3: Frontend Development
- Create HTML page structure
- Implement CSS styling (Bootstrap/Tailwind)
- Build JavaScript API client
- Implement authentication flow
- Create exercise management UI
- Build weekly plan interface
- Develop dashboard with statistics
Phase 4: Docker & Deployment
- Create backend Dockerfile
- Set up docker-compose for development
- Test full stack locally
- Create production docker-compose
- Add nginx for serving frontend (optional)
- Document deployment process
Phase 5: Testing & Refinement
- Add unit tests for services
- Add integration tests for repositories
- Test REST API endpoints
- Frontend testing and bug fixes
- Performance optimization
- Security audit
Design Decisions & Considerations
Video Storage Strategy
Options:
-
File System with Docker volumes (simple, low maintenance)
- Store videos in
/app/videosdirectory - Mount as Docker volume for persistence
- Serve via Spring Boot static resources
- Store videos in
-
External Object Storage (scalable, better for production)
- Use MinIO (self-hosted S3-compatible)
- Store only URLs in database
- Better for large video files
Recommendation: Start with file system, migrate to object storage if needed.
Authentication Approach
JWT Token-based Authentication
- Stateless, scalable
- Token stored in localStorage
- Refresh token mechanism for long sessions
- Role-based access control (ADMIN, THERAPIST, PATIENT)
Weekly Plan Generation
Options:
- Manual creation by therapist/admin
- Template-based (predefined plan templates)
- Rule-based auto-generation (based on user goals/conditions)
Recommendation: Start with manual creation, add templates in phase 2.
Database Schema Considerations
- Use UUID for primary keys (better for distributed systems) OR Long (simpler, sequential)
- Soft delete pattern for exercises (keep history)
- Audit fields (createdBy, updatedBy, createdDate, updatedDate)
- Index frequently queried fields (username, email, weekStartDate)
Security Considerations
- Password hashing with BCrypt (min strength 12)
- HTTPS only in production
- CORS configuration for frontend domain
- Rate limiting on login endpoint
- Input validation and sanitization
- SQL injection prevention (JPA handles this)
- XSS prevention in frontend
Future Enhancements
- Mobile App - React Native or Flutter
- Exercise Library - Import from external sources
- Progress Photos - Before/after photos for tracking
- Notifications - Email/push reminders for exercises
- Social Features - Share progress, community support
- Analytics - Advanced statistics and insights
- Exercise Recommendations - AI-based suggestions
- Multi-language Support - i18n for German/English
- Exercise Calendar - Visual calendar view
- Export/Import - Backup and restore data
Maintenance & Operations
Backup Strategy
- Automated PostgreSQL backups (daily)
- Store backups in separate volume/location
- Test restore procedure regularly
Monitoring
- Spring Boot Actuator for health checks
- Log aggregation (ELK stack or similar)
- Performance metrics (response times, DB queries)
Updates
- Flyway handles database migrations automatically
- Rolling updates for backend (zero downtime)
- Version API endpoints if breaking changes needed
Documentation
- API documentation with Swagger/OpenAPI
- README for setup and deployment
- Architecture decision records (ADRs)
- Code comments for complex logic
Success Metrics
- Clean, maintainable codebase
- Fast API response times (<100ms for most endpoints)
- Simple deployment process (docker-compose up)
- Low operational overhead
- Easy to add new features
- Good test coverage (>70%)
- Intuitive user interface
- Reliable data persistence