14 KiB
Story 1: Business Unit Management
Story Overview
As a system administrator
I want to manage business units in the system
So that I can organize applications under their respective organizational units
Story Type: Feature
Priority: High
Estimated Effort: 3-5 days
Dependencies: Story 0 (Foundation)
Business Value
Business units represent the organizational structure within which applications are managed. This story enables:
- Clear organizational hierarchy
- Application ownership mapping
- Contact management at the business unit level
- Foundation for multi-tenant capabilities
Scope
In Scope
✅ Business unit CRUD operations
✅ Business unit listing with search/filter
✅ Basic contact association (simplified for MVP)
✅ Validation (unique names, required fields)
Out of Scope
❌ Complex hierarchical business units (parent/child relationships)
❌ Full contact management (covered in Story 3)
❌ Business unit-specific permissions
❌ Bulk import of business units
Technical Implementation
Backend Tasks
1. Database Migration
- Create Liquibase migration file:
003-create-business-unit-tables.xml - Create
business_unittable:- id (UUID, PK) - name (VARCHAR(255), unique, not null) - description (TEXT, nullable) - created_at (TIMESTAMP, not null) - updated_at (TIMESTAMP, not null) - Add index on
namefor search performance - Insert sample data (3-5 business units) for testing
2. JPA Entity
- Create
BusinessUnitentity extendingBaseEntity@Entity @Table(name = "business_unit") public class BusinessUnit extends BaseEntity { @Column(nullable = false, unique = true) private String name; @Column(columnDefinition = "TEXT") private String description; // Getters, setters, constructors }
3. Repository Layer
- Create
BusinessUnitRepositoryinterfacepublic interface BusinessUnitRepository extends JpaRepository<BusinessUnit, UUID> { Optional<BusinessUnit> findByName(String name); boolean existsByName(String name); Page<BusinessUnit> findByNameContainingIgnoreCase(String name, Pageable pageable); }
4. DTOs
- Create
CreateBusinessUnitRequest:name(required, max 255 chars)description(optional)
- Create
UpdateBusinessUnitRequest:name(optional, max 255 chars)description(optional)
- Create
BusinessUnitResponse:id,name,description,createdAt,updatedAt
- Create
BusinessUnitSummaryResponse(for lists):id,name
5. Service Layer
- Create
BusinessUnitServicewith methods:BusinessUnitResponse create(CreateBusinessUnitRequest request); BusinessUnitResponse update(UUID id, UpdateBusinessUnitRequest request); BusinessUnitResponse findById(UUID id); Page<BusinessUnitResponse> findAll(Pageable pageable); Page<BusinessUnitResponse> search(String query, Pageable pageable); void delete(UUID id); - Implement business logic:
- Check uniqueness of name on create/update
- Throw
ResourceNotFoundExceptionif not found - Throw
BadRequestExceptionfor duplicate names
- Add validation for required fields
6. Controller Layer
- Create
BusinessUnitControllerwith endpoints:GET /api/business-units - List all (paginated) GET /api/business-units/search?q={query} - Search by name GET /api/business-units/{id} - Get by ID POST /api/business-units - Create new PUT /api/business-units/{id} - Update DELETE /api/business-units/{id} - Delete - Add validation annotations (
@Valid,@NotNull, etc.) - Add Swagger/OpenAPI annotations
- Add security: require authentication for all endpoints
7. Testing
- Unit tests for
BusinessUnitService:- Test create with valid data
- Test create with duplicate name (should fail)
- Test update existing business unit
- Test delete business unit
- Test search functionality
- Integration tests for
BusinessUnitController:- Test full CRUD flow
- Test pagination and sorting
- Test search with various queries
- Test error cases (404, 400)
- Test coverage > 80%
Frontend Tasks
1. Models
- Create
business-unit.model.ts:export interface BusinessUnit { id: string; name: string; description?: string; createdAt: Date; updatedAt: Date; } export interface BusinessUnitSummary { id: string; name: string; } export interface CreateBusinessUnitRequest { name: string; description?: string; } export interface UpdateBusinessUnitRequest { name?: string; description?: string; }
2. Service
- Create
business-unit.service.ts:@Injectable({ providedIn: 'root' }) export class BusinessUnitService { getBusinessUnits(page, size, sort): Observable<Page<BusinessUnit>> searchBusinessUnits(query, page, size): Observable<Page<BusinessUnit>> getBusinessUnit(id): Observable<BusinessUnit> createBusinessUnit(data): Observable<BusinessUnit> updateBusinessUnit(id, data): Observable<BusinessUnit> deleteBusinessUnit(id): Observable<void> }
3. Components
BusinessUnitListComponent
- Create component with template and styles
- Features:
- Table/list view of business units
- Columns: Name, Description, Actions
- Pagination controls (page size: 20)
- Sort by name
- Search bar (filter by name)
- "Create New" button
- Actions per row: View, Edit, Delete
- Implement component logic:
- Load business units on init
- Handle pagination events
- Handle sort events
- Handle search with debounce (300ms)
- Navigate to detail/form pages
- Handle delete with confirmation
BusinessUnitDetailComponent
- Create component with template and styles
- Features:
- Display all business unit details
- "Edit" button
- "Delete" button
- "Back to List" button
- Show created/updated timestamps
- Load business unit by ID from route params
BusinessUnitFormComponent
- Create component with template and styles
- Reactive form with fields:
- Name (required, max 255 chars)
- Description (optional, textarea)
- Form validation:
- Name required
- Max length validation
- Show validation errors
- Support both create and edit modes (based on route)
- Handle form submission:
- Call appropriate service method
- Show loading indicator during save
- Navigate to list on success
- Show error notification on failure
- "Cancel" button (navigate back)
4. Routing
- Add routes to
app.routes.ts:{ path: 'business-units', canActivate: [AuthGuard], children: [ { path: '', component: BusinessUnitListComponent }, { path: 'new', component: BusinessUnitFormComponent }, { path: ':id', component: BusinessUnitDetailComponent }, { path: ':id/edit', component: BusinessUnitFormComponent } ] }
5. Navigation
- Add "Business Units" link to header/sidebar navigation
6. Testing
- Unit tests for
BusinessUnitService - Component tests for
BusinessUnitListComponent:- Test rendering of business units
- Test pagination
- Test search
- Test navigation to create/edit/detail
- Component tests for
BusinessUnitFormComponent:- Test form validation
- Test create mode
- Test edit mode
- Test form submission
- E2E test: Full CRUD flow
- Test coverage > 70%
Acceptance Criteria
Backend
- Business unit can be created with unique name
- Duplicate business unit names are rejected with 400 error
- Business unit can be updated
- Business unit can be deleted
- Business units can be listed with pagination
- Business units can be searched by name (case-insensitive)
- All endpoints are authenticated
- All endpoints return proper HTTP status codes
- API is documented in Swagger
Frontend
- User can view list of all business units
- List supports pagination (20 items per page)
- User can search business units by name
- Search has debounce (doesn't query on every keystroke)
- User can create new business unit
- Form validates required fields
- User cannot create duplicate business unit names
- User can view business unit details
- User can edit existing business unit
- User can delete business unit (with confirmation)
- Success/error notifications are displayed
- Navigation is intuitive and works correctly
Testing
- Backend unit tests pass (>80% coverage)
- Backend integration tests pass
- Frontend unit tests pass (>70% coverage)
- E2E tests pass
Testing Scenarios
Scenario 1: Create Business Unit
- Navigate to business units list
- Click "Create New Business Unit"
- Fill in form:
- Name: "Digital Services"
- Description: "Digital transformation initiatives"
- Click "Save"
- Verify success notification
- Verify redirect to business unit list
- Verify new business unit appears in list
Scenario 2: Duplicate Name Prevention
- Navigate to create business unit form
- Enter name of existing business unit
- Click "Save"
- Verify error message: "Business unit with this name already exists"
- Verify business unit is not created
Scenario 3: Edit Business Unit
- Navigate to business units list
- Click "Edit" on a business unit
- Modify description
- Click "Save"
- Verify success notification
- Verify changes are reflected in detail view
Scenario 4: Delete Business Unit
- Navigate to business units list
- Click "Delete" on a business unit
- Confirm deletion in dialog
- Verify success notification
- Verify business unit is removed from list
Scenario 5: Search Business Units
- Navigate to business units list
- Enter search query: "digital"
- Wait for debounce (300ms)
- Verify filtered results contain only matching business units
- Clear search
- Verify all business units are shown again
Scenario 6: Pagination
- Create 25+ business units (if not exists)
- Navigate to business units list
- Verify only 20 items shown on page 1
- Click "Next page"
- Verify remaining items shown on page 2
- Click "Previous page"
- Verify back to page 1
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 CRUD operations via UI
- Demo conducted successfully
- Code merged to main branch
Technical Debt & Future Improvements
Known Limitations
- No hierarchical business units (flat structure only)
- No business unit deactivation (only hard delete)
- No audit trail for changes
- No bulk operations
Future Enhancements
- Add parent-child relationships between business units
- Implement soft delete with deactivation flag
- Add audit logging for business unit changes
- Add bulk import from CSV/Excel
- Add business unit-specific settings
- Implement business unit archiving
Dependencies & Blockers
Dependencies
- Story 0 (Foundation) must be complete
Potential Blockers
- None identified
API Specification
Endpoints
GET /api/business-units
Description: List all business units
Query Parameters:
page(default: 0)size(default: 20)sort(default: name,asc)
Response: 200 OK
{
"content": [
{
"id": "uuid",
"name": "Digital Services",
"description": "Digital transformation initiatives",
"createdAt": "2026-02-01T10:00:00Z",
"updatedAt": "2026-02-01T10:00:00Z"
}
],
"pageable": {
"pageNumber": 0,
"pageSize": 20,
"sort": { "sorted": true, "unsorted": false }
},
"totalElements": 5,
"totalPages": 1
}
GET /api/business-units/search
Description: Search business units by name
Query Parameters:
q(search query)page,size,sort
Response: Same as GET /api/business-units
GET /api/business-units/{id}
Description: Get business unit by ID
Response: 200 OK
{
"id": "uuid",
"name": "Digital Services",
"description": "Digital transformation initiatives",
"createdAt": "2026-02-01T10:00:00Z",
"updatedAt": "2026-02-01T10:00:00Z"
}
Error: 404 Not Found if business unit doesn't exist
POST /api/business-units
Description: Create new business unit
Request Body:
{
"name": "Digital Services",
"description": "Digital transformation initiatives"
}
Response: 201 Created
{
"id": "uuid",
"name": "Digital Services",
"description": "Digital transformation initiatives",
"createdAt": "2026-02-01T10:00:00Z",
"updatedAt": "2026-02-01T10:00:00Z"
}
Errors:
400 Bad Requestif name is duplicate or validation fails401 Unauthorizedif not authenticated
PUT /api/business-units/{id}
Description: Update business unit
Request Body:
{
"name": "Digital Services",
"description": "Updated description"
}
Response: 200 OK (same format as POST)
Errors:
404 Not Foundif business unit doesn't exist400 Bad Requestif validation fails
DELETE /api/business-units/{id}
Description: Delete business unit
Response: 204 No Content
Error: 404 Not Found if business unit doesn't exist
Story Status: Ready for Development
Story Created: February 2026
Estimated Completion: 3-5 days from start