- Implement test script for new SAG module endpoints BE-003 (Tag State Management) and BE-004 (Bulk Operations). - Create test cases for creating, updating, and bulk operations on cases and tags. - Add a test for module deactivation to ensure data integrity is maintained. - Include setup and teardown for tests to clear database state before and after each test.
32 KiB
SAG MODULE IMPLEMENTATION PLAN
Professional Sub-Agent Task Breakdown
Document Version: 2.0
Created: 2026-01-30
Module Location: /app/modules/sag/
API Path: /api/v1/cases
Database Prefix: sag_
EXECUTIVE SUMMARY
The Sag (Case) Module is the process backbone of BMC Hub. It implements a universal entity model where tickets, tasks, and (eventually) orders are all represented as Cases differentiated by:
- Relations (directional, transitive connections between cases)
- Tags (workflow state and categorization)
- Attached modules (billing, hardware, etc.)
This plan provides a phased, task-based approach to complete the implementation with architectural constraints preserved.
1️⃣ CURRENT STATE ASSESSMENT
✅ What's Already Implemented
Database Schema (COMPLETE)
-
✅
sag_sagertable (cases) -/migrations/001_init.sql- Binary status:
åben/lukket(constraint enforced) template_keyas nullable field (creation-time only)deleted_atfor soft-deletes- Proper indexes on customer_id, status, ansvarlig_bruger_id
- Auto-update trigger for
updated_at
- Binary status:
-
✅
sag_relationertable (relations)- Directional:
kilde_sag_id→målsag_id relationstypefor categorization- Soft-delete support
- Constraint preventing self-relations
- Directional:
-
✅
sag_tagstable (tags)tag_navnfor categorizationstatefield:open/closed(constraint enforced)closed_attimestamp- Soft-delete support
-
✅
sag_kontaktertable (case-contact links) -/migrations/002_sag_contacts_relations.sql- Many-to-many with roles
-
✅
sag_kundertable (case-customer links)- Many-to-many with roles
Backend API (MOSTLY COMPLETE)
✅ Cases CRUD - router.py lines 1-671
GET /api/v1/cases- List with filters (status, tag, customer_id, ansvarlig)POST /api/v1/cases- Create caseGET /api/v1/cases/{id}- Get case detailsPATCH /api/v1/cases/{id}- Update caseDELETE /api/v1/cases/{id}- Soft-delete
✅ Relations CRUD
GET /api/v1/cases/{id}/relations- List relations with titlesPOST /api/v1/cases/{id}/relations- Create relationDELETE /api/v1/cases/{id}/relations/{relation_id}- Soft-delete
✅ Tags CRUD
GET /api/v1/cases/{id}/tags- List tagsPOST /api/v1/cases/{id}/tags- Add tag (with state support)DELETE /api/v1/cases/{id}/tags/{tag_id}- Soft-delete
✅ Contact/Customer Links
POST /api/v1/cases/{id}/contacts- Link contactGET /api/v1/cases/{id}/contacts- List contactsDELETE /api/v1/cases/{id}/contacts/{contact_id}- Remove contactPOST /api/v1/cases/{id}/customers- Link customerGET /api/v1/cases/{id}/customers- List customersDELETE /api/v1/cases/{id}/customers/{customer_id}- Remove customer
✅ Search
GET /api/v1/search/cases- Full-text searchGET /api/v1/search/customers- Customer searchGET /api/v1/search/contacts- Contact search
Frontend Views (MOSTLY COMPLETE)
✅ List View - frontend/views.py
/casesand/sagroutes (dual paths)- Filter by status, tag, customer_id
- Fetches statuses and tags for filters
✅ Detail View
/cases/{id}and/sag/{id}routes- Shows case, tags, relations, customer
- Fetches contacts and customers (partially implemented)
✅ Create Form
/cases/newand/sag/newroutes- Template exists (
create.html)
❌ Edit Form - Template exists (edit.html) but no backend route
Templates (COMPLETE)
✅ All four templates exist:
index.html- Case list with Nordic Top design, filters, dark modedetail.html- Case details with relations, tags, info sectionscreate.html- Create form with customer search, validationedit.html- Edit form (needs backend route)
🔴 Architectural Violations Found
VIOLATION 1: Duplicate API Paths
Issue: Router has both /sag/* and /cases/* endpoints doing identical things.
- Lines 14-157:
/sagprefix endpoints - Lines 327-671:
/casesprefix endpoints (duplicates)
Fix Required: Remove /sag/* endpoints, keep only /cases/* (architectural standard).
VIOLATION 2: Missing Tag State Management
Issue: Tag closing endpoint missing.
PATCH /api/v1/cases/{id}/tags/{tag_id}should allow closing tags (setstate='closed',closed_at=NOW())- Currently only delete (soft) exists
Fix Required: Add tag state update endpoint.
VIOLATION 3: Missing Edit Route
Issue: edit.html template exists but no backend route to serve it.
Fix Required: Add GET /cases/{id}/edit view route.
⚠️ What Needs Enhancement
- Tag State Workflow - Endpoint to close tags (not delete)
- Edit View Route - Backend route for edit form
- Relation Type Validation - Should validate allowed relation types
- Bulk Operations - Close multiple tags, archive cases
- Activity Log - Track who changed what (future phase)
- Order Integration - Link cases to orders (future phase)
2️⃣ PHASE OVERVIEW
Phase 1: Database Schema Validation (30 min)
- Verify all tables match architectural constraints
- Add any missing indexes
- Validate soft-delete coverage
Phase 2: Backend API Enhancement (2-3 hours)
- Remove duplicate
/sag/*endpoints - Add tag state management endpoint
- Add edit view route
- Improve error handling
- Add relation type validation
Phase 3: Frontend Enhancement (2-3 hours)
- Wire up edit form
- Add tag closing UI
- Improve relation visualization
- Add bulk operations UI
- Enhance mobile responsiveness
Phase 4: Order Integration Planning (1 hour)
- Define order-case relation types
- Document order creation workflow
- Plan order table schema
- Define API contract
Phase 5: Documentation (1 hour)
- Update module README
- Create API documentation
- Document relation types
- Create workflow examples
Phase 6: QA & Testing (1-2 hours)
- Unit tests for CRUD operations
- Integration tests for relations
- Frontend E2E tests
- Soft-delete verification
- Module disable/enable test
Total Estimate: 8-12 hours
3️⃣ SUB-AGENT TASK BREAKDOWN
PHASE 1: DATABASE SCHEMA VALIDATION
DB-001: Schema Compliance Audit
Assigned: DB-Agent
Estimated Time: 30 minutes
Dependencies: None
Description:
Audit all sag_* tables against architectural constraints. Verify:
- Binary status constraint on
sag_sager - Tag state constraint on
sag_tags - Soft-delete columns present
- No missing indexes
- Trigger functions working
Inputs:
/migrations/001_init.sql/migrations/002_sag_contacts_relations.sql- Database connection
Outputs:
- Validation report (pass/fail for each constraint)
- SQL script for any missing indexes/constraints
Done Criteria:
- All constraints match architectural rules
- All soft-delete columns present
- All indexes exist and performant
PHASE 2: BACKEND API ENHANCEMENT
BE-001: Remove Duplicate /sag/* Endpoints
Assigned: Backend-Agent
Estimated Time: 45 minutes
Dependencies: None
Description:
Remove duplicate endpoints with /sag prefix (lines 14-330). Keep only /cases prefix endpoints. Update any internal references.
Inputs:
/app/modules/sag/backend/router.py
Outputs:
- Modified
router.pywith only/casesendpoints - Updated imports if needed
Done Criteria:
- No
/sagprefix endpoints remain - All functionality preserved under
/cases - No broken internal references
BE-002: Add Tag State Management Endpoint
Assigned: Backend-Agent
Estimated Time: 45 minutes
Dependencies: BE-001
Description:
Add PATCH /api/v1/cases/{id}/tags/{tag_id} endpoint to close tags without deleting. Should:
- Accept
{"state": "closed"}payload - Set
closed_at = NOW() - NOT set
deleted_at(tags are closed, not deleted) - Return updated tag
Inputs:
/app/modules/sag/backend/router.pysag_tagstable schema
Outputs:
- New endpoint in
router.py - Proper error handling
Done Criteria:
- Endpoint closes tag (state='closed', closed_at set)
- Returns 404 if tag not found
- Doesn't soft-delete
- Logs action with emoji prefix
BE-003: Add Edit View Route
Assigned: Backend-Agent
Estimated Time: 30 minutes
Dependencies: BE-001
Description:
Add GET /cases/{id}/edit route in frontend/views.py to serve the edit form. Should fetch case and render edit.html template.
Inputs:
/app/modules/sag/frontend/views.py/app/modules/sag/templates/edit.html
Outputs:
- New route in
views.py - Template receives case data
Done Criteria:
- Route returns edit form
- Form pre-populated with case data
- Returns 404 if case not found
BE-004: Add Relation Type Validation
Assigned: Backend-Agent
Estimated Time: 45 minutes
Dependencies: BE-001
Description: Add validation for allowed relation types when creating relations. Define allowed types:
derived(spawned from)blocks(prevents progress)executes(performs work for)relates_to(generic link)
Reject other types with 400 error.
Inputs:
/app/modules/sag/backend/router.py(relation creation endpoint)
Outputs:
- Updated
POST /api/v1/cases/{id}/relationswith validation - Error message listing allowed types
Done Criteria:
- Only allowed types accepted
- 400 error with clear message for invalid types
- Logged validation failures
BE-005: Improve Error Handling
Assigned: Backend-Agent
Estimated Time: 45 minutes
Dependencies: BE-001, BE-002, BE-003, BE-004
Description: Standardize error responses across all endpoints:
- Use consistent HTTPException format
- Include helpful error messages
- Log all errors with context
- Return proper status codes
Inputs:
- All endpoint functions in
router.pyandviews.py
Outputs:
- Consistent error handling pattern
- Improved logging
Done Criteria:
- All errors return proper status codes
- Error messages are user-friendly
- All errors logged with context
- No uncaught exceptions
PHASE 3: FRONTEND ENHANCEMENT
FE-001: Wire Up Edit Form Backend Connection
Assigned: Frontend-Agent
Estimated Time: 45 minutes
Dependencies: BE-003
Description: Complete the edit form JavaScript to:
- Load case data into form
- Submit to
PATCH /api/v1/cases/{id} - Handle success/error responses
- Redirect to detail view on success
Inputs:
/app/modules/sag/templates/edit.html- Backend edit route
- PATCH endpoint
Outputs:
- Functional edit form with submission
- Success/error feedback
- Redirect on success
Done Criteria:
- Form loads case data
- Submission calls PATCH endpoint
- Success redirects to
/cases/{id} - Errors displayed to user
FE-002: Add Tag Closing UI
Assigned: Frontend-Agent
Estimated Time: 60 minutes
Dependencies: BE-002
Description: Add UI to close tags (not delete) in detail view:
- Add "Close Tag" button next to each open tag
- Call
PATCH /api/v1/cases/{id}/tags/{tag_id}withstate='closed' - Update UI to show closed state (greyed out, strikethrough)
- Keep closed tags visible in UI
Inputs:
/app/modules/sag/templates/detail.html- Tag closing endpoint
Outputs:
- Close button on each open tag
- Visual distinction for closed tags
- AJAX call to close endpoint
Done Criteria:
- Closed tags remain visible
- Visual feedback on state change
- No page reload needed
- Error handling for failures
FE-003: Improve Relation Visualization
Assigned: Frontend-Agent
Estimated Time: 90 minutes
Dependencies: None
Description: Enhance relation display in detail view:
- Group relations by type (derived, blocks, executes, relates_to)
- Show directionality clearly (this case → target vs. source → this case)
- Add visual indicators (arrows, colors)
- Make relation targets clickable links
Inputs:
/app/modules/sag/templates/detail.html- Relation data from backend
Outputs:
- Updated relation section with grouping
- Visual indicators for direction
- Clickable links to related cases
Done Criteria:
- Relations grouped by type
- Direction clear (outgoing vs incoming)
- All targets are clickable
- Mobile-responsive
FE-004: Add Bulk Operations UI
Assigned: Frontend-Agent
Estimated Time: 90 minutes
Dependencies: BE-002
Description: Add bulk operations to list view:
- Checkboxes to select multiple cases
- "Close Selected" button (set status='lukket')
- "Archive Selected" button (soft-delete)
- Confirmation dialogs
Inputs:
/app/modules/sag/templates/index.html- Update/delete endpoints
Outputs:
- Selection UI in list view
- Bulk action buttons
- Confirmation dialogs
Done Criteria:
- Multiple cases selectable
- Bulk close works
- Bulk archive works (soft-delete)
- Confirmation required
- Success feedback shown
FE-005: Enhance Mobile Responsiveness
Assigned: Frontend-Agent
Estimated Time: 60 minutes
Dependencies: FE-001, FE-002, FE-003, FE-004
Description: Ensure all views work on mobile:
- Stack filters vertically on small screens
- Make tables scrollable or card-based
- Touch-friendly buttons (min 44px)
- Collapsible sections for detail view
Inputs:
- All template files
Outputs:
- Updated CSS with media queries
- Mobile-optimized layouts
Done Criteria:
- All views usable on 375px width
- No horizontal scroll needed
- Touch targets large enough
- Text readable without zoom
PHASE 4: ORDER INTEGRATION PLANNING
INT-001: Define Order-Case Relation Model
Assigned: Integration-Agent
Estimated Time: 30 minutes
Dependencies: None
Description: Document how orders integrate with cases:
- Orders CAN be created independently
- Orders MUST be linkable to one or more cases
- When order created from case → create relation
- Define relation type for order links (e.g.,
fulfills,invoices_for)
Inputs:
- Architectural constraints document
- Current relation types
Outputs:
- Design document:
docs/ORDER_CASE_INTEGRATION.md - Relation type definitions
- Workflow diagrams
Done Criteria:
- Clear definition of order independence
- Relation type defined
- Creation workflow documented
- No violation of "orders are not cases" rule
INT-002: Plan Order Table Schema
Assigned: Integration-Agent
Estimated Time: 45 minutes
Dependencies: INT-001
Description: Design order tables with case linking:
orderstable (id, title, description, status, etc.)order_case_relationstable (order_id, case_id, relation_type)- NO embedding of case logic in orders
- Soft-delete everywhere
Inputs:
- Order-case relation model (INT-001)
- Existing
sag_*schema
Outputs:
- SQL migration draft:
migrations/XXX_orders.sql - Schema documentation
Done Criteria:
- Order table defined
- Many-to-many relation to cases
- No parent/child embedding
- Soft-delete columns present
INT-003: Define Order API Contract
Assigned: Integration-Agent
Estimated Time: 45 minutes
Dependencies: INT-002
Description: Define order API endpoints:
GET /api/v1/orders- List ordersPOST /api/v1/orders- Create order (optionally from case)POST /api/v1/orders/{id}/cases- Link to caseGET /api/v1/cases/{id}/orders- Get orders for case
Inputs:
- Order schema (INT-002)
- Case API patterns
Outputs:
- API specification document
- Example requests/responses
Done Criteria:
- All CRUD operations defined
- Case linking endpoints defined
- Consistent with case API patterns
- Examples provided
PHASE 5: DOCUMENTATION
DOC-001: Update Module README
Assigned: Docs-Agent
Estimated Time: 30 minutes
Dependencies: BE-001 through BE-005
Description:
Update /app/modules/sag/README.md with:
- Current implementation status
- All API endpoints with examples
- Relation types and meanings
- Tag workflow explanation
- Architectural constraints summary
Inputs:
- Current implementation
- Backend router
- Templates
Outputs:
- Updated
README.md
Done Criteria:
- All endpoints documented
- Examples provided
- Architectural rules explained
- Easy to understand for new developers
DOC-002: Create API Documentation
Assigned: Docs-Agent
Estimated Time: 45 minutes
Dependencies: BE-001 through BE-005
Description: Create OpenAPI-style documentation for all endpoints:
- Request/response schemas
- Status codes
- Error responses
- Example curl commands
Inputs:
- Backend router
- Pydantic models (if any)
Outputs:
docs/SAG_API_REFERENCE.md
Done Criteria:
- All endpoints documented
- Schemas defined
- Examples provided
- Status codes listed
DOC-003: Document Relation Types
Assigned: Docs-Agent
Estimated Time: 30 minutes
Dependencies: BE-004
Description: Create reference guide for relation types:
derived- Target case spawned from sourceblocks- Source blocks target from progressingexecutes- Target performs work for sourcerelates_to- Generic association
Include use cases and examples.
Inputs:
- Relation type validation (BE-004)
- Existing use patterns
Outputs:
docs/CASE_RELATION_TYPES.md
Done Criteria:
- All types explained
- Use cases provided
- Examples given
- Directionality clear
DOC-004: Create Workflow Examples
Assigned: Docs-Agent
Estimated Time: 45 minutes
Dependencies: DOC-001, DOC-002, DOC-003
Description: Document common workflows:
- Customer calls → create support case → derive hardware order case → execute fulfillment case
- Billing cycle → create invoice case → relate to completed support cases
- Project → create project case → derive task cases → track via tags
Inputs:
- All documentation
- Current implementation
Outputs:
docs/SAG_WORKFLOWS.md
Done Criteria:
- At least 3 workflows documented
- Step-by-step instructions
- API calls shown
- Relation chains visualized
PHASE 6: QA & TESTING
QA-001: Backend CRUD Tests
Assigned: QA-Agent
Estimated Time: 90 minutes
Dependencies: BE-001 through BE-005
Description: Write integration tests for all CRUD operations:
- Create case
- Read case
- Update case
- Delete case (soft)
- Verify deleted_at set correctly
Inputs:
- Backend router
- Test database
Outputs:
- Test file:
tests/test_sag_crud.py - At least 20 test cases
Done Criteria:
- All CRUD operations tested
- Soft-delete verified
- Error cases tested
- All tests pass
QA-002: Relation Tests
Assigned: QA-Agent
Estimated Time: 60 minutes
Dependencies: BE-001, BE-004
Description: Test relation operations:
- Create relation between cases
- List relations (both directions)
- Validate relation type validation
- Delete relation (soft)
- Prevent self-relations
Inputs:
- Relation endpoints
- Test database
Outputs:
- Test file:
tests/test_sag_relations.py - At least 10 test cases
Done Criteria:
- Create/delete tested
- Type validation tested
- Self-relation prevention tested
- Directionality correct
QA-003: Tag Workflow Tests
Assigned: QA-Agent
Estimated Time: 60 minutes
Dependencies: BE-002
Description: Test tag lifecycle:
- Add tag to case
- Close tag (state='closed', closed_at set)
- Verify closed tags not deleted
- Delete tag (soft)
- List tags (filter by state)
Inputs:
- Tag endpoints
- Test database
Outputs:
- Test file:
tests/test_sag_tags.py - At least 8 test cases
Done Criteria:
- Add/close/delete tested
- State transitions verified
- Soft-delete vs close distinction tested
- All tests pass
QA-004: Frontend E2E Tests
Assigned: QA-Agent
Estimated Time: 90 minutes
Dependencies: FE-001 through FE-005
Description: Test frontend user flows:
- Navigate to case list
- Filter by status/tag
- Create new case
- View case details
- Edit case
- Add/close tag
- Add relation
- Delete case
Inputs:
- All frontend templates
- Browser automation tool (Playwright/Selenium)
Outputs:
- Test file:
tests/test_sag_frontend.py - At least 10 E2E scenarios
Done Criteria:
- All major flows tested
- Form submissions work
- Navigation works
- Error handling tested
QA-005: Module Disable/Enable Test
Assigned: QA-Agent
Estimated Time: 30 minutes
Dependencies: QA-001, QA-002, QA-003, QA-004
Description: Test module deactivation:
- Create test cases/relations/tags
- Disable module (enabled=false in module.json)
- Verify endpoints return 404
- Verify database data intact
- Re-enable module
- Verify data still accessible
Inputs:
- Module loader
- Test database
Outputs:
- Test file:
tests/test_sag_module_lifecycle.py
Done Criteria:
- Disable prevents access
- Data preserved
- Re-enable restores access
- No data loss
4️⃣ DEPENDENCY GRAPH
Sequential Dependencies (Critical Path)
DB-001 (30m)
↓
BE-001 (45m) ← MUST complete before any backend work
↓
├→ BE-002 (45m)
├→ BE-003 (30m)
├→ BE-004 (45m)
└→ BE-005 (45m) ← Touches all other BE tasks
↓
┌────┴────┐
↓ ↓
FE-001 QA-001 (90m)
(45m) ↓
↓ QA-002 (60m)
FE-002 ↓
(60m) QA-003 (60m)
↓ ↓
FE-003 QA-004 (90m)
(90m) ↓
↓ QA-005 (30m)
FE-004
(90m)
↓
FE-005
(60m)
Parallel Opportunities
Wave 1 (after BE-001):
- BE-002, BE-003, BE-004 can run in parallel
- Saves ~90 minutes
Wave 2 (after BE-005):
- FE-001, FE-003, QA-001, QA-002 can run in parallel
- DOC-001, DOC-002, DOC-003 can run in parallel
- Saves ~2 hours
Wave 3 (after FE-004):
- FE-005, QA-004, DOC-004 can run in parallel
- Saves ~1 hour
Wave 4 (order integration):
- INT-001, INT-002, INT-003 can run in parallel (independent of other work)
Critical Path Time
If executed sequentially: ~12 hours
If parallelized optimally: ~6-7 hours
Where Orders Integrate
Order Integration is PARALLEL to Case Enhancement:
- INT-001, INT-002, INT-003 can start immediately
- Do NOT block case module completion
- Orders gain meaning when linked to cases via relations
- No architectural changes to cases needed
Order-Case Interface:
Cases Module (Complete)
↓
Orders Module (New)
↓
order_case_relations table
↓
Relation type: "fulfills" / "invoices_for"
5️⃣ VALIDATION CHECKLIST
Phase 1: Database Schema
- Binary status constraint verified (
åben/lukket) - Tag state constraint verified (
open/closed) - All soft-delete columns present
- All indexes exist and performant
- Triggers working (updated_at auto-update)
- No foreign key errors
- Relation self-reference prevented
Phase 2: Backend API
- No duplicate
/sag/*endpoints exist - Only
/casesprefix used - Tag closing endpoint works (PATCH tags/{id})
- Edit view route serves form
- Relation type validation enforces allowed types
- All endpoints return consistent error format
- All errors logged with context
- Soft-deletes set
deleted_at, not physical delete
Phase 3: Frontend
- Edit form loads case data
- Edit form submits to PATCH endpoint
- Tag closing UI doesn't delete tags
- Closed tags remain visible (greyed out)
- Relations grouped by type
- Directionality clear (in/out)
- Bulk operations work
- All views mobile-responsive (375px)
Phase 4: Order Integration
- Order-case relation model documented
- Orders can be created independently
- Orders linkable to multiple cases
- No case logic embedded in orders
- Order table schema has soft-deletes
- API contract consistent with case API
Phase 5: Documentation
- README updated with current state
- All endpoints documented
- Relation types explained
- Workflows documented
- Examples provided
Phase 6: Testing
- All CRUD operations tested
- Relation creation/deletion tested
- Tag state transitions tested
- Frontend flows tested
- Module disable/enable tested
- Data preserved after disable
- All tests pass
ARCHITECTURAL CONSTRAINT RE-VALIDATION
After each phase, validate these rules:
Core Entity Rule
- ✅ Only one entity: Case
- ✅ Tickets/tasks are cases with different tags/relations
- ⚠️ Orders are transactional objects, NOT cases (separate table)
Orders Exception
- ⚠️ Orders can be created independently (INT-002)
- ⚠️ Orders linkable to cases via relations (INT-002)
- ⚠️ No case logic in order workflow (INT-001)
Template Usage
- ✅
template_keyonly used at creation - ✅ No business logic depends on it
Case Status
- ✅ Binary only:
åben/lukket - ✅ Workflow state via tags
Tags
- ✅ Represent work to be done
- ✅ Have state:
open/closed - ✅ Never deleted when completed (closed instead)
- ✅ Closing = completion of responsibility
Relations
- ✅ First-class data (own table)
- ✅ Directional (kilde → mål)
- ✅ Transitive (chains allowed)
- ✅ No parent/child duality in stored data
- ✅ UI derives parent/child views
Deletion Policy
- ✅ All deletes are soft-deletes
- ✅
deleted_atmandatory everywhere
Modeling Rule
- ✅ If you think you need a new table → use relations instead
- ⚠️ Exception: Orders (per architectural rule)
TEST SCENARIOS BY PHASE
Phase 1: Database
- Insert case with status='other' → constraint violation
- Insert tag with state='pending' → constraint violation
- Create relation with kilde_sag_id = målsag_id → constraint violation
- Soft-delete case → deleted_at set, not physical delete
- Query cases WHERE deleted_at IS NULL → deleted cases excluded
Phase 2: Backend
- Call
/sag/cases→ 404 (removed endpoint) - Call
/cases→ 200 with case list - PATCH tag state to 'closed' → closed_at set, deleted_at NULL
- DELETE tag → deleted_at set, state unchanged
- POST relation with type='invalid' → 400 error
- POST relation with type='derived' → 201 created
Phase 3: Frontend
- Edit case form → loads current values
- Submit edit form → case updated, redirect to detail
- Click "Close Tag" → tag state='closed', remains visible, greyed
- Add relation → dropdown shows allowed types
- Bulk close cases → all selected closed
- View on 375px screen → no horizontal scroll
Phase 4: Order Integration
- Create order without case → success
- Link order to case → relation created
- View case → shows linked orders
- View order → shows linked cases
- Delete case → order remains (independent)
Phase 5: Documentation
- Developer reads README → understands architecture
- Developer reads API docs → can call endpoints
- Developer reads relation types → understands usage
- Developer reads workflows → can implement feature
Phase 6: QA
- All CRUD operations → success
- Soft-delete case → data preserved
- Module disabled → endpoints return 404
- Module re-enabled → data accessible again
- Tag closed → not deleted
- Relation created → directionality correct
ANTI-PATTERNS TO AVOID
DO NOT:
- ❌ Create
ticketsortaskstables (use cases with tags) - ❌ Embed workflow logic in orders
- ❌ Introduce parent/child trees outside relations
- ❌ Add state machines (use tags)
- ❌ Optimize prematurely (no Redis, no caching yet)
- ❌ Physical delete anything (always soft-delete)
- ❌ Skip validation (enforce constraints)
- ❌ Duplicate endpoints (one path per resource)
DO:
- ✅ Use relations to express connections
- ✅ Use tags to express workflow state
- ✅ Keep orders independent but relatable
- ✅ Soft-delete everything
- ✅ Log all actions with emoji prefixes
- ✅ Return user-friendly errors
- ✅ Preserve data on module disable
ROLLOUT PLAN
Development Environment
- Complete Phases 1-3 in dev
- Test with test data
- Verify module disable/enable
Staging/QA
- Run full QA suite (Phase 6)
- Performance test with 10k+ cases
- Load test endpoints
- Verify soft-deletes work at scale
Production
- Run schema validation (DB-001)
- Deploy backend changes (Phase 2)
- Deploy frontend changes (Phase 3)
- Monitor logs for errors
- Verify no downtime
- Roll back if issues (soft-deletes preserve data)
Post-Deployment
- Monitor case creation rate
- Track relation usage patterns
- Identify most-used tags
- Plan order integration (Phase 4)
SUCCESS CRITERIA
The Sag Module implementation is COMPLETE when:
✅ Database
- All constraints enforced
- Soft-deletes everywhere
- Indexes performant
✅ Backend
- No duplicate endpoints
- Tag closing works
- Relations validated
- Edit route exists
- Errors consistent
✅ Frontend
- Edit form works
- Tag closing UI works
- Relations visualized
- Bulk operations work
- Mobile responsive
✅ Order Integration
- Model documented
- Schema planned
- API defined
- No constraint violations
✅ Documentation
- README complete
- API documented
- Relation types explained
- Workflows documented
✅ Testing
- All CRUD tested
- Relations tested
- Tags tested
- Frontend tested
- Module lifecycle tested
✅ Architectural Compliance
- One entity: Case
- Orders separate but linkable
- Template key not used in logic
- Status binary
- Tags never deleted (closed)
- Relations directional
- Soft-deletes everywhere
- No new tables (except orders)
APPENDIX A: TASK TIME SUMMARY
| Phase | Task Count | Sequential Time | Parallel Time |
|---|---|---|---|
| Phase 1: Database | 1 | 30m | 30m |
| Phase 2: Backend | 5 | 3h 30m | 1h 45m |
| Phase 3: Frontend | 5 | 5h 45m | 2h 30m |
| Phase 4: Orders | 3 | 2h | 30m (parallel) |
| Phase 5: Docs | 4 | 2h 30m | 45m (parallel) |
| Phase 6: QA | 5 | 4h 30m | 2h |
| TOTAL | 23 | 18h 45m | ~8h |
APPENDIX B: RELATION TYPE REFERENCE
| Type | Direction | Meaning | Example |
|---|---|---|---|
derived |
A → B | B spawned from A | Support call → hardware order |
blocks |
A → B | A prevents B | Missing part → installation task |
executes |
A → B | A performs work for B | Packing task → customer order |
relates_to |
A ↔ B | Generic association | Related support tickets |
Validation: Only these four types allowed in POST /api/v1/cases/{id}/relations
APPENDIX C: TAG STATE LIFECYCLE
Tag Created (state='open', closed_at=NULL)
↓
[Work happens]
↓
Tag Closed (state='closed', closed_at=NOW(), deleted_at=NULL)
↓
Tag Remains Visible (greyed out in UI)
↓
[Optional: Technical cleanup]
↓
Tag Soft-Deleted (deleted_at=NOW())
Key Rule: Closing ≠ Deleting. Tags are closed when work is done, deleted only if added by mistake.
APPENDIX D: ORDER-CASE INTEGRATION EXAMPLE
Scenario: Customer needs new laptop
1. Support Call (Case ID: 1001)
- Type: Case
- Tags: [support, hardware]
- Status: åben
2. Create Hardware Order (Order ID: 5001)
- Type: Order (separate table)
- Items: [Laptop, Charger]
- Status: pending
3. Link Order to Case
- POST /api/v1/orders/5001/cases
- Body: {"case_id": 1001, "relation_type": "fulfills"}
- Creates entry in order_case_relations
4. Fulfillment Task (Case ID: 1002)
- Type: Case
- Tags: [fulfillment]
- Status: åben
- Relation: 1002 executes 1001
5. Query Cases for Order
- GET /api/v1/orders/5001/cases
- Returns: [Case 1001]
6. Query Orders for Case
- GET /api/v1/cases/1001/orders
- Returns: [Order 5001]
Architecture Preserved:
- Order is NOT a case
- Order is independent (can exist without case)
- Order gains context through case relation
- Cases remain the process backbone
DOCUMENT CONTROL
Version History:
| Version | Date | Author | Changes |
|---|---|---|---|
| 1.0 | 2026-01-30 | GitHub Copilot | Initial plan |
| 2.0 | 2026-01-30 | GitHub Copilot | Sub-agent task breakdown added |
Approval:
- Architect Review
- Technical Lead Review
- Project Manager Approval
Next Review Date: After Phase 2 completion
END OF IMPLEMENTATION PLAN