542 lines
17 KiB
Markdown
542 lines
17 KiB
Markdown
# Story 2: Application Management
|
|
|
|
## Story Overview
|
|
|
|
**As a** application manager
|
|
**I want** to manage applications in the system
|
|
**So that** I can track all applications and their lifecycle status
|
|
|
|
**Story Type**: Feature (Core Domain)
|
|
**Priority**: Highest
|
|
**Estimated Effort**: 5-7 days
|
|
**Dependencies**: Story 1 (Business Units)
|
|
|
|
---
|
|
|
|
## Business Value
|
|
|
|
Applications are the central entity in LDPv2. This story enables:
|
|
- Complete application inventory
|
|
- Lifecycle status tracking (IDEA → IN_DEVELOPMENT → IN_SERVICE → MAINTENANCE → DECOMMISSIONED)
|
|
- Business unit ownership
|
|
- Foundation for deployment tracking (Story 6)
|
|
- End-of-life and support tracking
|
|
|
|
---
|
|
|
|
## Scope
|
|
|
|
### In Scope
|
|
✅ Application CRUD operations
|
|
✅ Lifecycle status management
|
|
✅ Business unit association
|
|
✅ End-of-life and end-of-support date tracking
|
|
✅ Application search and filtering
|
|
✅ Status-based filtering
|
|
|
|
### Out of Scope
|
|
❌ Version management (Story 5)
|
|
❌ Deployment tracking (Story 6)
|
|
❌ Contact/stakeholder management (Story 3)
|
|
❌ SLA management (Phase 2)
|
|
❌ Technical documentation (Phase 2)
|
|
❌ External dependencies (Phase 2)
|
|
|
|
---
|
|
|
|
## Technical Implementation
|
|
|
|
### Backend Tasks
|
|
|
|
#### 1. Database Migration
|
|
- [ ] Create Liquibase migration: `004-create-application-tables.xml`
|
|
- [ ] Create `application` table:
|
|
```sql
|
|
- id (UUID, PK)
|
|
- name (VARCHAR(255), not null)
|
|
- description (TEXT, nullable)
|
|
- status (VARCHAR(50), not null) -- IDEA, IN_DEVELOPMENT, IN_SERVICE, MAINTENANCE, DECOMMISSIONED
|
|
- business_unit_id (UUID, FK to business_unit, not null)
|
|
- end_of_life_date (DATE, nullable)
|
|
- end_of_support_date (DATE, nullable)
|
|
- created_at (TIMESTAMP, not null)
|
|
- updated_at (TIMESTAMP, not null)
|
|
```
|
|
- [ ] Add indexes:
|
|
- `idx_application_status` on status
|
|
- `idx_application_business_unit` on business_unit_id
|
|
- `idx_application_name` on name (for search)
|
|
- [ ] Add foreign key constraint: `business_unit_id` → `business_unit(id)`
|
|
- [ ] Insert sample data (5-10 applications with various statuses)
|
|
|
|
#### 2. Enum
|
|
- [ ] Create `ApplicationStatus` enum:
|
|
```java
|
|
public enum ApplicationStatus {
|
|
IDEA("Idea"),
|
|
IN_DEVELOPMENT("In Development"),
|
|
IN_SERVICE("In Service"),
|
|
MAINTENANCE("Maintenance"),
|
|
DECOMMISSIONED("Decommissioned");
|
|
|
|
private final String displayName;
|
|
// Constructor, getter
|
|
}
|
|
```
|
|
|
|
#### 3. JPA Entity
|
|
- [ ] Create `Application` entity extending `BaseEntity`:
|
|
```java
|
|
@Entity
|
|
@Table(name = "application")
|
|
public class Application extends BaseEntity {
|
|
@Column(nullable = false)
|
|
private String name;
|
|
|
|
@Column(columnDefinition = "TEXT")
|
|
private String description;
|
|
|
|
@Enumerated(EnumType.STRING)
|
|
@Column(nullable = false, length = 50)
|
|
private ApplicationStatus status;
|
|
|
|
@ManyToOne(fetch = FetchType.LAZY)
|
|
@JoinColumn(name = "business_unit_id", nullable = false)
|
|
private BusinessUnit businessUnit;
|
|
|
|
@Column(name = "end_of_life_date")
|
|
private LocalDate endOfLifeDate;
|
|
|
|
@Column(name = "end_of_support_date")
|
|
private LocalDate endOfSupportDate;
|
|
|
|
// Getters, setters, constructors
|
|
}
|
|
```
|
|
|
|
#### 4. Repository Layer
|
|
- [ ] Create `ApplicationRepository`:
|
|
```java
|
|
public interface ApplicationRepository extends JpaRepository<Application, UUID> {
|
|
Page<Application> findByStatus(ApplicationStatus status, Pageable pageable);
|
|
Page<Application> findByBusinessUnitId(UUID businessUnitId, Pageable pageable);
|
|
Page<Application> findByNameContainingIgnoreCase(String name, Pageable pageable);
|
|
Page<Application> findByStatusAndBusinessUnitId(ApplicationStatus status, UUID businessUnitId, Pageable pageable);
|
|
|
|
@Query("SELECT a FROM Application a WHERE " +
|
|
"(:status IS NULL OR a.status = :status) AND " +
|
|
"(:businessUnitId IS NULL OR a.businessUnit.id = :businessUnitId) AND " +
|
|
"(:name IS NULL OR LOWER(a.name) LIKE LOWER(CONCAT('%', :name, '%')))")
|
|
Page<Application> search(
|
|
@Param("status") ApplicationStatus status,
|
|
@Param("businessUnitId") UUID businessUnitId,
|
|
@Param("name") String name,
|
|
Pageable pageable
|
|
);
|
|
}
|
|
```
|
|
|
|
#### 5. DTOs
|
|
- [ ] Create `CreateApplicationRequest`:
|
|
- `name` (required, max 255 chars)
|
|
- `description` (optional)
|
|
- `status` (required, default: IDEA)
|
|
- `businessUnitId` (required, UUID)
|
|
- `endOfLifeDate` (optional, LocalDate)
|
|
- `endOfSupportDate` (optional, LocalDate)
|
|
- [ ] Create `UpdateApplicationRequest`:
|
|
- All fields optional (partial update support)
|
|
- [ ] Create `ApplicationResponse`:
|
|
- `id`, `name`, `description`, `status`, `businessUnit` (summary), `endOfLifeDate`, `endOfSupportDate`, `createdAt`, `updatedAt`
|
|
- [ ] Create `ApplicationSummaryResponse` (for lists):
|
|
- `id`, `name`, `status`, `businessUnitName`
|
|
- [ ] Create `BusinessUnitSummaryDto`:
|
|
- `id`, `name`
|
|
|
|
#### 6. Service Layer
|
|
- [ ] Create `ApplicationService` with methods:
|
|
```java
|
|
ApplicationResponse create(CreateApplicationRequest request);
|
|
ApplicationResponse update(UUID id, UpdateApplicationRequest request);
|
|
ApplicationResponse findById(UUID id);
|
|
Page<ApplicationResponse> findAll(Pageable pageable);
|
|
Page<ApplicationResponse> search(ApplicationStatus status, UUID businessUnitId, String name, Pageable pageable);
|
|
Page<ApplicationResponse> findByStatus(ApplicationStatus status, Pageable pageable);
|
|
Page<ApplicationResponse> findByBusinessUnit(UUID businessUnitId, Pageable pageable);
|
|
void delete(UUID id);
|
|
ApplicationResponse updateStatus(UUID id, ApplicationStatus newStatus);
|
|
```
|
|
- [ ] Implement business logic:
|
|
- Validate business unit exists on create/update
|
|
- Validate end-of-support date is before end-of-life date
|
|
- Throw exceptions for invalid states
|
|
- Map entities to DTOs (consider using MapStruct or ModelMapper)
|
|
|
|
#### 7. Controller Layer
|
|
- [ ] Create `ApplicationController` with endpoints:
|
|
```java
|
|
GET /api/applications - List all (with filters)
|
|
GET /api/applications/search - Advanced search
|
|
GET /api/applications/{id} - Get by ID
|
|
POST /api/applications - Create new
|
|
PUT /api/applications/{id} - Update
|
|
PATCH /api/applications/{id}/status - Update status only
|
|
DELETE /api/applications/{id} - Delete
|
|
GET /api/applications/by-status/{status} - Filter by status
|
|
GET /api/applications/by-business-unit/{businessUnitId} - Filter by BU
|
|
```
|
|
- [ ] Add query parameters for filtering:
|
|
- `status`: Filter by status
|
|
- `businessUnitId`: Filter by business unit
|
|
- `name`: Search by name
|
|
- `page`, `size`, `sort`: Pagination
|
|
- [ ] Add validation annotations
|
|
- [ ] Add Swagger/OpenAPI annotations
|
|
- [ ] Add security: require authentication
|
|
|
|
#### 8. Testing
|
|
- [ ] Unit tests for `ApplicationService`:
|
|
- Test create application
|
|
- Test create with invalid business unit (should fail)
|
|
- Test update application
|
|
- Test update status
|
|
- Test search with various filters
|
|
- Test validation (end-of-support before end-of-life)
|
|
- [ ] Integration tests for `ApplicationController`:
|
|
- Test full CRUD flow
|
|
- Test filtering by status
|
|
- Test filtering by business unit
|
|
- Test search functionality
|
|
- Test pagination and sorting
|
|
- Test error cases (404, 400)
|
|
- [ ] Test coverage > 80%
|
|
|
|
---
|
|
|
|
### Frontend Tasks
|
|
|
|
#### 1. Models
|
|
- [ ] Create `application.model.ts`:
|
|
```typescript
|
|
export enum ApplicationStatus {
|
|
IDEA = 'IDEA',
|
|
IN_DEVELOPMENT = 'IN_DEVELOPMENT',
|
|
IN_SERVICE = 'IN_SERVICE',
|
|
MAINTENANCE = 'MAINTENANCE',
|
|
DECOMMISSIONED = 'DECOMMISSIONED'
|
|
}
|
|
|
|
export interface Application {
|
|
id: string;
|
|
name: string;
|
|
description?: string;
|
|
status: ApplicationStatus;
|
|
businessUnit: { id: string; name: string };
|
|
endOfLifeDate?: Date;
|
|
endOfSupportDate?: Date;
|
|
createdAt: Date;
|
|
updatedAt: Date;
|
|
}
|
|
|
|
export interface CreateApplicationRequest {
|
|
name: string;
|
|
description?: string;
|
|
status: ApplicationStatus;
|
|
businessUnitId: string;
|
|
endOfLifeDate?: Date;
|
|
endOfSupportDate?: Date;
|
|
}
|
|
|
|
export interface UpdateApplicationRequest {
|
|
name?: string;
|
|
description?: string;
|
|
status?: ApplicationStatus;
|
|
businessUnitId?: string;
|
|
endOfLifeDate?: Date;
|
|
endOfSupportDate?: Date;
|
|
}
|
|
```
|
|
|
|
#### 2. Service
|
|
- [ ] Create `application.service.ts`:
|
|
```typescript
|
|
@Injectable({ providedIn: 'root' })
|
|
export class ApplicationService {
|
|
getApplications(filters?, page?, size?, sort?): Observable<Page<Application>>
|
|
searchApplications(criteria): Observable<Page<Application>>
|
|
getApplication(id): Observable<Application>
|
|
createApplication(data): Observable<Application>
|
|
updateApplication(id, data): Observable<Application>
|
|
updateStatus(id, status): Observable<Application>
|
|
deleteApplication(id): Observable<void>
|
|
}
|
|
```
|
|
|
|
#### 3. Components
|
|
|
|
##### ApplicationListComponent
|
|
- [ ] Create component with template and styles
|
|
- [ ] Features:
|
|
- Table view with columns: Name, Status, Business Unit, End of Life, Actions
|
|
- Status badge with color coding:
|
|
- IDEA: blue
|
|
- IN_DEVELOPMENT: yellow
|
|
- IN_SERVICE: green
|
|
- MAINTENANCE: orange
|
|
- DECOMMISSIONED: gray
|
|
- Filters:
|
|
- Status dropdown (All, IDEA, IN_DEVELOPMENT, IN_SERVICE, MAINTENANCE, DECOMMISSIONED)
|
|
- Business unit dropdown (All + list of BUs)
|
|
- Search by name
|
|
- Pagination controls (20 items per page)
|
|
- Sort by name, status, created date
|
|
- "Create New Application" button
|
|
- Actions per row: View, Edit, Delete, Change Status
|
|
- [ ] Implement logic:
|
|
- Load applications on init
|
|
- Apply filters reactively
|
|
- Handle pagination and sorting
|
|
- Handle search with debounce
|
|
- Quick status change dropdown
|
|
- Navigate to detail/form pages
|
|
- Handle delete with confirmation
|
|
|
|
##### ApplicationDetailComponent
|
|
- [ ] Create component with template and styles
|
|
- [ ] Features:
|
|
- Display all application details
|
|
- Status badge (colored)
|
|
- Business unit link (navigate to BU detail)
|
|
- Show end-of-life and end-of-support dates (highlight if approaching)
|
|
- "Edit" button
|
|
- "Change Status" dropdown
|
|
- "Delete" button
|
|
- "Back to List" button
|
|
- Tabs (for future: Versions, Deployments, Contacts)
|
|
- [ ] Load application by ID from route params
|
|
- [ ] Reload on status change
|
|
|
|
##### ApplicationFormComponent
|
|
- [ ] Create component with template and styles
|
|
- [ ] Reactive form with fields:
|
|
- Name (required, max 255 chars)
|
|
- Description (optional, textarea)
|
|
- Status (required, dropdown)
|
|
- Business Unit (required, dropdown - load from API)
|
|
- End of Life Date (optional, date picker)
|
|
- End of Support Date (optional, date picker)
|
|
- [ ] Form validation:
|
|
- Name required
|
|
- Status required
|
|
- Business unit required
|
|
- End of support date must be before end of life date
|
|
- Show validation errors
|
|
- [ ] Support both create and edit modes
|
|
- [ ] Handle form submission
|
|
- [ ] "Cancel" button
|
|
|
|
#### 4. Shared Components
|
|
- [ ] Create `StatusBadgeComponent`:
|
|
- Input: status (ApplicationStatus)
|
|
- Display colored badge based on status
|
|
- Reusable across application views
|
|
|
|
#### 5. Routing
|
|
- [ ] Add routes:
|
|
```typescript
|
|
{
|
|
path: 'applications',
|
|
canActivate: [AuthGuard],
|
|
children: [
|
|
{ path: '', component: ApplicationListComponent },
|
|
{ path: 'new', component: ApplicationFormComponent },
|
|
{ path: ':id', component: ApplicationDetailComponent },
|
|
{ path: ':id/edit', component: ApplicationFormComponent }
|
|
]
|
|
}
|
|
```
|
|
|
|
#### 6. Navigation
|
|
- [ ] Add "Applications" link to header/sidebar (prominent position)
|
|
|
|
#### 7. Testing
|
|
- [ ] Unit tests for `ApplicationService`
|
|
- [ ] Component tests for `ApplicationListComponent`:
|
|
- Test rendering
|
|
- Test filters (status, business unit, search)
|
|
- Test pagination
|
|
- Test status change
|
|
- [ ] Component tests for `ApplicationFormComponent`:
|
|
- Test form validation
|
|
- Test date validation (end-of-support before end-of-life)
|
|
- Test create and edit modes
|
|
- [ ] E2E tests:
|
|
- Create application flow
|
|
- Edit application flow
|
|
- Change status flow
|
|
- Filter and search flow
|
|
- [ ] Test coverage > 70%
|
|
|
|
---
|
|
|
|
## Acceptance Criteria
|
|
|
|
### Backend
|
|
- [ ] Application can be created with all required fields
|
|
- [ ] Application creation fails if business unit doesn't exist
|
|
- [ ] Application can be updated (partial updates supported)
|
|
- [ ] Application status can be updated independently
|
|
- [ ] Application can be deleted
|
|
- [ ] Applications can be listed with pagination
|
|
- [ ] Applications can be filtered by status
|
|
- [ ] Applications can be filtered by business unit
|
|
- [ ] Applications can be searched by name
|
|
- [ ] Advanced search combines multiple filters
|
|
- [ ] End-of-support date validation (must be before end-of-life)
|
|
- [ ] All endpoints authenticated
|
|
- [ ] API documented in Swagger
|
|
|
|
### Frontend
|
|
- [ ] User can view list of all applications
|
|
- [ ] List shows application name, status, business unit
|
|
- [ ] Status is displayed with colored badge
|
|
- [ ] User can filter applications by status
|
|
- [ ] User can filter applications by business unit
|
|
- [ ] User can search applications by name
|
|
- [ ] Filters work together (combined)
|
|
- [ ] List supports pagination and sorting
|
|
- [ ] User can create new application
|
|
- [ ] Form validates all required fields
|
|
- [ ] Form validates date logic (end-of-support before end-of-life)
|
|
- [ ] User can view application details
|
|
- [ ] User can edit existing application
|
|
- [ ] User can change application status from list or detail view
|
|
- [ ] User can delete application (with confirmation)
|
|
- [ ] Approaching end-of-life dates are highlighted
|
|
- [ ] Success/error notifications displayed
|
|
- [ ] Navigation is intuitive
|
|
|
|
### Testing
|
|
- [ ] Backend tests pass (>80% coverage)
|
|
- [ ] Frontend tests pass (>70% coverage)
|
|
- [ ] E2E tests pass
|
|
|
|
---
|
|
|
|
## Testing Scenarios
|
|
|
|
### Scenario 1: Create Application
|
|
1. Navigate to applications list
|
|
2. Click "Create New Application"
|
|
3. Fill in form:
|
|
- Name: "Customer Portal"
|
|
- Description: "External customer-facing portal"
|
|
- Status: IN_DEVELOPMENT
|
|
- Business Unit: Select "Digital Services"
|
|
- End of Support: 2028-12-31
|
|
- End of Life: 2030-12-31
|
|
4. Click "Save"
|
|
5. Verify success notification
|
|
6. Verify redirect to application list
|
|
7. Verify new application appears with IN_DEVELOPMENT badge (yellow)
|
|
|
|
### Scenario 2: Filter Applications
|
|
1. Navigate to applications list
|
|
2. Select status filter: "IN_SERVICE"
|
|
3. Verify only IN_SERVICE applications shown
|
|
4. Select business unit filter: "Digital Services"
|
|
5. Verify only IN_SERVICE applications from Digital Services shown
|
|
6. Clear filters
|
|
7. Verify all applications shown
|
|
|
|
### Scenario 3: Search Applications
|
|
1. Navigate to applications list
|
|
2. Enter search query: "portal"
|
|
3. Wait for debounce
|
|
4. Verify results contain only matching applications
|
|
5. Clear search
|
|
6. Verify all applications shown
|
|
|
|
### Scenario 4: Change Application Status
|
|
1. Navigate to applications list
|
|
2. Click "Change Status" dropdown on an application
|
|
3. Select new status: "IN_SERVICE"
|
|
4. Verify success notification
|
|
5. Verify status badge updated to green
|
|
6. Refresh page
|
|
7. Verify status persisted
|
|
|
|
### Scenario 5: Edit Application
|
|
1. Navigate to application detail page
|
|
2. Click "Edit"
|
|
3. Modify description and end-of-life date
|
|
4. Click "Save"
|
|
5. Verify success notification
|
|
6. Verify changes reflected in detail view
|
|
|
|
### Scenario 6: Date Validation
|
|
1. Navigate to create/edit application form
|
|
2. Set End of Support: 2030-12-31
|
|
3. Set End of Life: 2028-12-31 (before end-of-support)
|
|
4. Attempt to save
|
|
5. Verify validation error: "End of support must be before end of life"
|
|
6. Correct dates
|
|
7. Verify form can be saved
|
|
|
|
### Scenario 7: Delete Application
|
|
1. Navigate to application detail page
|
|
2. Click "Delete"
|
|
3. Confirm deletion
|
|
4. Verify success notification
|
|
5. Verify redirect to application list
|
|
6. Verify application removed from list
|
|
|
|
---
|
|
|
|
## Definition of Done
|
|
|
|
- [ ] All backend tasks completed
|
|
- [ ] All frontend tasks completed
|
|
- [ ] All acceptance criteria met
|
|
- [ ] All tests passing (unit, integration, E2E)
|
|
- [ ] Code reviewed and approved
|
|
- [ ] API documented in Swagger
|
|
- [ ] User can perform all operations via UI
|
|
- [ ] Demo conducted successfully
|
|
- [ ] Code merged to main branch
|
|
|
|
---
|
|
|
|
## Technical Debt & Future Improvements
|
|
|
|
### Known Limitations
|
|
- No application archiving (only hard delete)
|
|
- No status change audit trail
|
|
- No automated end-of-life notifications
|
|
- No application tags/categories
|
|
|
|
### Future Enhancements
|
|
- Implement soft delete with archiving
|
|
- Add status change history/audit log
|
|
- Add automated alerts for approaching end-of-life
|
|
- Add tagging system for categorization
|
|
- Add application relationships (depends on, integrates with)
|
|
- Add bulk status updates
|
|
- Add export to Excel/CSV
|
|
|
|
---
|
|
|
|
## Dependencies & Blockers
|
|
|
|
### Dependencies
|
|
- Story 1 (Business Units) must be complete
|
|
|
|
### Potential Blockers
|
|
- None identified
|
|
|
|
---
|
|
|
|
**Story Status**: Ready for Development
|
|
**Story Created**: February 2026
|
|
**Estimated Completion**: 5-7 days from start
|