mirror of
https://github.com/pacnpal/thrillwiki_django_no_react.git
synced 2025-12-22 20:31:10 -05:00
Add test utilities and state machine diagrams for FSM models
- Introduced reusable test utilities in `backend/tests/utils` for FSM transitions, HTMX interactions, and common scenarios. - Added factory functions for creating test submissions, parks, rides, and photo submissions. - Implemented assertion helpers for verifying state changes, toast notifications, and transition logs. - Created comprehensive state machine diagrams for all FSM-enabled models in `docs/STATE_DIAGRAMS.md`, detailing states, transitions, and guard conditions.
This commit is contained in:
461
docs/STATE_DIAGRAMS.md
Normal file
461
docs/STATE_DIAGRAMS.md
Normal file
@@ -0,0 +1,461 @@
|
||||
# State Machine Diagrams
|
||||
|
||||
This document provides comprehensive state diagrams for all FSM-enabled models in ThrillWiki.
|
||||
These diagrams show all possible states, transitions, and guard conditions.
|
||||
|
||||
## Table of Contents
|
||||
|
||||
1. [EditSubmission State Machine](#editsubmission-state-machine)
|
||||
2. [PhotoSubmission State Machine](#photosubmission-state-machine)
|
||||
3. [Park Status State Machine](#park-status-state-machine)
|
||||
4. [Ride Status State Machine](#ride-status-state-machine)
|
||||
5. [ModerationReport State Machine](#moderationreport-state-machine)
|
||||
6. [ModerationQueue State Machine](#moderationqueue-state-machine)
|
||||
7. [BulkOperation State Machine](#bulkoperation-state-machine)
|
||||
|
||||
---
|
||||
|
||||
## EditSubmission State Machine
|
||||
|
||||
EditSubmission tracks user-submitted edits through the moderation workflow.
|
||||
|
||||
```mermaid
|
||||
stateDiagram-v2
|
||||
[*] --> PENDING: User submits edit
|
||||
|
||||
PENDING --> APPROVED: transition_to_approved()
|
||||
PENDING --> REJECTED: transition_to_rejected()
|
||||
PENDING --> ESCALATED: transition_to_escalated()
|
||||
|
||||
ESCALATED --> APPROVED: transition_to_approved()
|
||||
ESCALATED --> REJECTED: transition_to_rejected()
|
||||
|
||||
APPROVED --> [*]
|
||||
REJECTED --> [*]
|
||||
|
||||
note right of PENDING
|
||||
Initial state
|
||||
Yellow badge
|
||||
end note
|
||||
|
||||
note right of APPROVED
|
||||
Final state
|
||||
Green badge
|
||||
Changes applied
|
||||
end note
|
||||
|
||||
note right of REJECTED
|
||||
Final state
|
||||
Red badge
|
||||
end note
|
||||
|
||||
note right of ESCALATED
|
||||
Orange badge
|
||||
Needs admin review
|
||||
end note
|
||||
```
|
||||
|
||||
### States
|
||||
|
||||
| State | Color | Description |
|
||||
|-------|-------|-------------|
|
||||
| PENDING | Yellow | Initial state, awaiting moderator review |
|
||||
| APPROVED | Green | Final state, changes have been applied |
|
||||
| REJECTED | Red | Final state, changes were declined |
|
||||
| ESCALATED | Orange | Needs higher-level review |
|
||||
|
||||
### Transitions
|
||||
|
||||
| Transition | From | To | Guard | Description |
|
||||
|------------|------|-----|-------|-------------|
|
||||
| `transition_to_approved` | PENDING, ESCALATED | APPROVED | `is_moderator` | Approve and apply changes |
|
||||
| `transition_to_rejected` | PENDING, ESCALATED | REJECTED | `is_moderator` | Reject with reason |
|
||||
| `transition_to_escalated` | PENDING | ESCALATED | `is_moderator` | Escalate to admin |
|
||||
|
||||
---
|
||||
|
||||
## PhotoSubmission State Machine
|
||||
|
||||
PhotoSubmission tracks user-submitted photos through moderation.
|
||||
|
||||
```mermaid
|
||||
stateDiagram-v2
|
||||
[*] --> PENDING: User uploads photo
|
||||
|
||||
PENDING --> APPROVED: transition_to_approved()
|
||||
PENDING --> REJECTED: transition_to_rejected()
|
||||
PENDING --> ESCALATED: transition_to_escalated()
|
||||
|
||||
ESCALATED --> APPROVED: transition_to_approved()
|
||||
ESCALATED --> REJECTED: transition_to_rejected()
|
||||
|
||||
APPROVED --> [*]
|
||||
REJECTED --> [*]
|
||||
|
||||
note right of APPROVED
|
||||
Photo added to gallery
|
||||
end note
|
||||
```
|
||||
|
||||
### States
|
||||
|
||||
| State | Color | Description |
|
||||
|-------|-------|-------------|
|
||||
| PENDING | Yellow | Awaiting moderator review |
|
||||
| APPROVED | Green | Photo approved and visible |
|
||||
| REJECTED | Red | Photo rejected |
|
||||
| ESCALATED | Orange | Needs admin review |
|
||||
|
||||
---
|
||||
|
||||
## Park Status State Machine
|
||||
|
||||
Park status tracks the operational status of theme parks.
|
||||
|
||||
```mermaid
|
||||
stateDiagram-v2
|
||||
[*] --> OPERATING: Park opens
|
||||
[*] --> UNDER_CONSTRUCTION: Park announced
|
||||
|
||||
UNDER_CONSTRUCTION --> OPERATING: transition_to_operating()
|
||||
|
||||
OPERATING --> CLOSED_TEMP: transition_to_closed_temp()
|
||||
OPERATING --> CLOSED_PERM: transition_to_closed_perm()
|
||||
OPERATING --> UNDER_CONSTRUCTION: transition_to_under_construction()
|
||||
|
||||
CLOSED_TEMP --> OPERATING: transition_to_operating()
|
||||
CLOSED_TEMP --> CLOSED_PERM: transition_to_closed_perm()
|
||||
|
||||
CLOSED_PERM --> DEMOLISHED: transition_to_demolished()
|
||||
CLOSED_PERM --> RELOCATED: transition_to_relocated()
|
||||
CLOSED_PERM --> OPERATING: transition_to_operating()
|
||||
|
||||
DEMOLISHED --> [*]
|
||||
RELOCATED --> [*]
|
||||
|
||||
note right of OPERATING
|
||||
Green badge
|
||||
Normal operations
|
||||
end note
|
||||
|
||||
note right of CLOSED_TEMP
|
||||
Yellow badge
|
||||
Seasonal or temporary
|
||||
end note
|
||||
|
||||
note right of CLOSED_PERM
|
||||
Red badge
|
||||
Permanently closed
|
||||
end note
|
||||
|
||||
note left of DEMOLISHED
|
||||
Gray badge
|
||||
Final state
|
||||
end note
|
||||
|
||||
note left of RELOCATED
|
||||
Gray badge
|
||||
Final state
|
||||
end note
|
||||
```
|
||||
|
||||
### States
|
||||
|
||||
| State | Color | Description |
|
||||
|-------|-------|-------------|
|
||||
| OPERATING | Green | Park is open and operating |
|
||||
| UNDER_CONSTRUCTION | Blue | Park is being built |
|
||||
| CLOSED_TEMP | Yellow | Temporarily closed (seasonal, renovation) |
|
||||
| CLOSED_PERM | Red | Permanently closed |
|
||||
| DEMOLISHED | Gray | Park has been demolished |
|
||||
| RELOCATED | Gray | Park has moved to new location |
|
||||
|
||||
### Transitions
|
||||
|
||||
| Transition | From | To | Guard | Description |
|
||||
|------------|------|-----|-------|-------------|
|
||||
| `transition_to_operating` | CLOSED_TEMP, CLOSED_PERM, UNDER_CONSTRUCTION | OPERATING | `is_moderator` | Reopen park |
|
||||
| `transition_to_closed_temp` | OPERATING | CLOSED_TEMP | `is_moderator` | Close temporarily |
|
||||
| `transition_to_closed_perm` | OPERATING, CLOSED_TEMP | CLOSED_PERM | `is_moderator` | Close permanently |
|
||||
| `transition_to_demolished` | CLOSED_PERM | DEMOLISHED | `is_moderator` | Mark as demolished |
|
||||
| `transition_to_relocated` | CLOSED_PERM | RELOCATED | `is_moderator` | Mark as relocated |
|
||||
| `transition_to_under_construction` | OPERATING | UNDER_CONSTRUCTION | `is_moderator` | Mark under construction |
|
||||
|
||||
---
|
||||
|
||||
## Ride Status State Machine
|
||||
|
||||
Ride status tracks the operational status of individual rides within parks.
|
||||
|
||||
```mermaid
|
||||
stateDiagram-v2
|
||||
[*] --> OPERATING: Ride opens
|
||||
[*] --> UNDER_CONSTRUCTION: Ride announced
|
||||
|
||||
UNDER_CONSTRUCTION --> OPERATING: transition_to_operating()
|
||||
|
||||
OPERATING --> CLOSED_TEMP: transition_to_closed_temp()
|
||||
OPERATING --> SBNO: transition_to_sbno()
|
||||
OPERATING --> CLOSING: transition_to_closing()
|
||||
OPERATING --> CLOSED_PERM: transition_to_closed_perm()
|
||||
|
||||
CLOSED_TEMP --> OPERATING: transition_to_operating()
|
||||
CLOSED_TEMP --> CLOSED_PERM: transition_to_closed_perm()
|
||||
|
||||
SBNO --> OPERATING: transition_to_operating()
|
||||
SBNO --> CLOSED_PERM: transition_to_closed_perm()
|
||||
SBNO --> DEMOLISHED: transition_to_demolished()
|
||||
|
||||
CLOSING --> CLOSED_PERM: apply_post_closing_status()
|
||||
CLOSING --> OPERATING: transition_to_operating()
|
||||
|
||||
CLOSED_PERM --> DEMOLISHED: transition_to_demolished()
|
||||
CLOSED_PERM --> RELOCATED: transition_to_relocated()
|
||||
CLOSED_PERM --> OPERATING: transition_to_operating()
|
||||
|
||||
DEMOLISHED --> [*]
|
||||
RELOCATED --> [*]
|
||||
|
||||
note right of SBNO
|
||||
Amber badge
|
||||
Standing But Not Operating
|
||||
end note
|
||||
|
||||
note right of CLOSING
|
||||
Orange badge
|
||||
Closing date announced
|
||||
Auto-transitions when date passes
|
||||
end note
|
||||
```
|
||||
|
||||
### States
|
||||
|
||||
| State | Color | Description |
|
||||
|-------|-------|-------------|
|
||||
| OPERATING | Green | Ride is open and operating |
|
||||
| UNDER_CONSTRUCTION | Blue | Ride is being built |
|
||||
| CLOSED_TEMP | Yellow | Temporarily closed (maintenance, seasonal) |
|
||||
| SBNO | Amber | Standing But Not Operating |
|
||||
| CLOSING | Orange | Closing date announced, countdown to close |
|
||||
| CLOSED_PERM | Red | Permanently closed |
|
||||
| DEMOLISHED | Gray | Ride has been removed |
|
||||
| RELOCATED | Gray | Ride has moved to new park |
|
||||
|
||||
### Special: CLOSING Status
|
||||
|
||||
The CLOSING status has special behavior:
|
||||
- When a ride enters CLOSING, a `closing_date` should be set
|
||||
- When the closing date passes, `apply_post_closing_status()` is called
|
||||
- The ride transitions to the `post_closing_status` (default: CLOSED_PERM)
|
||||
- This allows announcing closures ahead of time
|
||||
|
||||
---
|
||||
|
||||
## ModerationReport State Machine
|
||||
|
||||
ModerationReport tracks user reports about content or behavior.
|
||||
|
||||
```mermaid
|
||||
stateDiagram-v2
|
||||
[*] --> PENDING: User submits report
|
||||
|
||||
PENDING --> INVESTIGATING: transition_to_investigating()
|
||||
PENDING --> DISMISSED: transition_to_dismissed()
|
||||
|
||||
INVESTIGATING --> RESOLVED: transition_to_resolved()
|
||||
INVESTIGATING --> DISMISSED: transition_to_dismissed()
|
||||
INVESTIGATING --> ESCALATED: transition_to_escalated()
|
||||
|
||||
ESCALATED --> RESOLVED: transition_to_resolved()
|
||||
ESCALATED --> DISMISSED: transition_to_dismissed()
|
||||
|
||||
RESOLVED --> [*]
|
||||
DISMISSED --> [*]
|
||||
|
||||
note right of INVESTIGATING
|
||||
Blue badge
|
||||
Moderator reviewing
|
||||
end note
|
||||
|
||||
note right of RESOLVED
|
||||
Green badge
|
||||
Action taken
|
||||
end note
|
||||
|
||||
note right of DISMISSED
|
||||
Gray badge
|
||||
No action needed
|
||||
end note
|
||||
```
|
||||
|
||||
### States
|
||||
|
||||
| State | Color | Description |
|
||||
|-------|-------|-------------|
|
||||
| PENDING | Yellow | Report awaiting review |
|
||||
| INVESTIGATING | Blue | Moderator is reviewing |
|
||||
| ESCALATED | Orange | Needs admin attention |
|
||||
| RESOLVED | Green | Action taken, issue addressed |
|
||||
| DISMISSED | Gray | Report dismissed, no action needed |
|
||||
|
||||
---
|
||||
|
||||
## ModerationQueue State Machine
|
||||
|
||||
ModerationQueue tracks workflow items for moderators.
|
||||
|
||||
```mermaid
|
||||
stateDiagram-v2
|
||||
[*] --> PENDING: Item created
|
||||
|
||||
PENDING --> IN_PROGRESS: transition_to_in_progress()
|
||||
PENDING --> CANCELLED: transition_to_cancelled()
|
||||
|
||||
IN_PROGRESS --> COMPLETED: transition_to_completed()
|
||||
IN_PROGRESS --> CANCELLED: transition_to_cancelled()
|
||||
IN_PROGRESS --> PENDING: transition_to_pending()
|
||||
|
||||
COMPLETED --> [*]
|
||||
CANCELLED --> [*]
|
||||
|
||||
note right of IN_PROGRESS
|
||||
Blue badge
|
||||
Being worked on
|
||||
end note
|
||||
|
||||
note right of COMPLETED
|
||||
Green badge
|
||||
Task finished
|
||||
end note
|
||||
```
|
||||
|
||||
### States
|
||||
|
||||
| State | Color | Description |
|
||||
|-------|-------|-------------|
|
||||
| PENDING | Yellow | Waiting to be picked up |
|
||||
| IN_PROGRESS | Blue | Currently being worked on |
|
||||
| COMPLETED | Green | Task finished successfully |
|
||||
| CANCELLED | Gray | Task cancelled |
|
||||
|
||||
---
|
||||
|
||||
## BulkOperation State Machine
|
||||
|
||||
BulkOperation tracks large-scale administrative operations.
|
||||
|
||||
```mermaid
|
||||
stateDiagram-v2
|
||||
[*] --> PENDING: Operation created
|
||||
|
||||
PENDING --> RUNNING: transition_to_running()
|
||||
PENDING --> CANCELLED: transition_to_cancelled()
|
||||
|
||||
RUNNING --> COMPLETED: transition_to_completed()
|
||||
RUNNING --> FAILED: transition_to_failed()
|
||||
RUNNING --> CANCELLED: transition_to_cancelled()
|
||||
|
||||
COMPLETED --> [*]
|
||||
FAILED --> [*]
|
||||
CANCELLED --> [*]
|
||||
|
||||
note right of RUNNING
|
||||
Blue badge
|
||||
Processing items
|
||||
Shows progress %
|
||||
end note
|
||||
|
||||
note right of FAILED
|
||||
Red badge
|
||||
Error occurred
|
||||
end note
|
||||
```
|
||||
|
||||
### States
|
||||
|
||||
| State | Color | Description |
|
||||
|-------|-------|-------------|
|
||||
| PENDING | Yellow | Scheduled, waiting to start |
|
||||
| RUNNING | Blue | Currently processing |
|
||||
| COMPLETED | Green | Finished successfully |
|
||||
| FAILED | Red | Encountered error |
|
||||
| CANCELLED | Gray | Manually cancelled |
|
||||
|
||||
---
|
||||
|
||||
## Common Patterns
|
||||
|
||||
### Permission Guards
|
||||
|
||||
All transitions include permission guards:
|
||||
|
||||
```python
|
||||
@transition(
|
||||
field=status,
|
||||
source='PENDING',
|
||||
target='APPROVED',
|
||||
permission='apps.moderation.can_approve_submission'
|
||||
)
|
||||
def transition_to_approved(self, user=None):
|
||||
pass
|
||||
```
|
||||
|
||||
### Confirmation Requirements
|
||||
|
||||
Dangerous transitions require confirmation in the UI:
|
||||
|
||||
- Reject (any submission)
|
||||
- Cancel (any operation)
|
||||
- Close Permanently (park/ride)
|
||||
- Demolish (park/ride)
|
||||
|
||||
### Toast Notifications
|
||||
|
||||
All transitions trigger toast notifications:
|
||||
|
||||
| Transition Type | Toast Color | Icon |
|
||||
|-----------------|-------------|------|
|
||||
| Approve | Green | check |
|
||||
| Reject | Red | times |
|
||||
| Escalate | Orange | arrow-up |
|
||||
| Complete | Green | check-circle |
|
||||
| Cancel | Red | ban |
|
||||
|
||||
---
|
||||
|
||||
## Testing Transitions
|
||||
|
||||
See the test documentation:
|
||||
|
||||
- **Unit tests**: `backend/apps/*/tests.py`
|
||||
- **Integration tests**: `backend/tests/integration/test_fsm_transition_view.py`
|
||||
- **E2E tests**: `backend/tests/e2e/test_*_fsm.py`
|
||||
- **Manual testing**: `backend/tests/e2e/BROWSER_TESTING_CHECKLIST.md`
|
||||
|
||||
---
|
||||
|
||||
## Implementation Notes
|
||||
|
||||
### Adding New Transitions
|
||||
|
||||
1. Add the transition method to the model with `@transition` decorator
|
||||
2. Define source states, target state, and permission guard
|
||||
3. Update the template to show the new button
|
||||
4. Add tests for the new transition
|
||||
5. Update this documentation
|
||||
|
||||
### State Field Configuration
|
||||
|
||||
States are defined using `RichFSMField` which integrates with:
|
||||
- django-fsm for transition logic
|
||||
- django-fsm-log for transition history
|
||||
- RichChoices for metadata (colors, icons, labels)
|
||||
|
||||
```python
|
||||
status = RichFSMField(
|
||||
choice_group="statuses",
|
||||
domain="moderation",
|
||||
max_length=20,
|
||||
default="PENDING"
|
||||
)
|
||||
```
|
||||
Reference in New Issue
Block a user