Skip to content

Commit 1dcd3c8

Browse files
Copilotkbeaugrand
andcommitted
Add implementation planning for User Story 2 (Edit and Delete Menu Entries)
Co-authored-by: kbeaugrand <9513635+kbeaugrand@users.noreply.github.com>
1 parent 5916e62 commit 1dcd3c8

File tree

7 files changed

+3984
-0
lines changed

7 files changed

+3984
-0
lines changed
Lines changed: 356 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,356 @@
1+
# User Story 2: Edit and Delete - Implementation Checklist
2+
3+
**Feature**: Custom Menu Entries
4+
**User Story**: US2 - Edit and Delete Menu Entries
5+
**Tasks**: T036-T056 (21 tasks total)
6+
7+
---
8+
9+
## 📋 Pre-Implementation Checklist
10+
11+
- [x] Plan.md reviewed and understood
12+
- [x] Quickstart.md guide ready
13+
- [x] API contracts reviewed (contracts/menu-entries-api.yaml)
14+
- [x] Data model understood (data-model.md)
15+
- [x] Research findings reviewed (research.md)
16+
- [x] Tasks.md reviewed (T036-T056)
17+
- [ ] Development environment ready
18+
- [ ] User Story 1 (US1) implementation verified
19+
20+
---
21+
22+
## 🧪 Phase 1: Write Tests (TDD - Tests MUST Fail First)
23+
24+
### Service Layer Tests (Tasks T036, T037)
25+
26+
**File**: `src/IoTHub.Portal.Tests.Unit/Infrastructure/Services/MenuEntryServiceTests.cs`
27+
28+
- [ ] T036: `UpdateMenuEntry_ValidData_UpdatesSuccessfully`
29+
- [ ] T036: `UpdateMenuEntry_DuplicateName_ThrowsResourceAlreadyExistsException`
30+
- [ ] T036: `UpdateMenuEntry_InvalidUrl_ThrowsArgumentException`
31+
- [ ] T036: `UpdateMenuEntry_NonExistentId_ThrowsResourceNotFoundException`
32+
- [ ] T036: `UpdateMenuEntry_NameTooLong_ThrowsArgumentException`
33+
- [ ] T037: `DeleteMenuEntry_ExistingId_DeletesSuccessfully`
34+
- [ ] T037: `DeleteMenuEntry_NonExistentId_ThrowsResourceNotFoundException`
35+
36+
**Verification**: Run `dotnet test` → Should see 7 FAILURES ✅
37+
38+
### Controller Layer Tests (Tasks T038, T039)
39+
40+
**File**: `src/IoTHub.Portal.Tests.Unit/Server/Controllers/v1.0/MenuEntriesControllerTests.cs`
41+
42+
- [ ] T038: `Put_ValidData_Returns200Ok`
43+
- [ ] T038: `Put_DuplicateName_Returns400BadRequest`
44+
- [ ] T038: `Put_InvalidModelState_Returns400BadRequest`
45+
- [ ] T038: `Put_NonExistentId_Returns404NotFound`
46+
- [ ] T039: `Delete_ExistingId_Returns204NoContent`
47+
- [ ] T039: `Delete_NonExistentId_Returns404NotFound`
48+
49+
**Verification**: Run `dotnet test` → Should see 6 MORE FAILURES ✅
50+
51+
---
52+
53+
## 🔧 Phase 2: Backend Implementation
54+
55+
### Service Interface (Task T040)
56+
57+
**File**: `src/IoTHub.Portal.Application/Services/IMenuEntryService.cs`
58+
59+
- [ ] T040: Verify `UpdateMenuEntryAsync(MenuEntryDto dto)` method signature exists
60+
- [ ] T040: Verify `DeleteMenuEntryAsync(string id)` method signature exists
61+
62+
### Service Implementation (Tasks T041, T042)
63+
64+
**File**: `src/IoTHub.Portal.Infrastructure/Services/MenuEntryService.cs`
65+
66+
- [ ] T041: Implement `UpdateMenuEntryAsync()` with:
67+
- [ ] Existence check (throw ResourceNotFoundException if not found)
68+
- [ ] Name validation (required, max 100 chars)
69+
- [ ] Duplicate name check (exclude current ID)
70+
- [ ] URL format validation (HTTP/HTTPS or relative path)
71+
- [ ] Auto-detect IsExternal
72+
- [ ] Update UpdatedAt timestamp
73+
- [ ] Preserve CreatedAt
74+
- [ ] Call repository.Update() and unitOfWork.SaveAsync()
75+
76+
- [ ] T042: Implement `DeleteMenuEntryAsync()` with:
77+
- [ ] Existence check (throw ResourceNotFoundException if not found)
78+
- [ ] Call repository.Delete() and unitOfWork.SaveAsync()
79+
- [ ] Add logging
80+
81+
**Verification**: Run `dotnet test` → Service tests should PASS ✅
82+
83+
### Controller Implementation (Tasks T043, T044, T045, T046)
84+
85+
**File**: `src/IoTHub.Portal.Server/Controllers/v1.0/MenuEntriesController.cs`
86+
87+
- [ ] T043: Verify GET by ID endpoint exists with `[Authorize("menuentry:read")]`
88+
- [ ] T044: Implement/enhance PUT endpoint with:
89+
- [ ] `[HttpPut("{id}")]` attribute
90+
- [ ] `[Authorize("menuentry:write")]` attribute
91+
- [ ] ModelState validation check
92+
- [ ] ID mismatch check (URL id vs body id)
93+
- [ ] Return 200 OK with updated DTO
94+
- [ ] Proper XML documentation
95+
96+
- [ ] T045: Implement/enhance DELETE endpoint with:
97+
- [ ] `[HttpDelete("{id}")]` attribute
98+
- [ ] `[Authorize("menuentry:write")]` attribute
99+
- [ ] Return 204 No Content on success
100+
- [ ] Proper XML documentation
101+
102+
- [ ] T046: Enhance error handling for all endpoints:
103+
- [ ] 404 Not Found for ResourceNotFoundException
104+
- [ ] 400 Bad Request for validation errors
105+
- [ ] 400 Bad Request for ResourceAlreadyExistsException
106+
- [ ] ProblemDetails format for all errors
107+
108+
**Verification**: Run `dotnet test` → Controller tests should PASS ✅
109+
110+
---
111+
112+
## 🎨 Phase 3: Frontend Implementation
113+
114+
### Client Service Interface (Task T047)
115+
116+
**File**: `src/IoTHub.Portal.Client/Services/IMenuEntryClientService.cs`
117+
118+
- [ ] T047: Verify `GetByIdAsync(string id)` method exists
119+
- [ ] T047: Verify `UpdateAsync(MenuEntryDto dto)` method exists
120+
- [ ] T047: Verify `DeleteAsync(string id)` method exists
121+
122+
### Client Service Implementation (Task T048)
123+
124+
**File**: `src/IoTHub.Portal.Client/Services/MenuEntryClientService.cs`
125+
126+
- [ ] T048: Implement `GetByIdAsync()` with GET request to `/api/menu-entries/{id}`
127+
- [ ] T048: Implement `UpdateAsync()` with PUT request to `/api/menu-entries/{id}`
128+
- [ ] T048: Implement `DeleteAsync()` with DELETE request to `/api/menu-entries/{id}`
129+
- [ ] T048: Ensure proper error propagation (EnsureSuccessStatusCode)
130+
131+
### Edit Dialog (Tasks T049, T050)
132+
133+
**File**: `src/IoTHub.Portal.Client/Dialogs/MenuEntries/EditMenuEntryDialog.razor`
134+
135+
- [ ] T049: Verify dialog component exists (may be from US1)
136+
- [ ] T050: Add/enhance form validation:
137+
- [ ] Real-time character counter for Name (max 100)
138+
- [ ] URL format validation on blur
139+
- [ ] External/Internal indicator chip
140+
- [ ] Disabled Save button when form invalid
141+
- [ ] Loading indicator during save
142+
- [ ] Error/success Snackbar notifications
143+
144+
### List Page Enhancements (Tasks T051, T052, T053)
145+
146+
**File**: `src/IoTHub.Portal.Client/Pages/MenuEntries/MenuEntryListPage.razor`
147+
148+
- [ ] T051: Add Edit button to each table row
149+
- [ ] T051: Implement `OpenEditDialog(MenuEntryDto entry)` method
150+
- [ ] T051: Refresh list on dialog close with success
151+
152+
- [ ] T052: Add Delete button to each table row
153+
- [ ] T052: Implement `OpenDeleteConfirmation(MenuEntryDto entry)` method
154+
- [ ] T052: Show confirmation dialog with entry name
155+
- [ ] T052: Implement `DeleteEntry(string id)` method
156+
- [ ] T052: Call delete API only after confirmation
157+
158+
- [ ] T053: Implement list refresh logic:
159+
- [ ] Refresh after successful edit
160+
- [ ] Refresh after successful delete
161+
- [ ] Show success Snackbar on operations
162+
- [ ] Show error Snackbar on failures
163+
164+
### Navigation Menu (Task T054)
165+
166+
**File**: `src/IoTHub.Portal.Client/Shared/NavMenu.razor`
167+
168+
- [ ] T054: Add try-catch in `OnInitializedAsync()`
169+
- [ ] T054: Gracefully handle missing entries (log error, continue rendering)
170+
- [ ] T054: Reload menu entries on navigation
171+
172+
**Verification**: Manual testing - all UI flows should work ✅
173+
174+
---
175+
176+
## 🧪 Phase 4: Client Tests
177+
178+
### Edit Dialog Tests (Task T055)
179+
180+
**File**: `src/IoTHub.Portal.Tests.Unit/Client/Dialogs/MenuEntries/EditMenuEntryDialogTests.cs`
181+
182+
- [ ] T055: `Dialog_ValidData_SubmitsSuccessfully`
183+
- [ ] T055: `Dialog_InvalidUrl_ShowsValidationError`
184+
- [ ] T055: `Dialog_NameTooLong_ShowsValidationError`
185+
- [ ] T055: `Dialog_ClosesOnSuccess`
186+
187+
### List Page Tests (Task T056)
188+
189+
**File**: `src/IoTHub.Portal.Tests.Unit/Client/Pages/MenuEntries/MenuEntryListPageTests.cs`
190+
191+
- [ ] T056: `EditButton_Click_OpensDialogWithCorrectData`
192+
- [ ] T056: `DeleteButton_Click_ShowsConfirmationDialog`
193+
- [ ] T056: `DeleteConfirmed_CallsApiAndRefreshesList`
194+
- [ ] T056: `DeleteCancelled_DoesNotCallApi`
195+
196+
**Verification**: Run `dotnet test` → All tests (including client) should PASS ✅
197+
198+
---
199+
200+
## ✅ Phase 5: Manual Testing & Validation
201+
202+
### Manual Testing Scenarios
203+
204+
- [ ] **Test 1: Edit menu entry name**
205+
- [ ] Navigate to Menu Entry management page
206+
- [ ] Click Edit button for an existing entry
207+
- [ ] Change name from "Old Name" to "New Name"
208+
- [ ] Click Save
209+
- [ ] Verify success message appears
210+
- [ ] Verify "New Name" appears in list
211+
- [ ] Verify navigation menu shows "New Name"
212+
213+
- [ ] **Test 2: Edit menu entry URL**
214+
- [ ] Click Edit button for an entry
215+
- [ ] Change URL from old to new
216+
- [ ] Click Save
217+
- [ ] Verify success message
218+
- [ ] Verify clicking link goes to new URL
219+
220+
- [ ] **Test 3: Delete menu entry**
221+
- [ ] Click Delete button
222+
- [ ] Verify confirmation dialog appears with entry name
223+
- [ ] Click Cancel → verify entry still exists
224+
- [ ] Click Delete button again
225+
- [ ] Click Delete in confirmation → verify success message
226+
- [ ] Verify entry removed from list
227+
- [ ] Verify entry removed from navigation menu
228+
229+
- [ ] **Test 4: Edit with duplicate name**
230+
- [ ] Create two entries: "Entry A" and "Entry B"
231+
- [ ] Edit "Entry A" to have name "Entry B"
232+
- [ ] Verify error message about duplicate name
233+
- [ ] Verify entry NOT updated
234+
235+
- [ ] **Test 5: Edit with invalid URL**
236+
- [ ] Click Edit on entry
237+
- [ ] Change URL to "invalid-url"
238+
- [ ] Verify inline validation error
239+
- [ ] Verify Save button disabled
240+
241+
- [ ] **Test 6: Authorization check**
242+
- [ ] Log in as user without `menuentry:write` permission
243+
- [ ] Verify Edit/Delete buttons hidden or disabled
244+
- [ ] (Optional) Try API call → verify 401 Unauthorized
245+
246+
### Acceptance Criteria Validation
247+
248+
- [ ] **AC1: Edit entry name** - updated name appears in navigation
249+
- [ ] **AC2: Delete entry** - removed from navigation and storage
250+
- [ ] **AC3: Edit with invalid URL** - validation prevents saving
251+
- [ ] **AC4: Delete confirmation** - system confirms before removal
252+
253+
---
254+
255+
## 📊 Phase 6: Code Quality & Review
256+
257+
### Code Quality Checks
258+
259+
- [ ] All unit tests pass (100% success rate)
260+
- [ ] No compiler warnings
261+
- [ ] All methods have proper XML documentation
262+
- [ ] Code follows IoT Hub Portal naming conventions
263+
- [ ] Authorization attributes present on all endpoints
264+
- [ ] Error responses use ProblemDetails format
265+
- [ ] No hardcoded strings (use constants)
266+
- [ ] Proper async/await patterns used
267+
268+
### Security Review
269+
270+
- [ ] PUT endpoint has `[Authorize("menuentry:write")]`
271+
- [ ] DELETE endpoint has `[Authorize("menuentry:write")]`
272+
- [ ] GET by ID has `[Authorize("menuentry:read")]`
273+
- [ ] URL validation prevents script injection
274+
- [ ] No SQL injection risk (EF Core parameterized queries)
275+
- [ ] Input sanitization via DataAnnotations
276+
277+
### Performance Review
278+
279+
- [ ] No N+1 query issues
280+
- [ ] Async methods used throughout
281+
- [ ] List refresh doesn't cause UI lag
282+
- [ ] API operations complete within 200ms
283+
284+
---
285+
286+
## 🚀 Phase 7: Deployment Preparation
287+
288+
### Pre-Deployment
289+
290+
- [ ] All tests passing
291+
- [ ] Manual testing complete
292+
- [ ] Code review approved
293+
- [ ] Documentation updated
294+
- [ ] No breaking changes confirmed
295+
- [ ] Staging environment ready
296+
297+
### Deployment Steps
298+
299+
- [ ] Deploy backend changes (service + controller)
300+
- [ ] Deploy frontend changes (client service + UI)
301+
- [ ] Verify staging deployment
302+
- [ ] Smoke test on staging
303+
- [ ] Get stakeholder approval
304+
- [ ] Deploy to production
305+
306+
### Post-Deployment Validation
307+
308+
- [ ] Edit existing entry → success
309+
- [ ] Delete entry → success + confirmation
310+
- [ ] Navigation menu reflects changes
311+
- [ ] Authorization working correctly
312+
- [ ] No errors in application logs
313+
314+
---
315+
316+
## 📈 Completion Metrics
317+
318+
### Task Completion
319+
320+
- **Total Tasks**: 21 (T036-T056)
321+
- **Tests Written**: 21 new unit tests
322+
- **Files Modified**: ~10 files
323+
- **Files Created**: ~2 test files
324+
- **Time Spent**: ___ days
325+
326+
### Quality Metrics
327+
328+
- **Test Pass Rate**: ___% (target: 100%)
329+
- **Code Coverage**: ___% (existing coverage maintained)
330+
- **Bugs Found**: ___
331+
- **Bugs Fixed**: ___
332+
333+
---
334+
335+
## ✅ Final Sign-Off
336+
337+
- [ ] All tasks complete (T036-T056)
338+
- [ ] All tests passing
339+
- [ ] All acceptance criteria met
340+
- [ ] Manual testing complete
341+
- [ ] Code review approved
342+
- [ ] Documentation complete
343+
- [ ] Deployed to staging
344+
- [ ] Stakeholder approval received
345+
- [ ] Ready for production deployment
346+
347+
---
348+
349+
**Implementation Status**: 🚧 IN PROGRESS
350+
**Started**: ___________
351+
**Completed**: ___________
352+
**Total Time**: ___________
353+
354+
---
355+
356+
*Use this checklist to track progress through User Story 2 implementation*

0 commit comments

Comments
 (0)