Add project management support and integrate customer-project functionality
This commit is contained in:
@@ -0,0 +1,63 @@
|
||||
package dev.rheinsw.server.project.controller;
|
||||
|
||||
import dev.rheinsw.server.common.controller.AbstractController;
|
||||
import dev.rheinsw.server.project.model.CreateCustomerProjectDto;
|
||||
import dev.rheinsw.server.project.model.Project;
|
||||
import dev.rheinsw.server.project.model.records.ProjectNote;
|
||||
import dev.rheinsw.server.project.usecase.ProjectUseCaseImpl;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import java.time.Instant;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* @author Thatsaphorn Atchariyaphap
|
||||
* @since 12.07.25
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/projects")
|
||||
@RequiredArgsConstructor
|
||||
public class ProjectController extends AbstractController {
|
||||
|
||||
private final ProjectUseCaseImpl useCase;
|
||||
|
||||
@PostMapping
|
||||
public ResponseEntity<UUID> create(@RequestBody CreateCustomerProjectDto request) {
|
||||
var currentUser = getUserFromCurrentSession();
|
||||
|
||||
var now = Instant.now();
|
||||
var notes = request.notes().stream().map(n -> new ProjectNote(n.text(), currentUser.getId(), currentUser.getId(), now, now)).toList();
|
||||
|
||||
var result = useCase.createProject(
|
||||
currentUser,
|
||||
request.customerId(),
|
||||
request.name(),
|
||||
request.description(),
|
||||
request.status(),
|
||||
notes
|
||||
);
|
||||
|
||||
return ResponseEntity.ok(result);
|
||||
}
|
||||
|
||||
@GetMapping
|
||||
public ResponseEntity<Project> findProjectById(@PathVariable("id") UUID id) {
|
||||
var result = useCase.getProjectById(id);
|
||||
return ResponseEntity.ok(result);
|
||||
}
|
||||
|
||||
@GetMapping("/customer/{customerId}")
|
||||
public ResponseEntity<List<Project>> findAllCustomerProjects(@PathVariable("customerId") UUID customerId) {
|
||||
var result = useCase.getProjectsByCustomerId(customerId);
|
||||
return ResponseEntity.ok(result);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
package dev.rheinsw.server.project.model;
|
||||
|
||||
import dev.rheinsw.server.project.model.enums.ProjectStatus;
|
||||
|
||||
import java.time.LocalDate;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* @author Thatsaphorn Atchariyaphap
|
||||
* @since 13.07.25
|
||||
*/
|
||||
public record CreateCustomerProjectDto(
|
||||
UUID customerId, // Reference to the related customer
|
||||
String name, // Project name
|
||||
String description, // Optional project description
|
||||
ProjectStatus status, // Enum for project status
|
||||
List<ProjectNoteDto> notes, // Optional list of project notes
|
||||
LocalDate startDate // Project start date
|
||||
) {
|
||||
|
||||
public record ProjectNoteDto(
|
||||
String text // Note text
|
||||
) {
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
package dev.rheinsw.server.project.model;
|
||||
|
||||
import com.vladmihalcea.hibernate.type.json.JsonType;
|
||||
import dev.rheinsw.server.common.entity.BaseEntity;
|
||||
import dev.rheinsw.server.project.model.enums.ProjectStatus;
|
||||
import dev.rheinsw.server.project.model.records.ProjectNote;
|
||||
import jakarta.persistence.Column;
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.EnumType;
|
||||
import jakarta.persistence.Enumerated;
|
||||
import jakarta.persistence.Id;
|
||||
import jakarta.persistence.Table;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.Setter;
|
||||
import org.hibernate.annotations.Type;
|
||||
|
||||
import java.time.Instant;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* @author Thatsaphorn Atchariyaphap
|
||||
* @since 12.07.25
|
||||
*/
|
||||
@Entity
|
||||
@Table(name = "project")
|
||||
@Getter
|
||||
@Setter
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Builder
|
||||
public class Project extends BaseEntity {
|
||||
|
||||
@Id
|
||||
private UUID id;
|
||||
|
||||
private UUID customerId;
|
||||
|
||||
private String name;
|
||||
private String description;
|
||||
|
||||
@Enumerated(EnumType.STRING)
|
||||
private ProjectStatus status;
|
||||
|
||||
@Column(name = "notes", columnDefinition = "jsonb")
|
||||
@Type(JsonType.class)
|
||||
private List<ProjectNote> notes;
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
package dev.rheinsw.server.project.model.enums;
|
||||
|
||||
/**
|
||||
* @author Thatsaphorn Atchariyaphap
|
||||
* @since 12.07.25
|
||||
*/
|
||||
public enum ProjectStatus {
|
||||
PLANNED,
|
||||
IN_PROGRESS,
|
||||
COMPLETED,
|
||||
ON_HOLD,
|
||||
CANCELLED
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
package dev.rheinsw.server.project.model.records;
|
||||
|
||||
import java.time.Instant;
|
||||
|
||||
/**
|
||||
* @author Thatsaphorn Atchariyaphap
|
||||
* @since 12.07.25
|
||||
*/
|
||||
public record ProjectNote(String text,
|
||||
Long createdBy,
|
||||
Long updatedBy,
|
||||
Instant createdAt,
|
||||
Instant updatedAt) {
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package dev.rheinsw.server.project.repository;
|
||||
|
||||
import dev.rheinsw.server.customer.model.Customer;
|
||||
import dev.rheinsw.server.project.model.Project;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* @author Thatsaphorn Atchariyaphap
|
||||
* @since 12.07.25
|
||||
*/
|
||||
public interface ProjectRepository extends JpaRepository<Project, UUID> {
|
||||
List<Project> findByCustomerId(UUID customerId);
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
package dev.rheinsw.server.project.usecase;
|
||||
|
||||
import dev.rheinsw.server.common.entity.User;
|
||||
import dev.rheinsw.server.project.model.enums.ProjectStatus;
|
||||
import dev.rheinsw.server.project.model.records.ProjectNote;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* @author Thatsaphorn Atchariyaphap
|
||||
* @since 13.07.25
|
||||
*/
|
||||
public interface CreateProjectUseCase {
|
||||
UUID createProject(
|
||||
User creator,
|
||||
UUID customerId,
|
||||
String name,
|
||||
String description,
|
||||
ProjectStatus status,
|
||||
List<ProjectNote> notes
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package dev.rheinsw.server.project.usecase;
|
||||
|
||||
import dev.rheinsw.server.project.model.Project;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* @author Thatsaphorn Atchariyaphap
|
||||
* @since 12.07.25
|
||||
*/
|
||||
public interface LoadProjectUseCase {
|
||||
Project getProjectById(UUID id);
|
||||
|
||||
List<Project> getProjectsByCustomerId(UUID customerId);
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
package dev.rheinsw.server.project.usecase;
|
||||
|
||||
import dev.rheinsw.server.common.entity.User;
|
||||
import dev.rheinsw.server.project.model.Project;
|
||||
import dev.rheinsw.server.project.model.enums.ProjectStatus;
|
||||
import dev.rheinsw.server.project.model.records.ProjectNote;
|
||||
import dev.rheinsw.server.project.repository.ProjectRepository;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.time.Instant;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* @author Thatsaphorn Atchariyaphap
|
||||
* @since 12.07.25
|
||||
*/
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class ProjectUseCaseImpl implements LoadProjectUseCase, CreateProjectUseCase {
|
||||
|
||||
private final ProjectRepository repository;
|
||||
|
||||
@Override
|
||||
public UUID createProject(
|
||||
User creator,
|
||||
UUID customerId,
|
||||
String name,
|
||||
String description,
|
||||
ProjectStatus status,
|
||||
List<ProjectNote> notes
|
||||
) {
|
||||
final var now = Instant.now();
|
||||
var enrichedNotes = notes.stream()
|
||||
.map(n -> new ProjectNote(n.text(), creator.getId(), creator.getId(), now, now))
|
||||
.toList();
|
||||
|
||||
Project project = Project.builder()
|
||||
.id(UUID.randomUUID())
|
||||
.customerId(customerId)
|
||||
.name(name)
|
||||
.description(description)
|
||||
.status(status)
|
||||
.notes(enrichedNotes)
|
||||
.build();
|
||||
|
||||
var savedProject = repository.save(project);
|
||||
return savedProject.getId();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Project getProjectById(UUID id) {
|
||||
return repository.findById(id).orElse(null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Project> getProjectsByCustomerId(UUID customerId) {
|
||||
return repository.findByCustomerId(customerId);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
-- Migration script for Project table and related components
|
||||
CREATE TABLE project
|
||||
(
|
||||
id UUID PRIMARY KEY,
|
||||
customer_id UUID NOT NULL,
|
||||
name VARCHAR(255) NOT NULL,
|
||||
description TEXT,
|
||||
status VARCHAR(50) NOT NULL, -- ProjectStatus enum
|
||||
notes JSONB, -- JSONB for storing ProjectNotes list
|
||||
start_date VARCHAR(50),
|
||||
end_date VARCHAR(50),
|
||||
created_at TIMESTAMP NOT NULL, -- From BaseEntity
|
||||
updated_at TIMESTAMP, -- From BaseEntity
|
||||
created_by BIGINT, -- From BaseEntity
|
||||
updated_by BIGINT, -- From BaseEntity
|
||||
version BIGINT -- From BaseEntity
|
||||
);
|
||||
|
||||
-- Adding a CHECK constraint to enforce valid ProjectStatus values
|
||||
ALTER TABLE project
|
||||
ADD CONSTRAINT chk_project_status
|
||||
CHECK (status IN ('PLANNED', 'IN_PROGRESS', 'COMPLETED', 'ON_HOLD', 'CANCELLED'));
|
||||
Reference in New Issue
Block a user