This commit is contained in:
2026-01-11 14:42:54 +01:00
parent 2f0b83f030
commit 90b6e73a22
27 changed files with 980 additions and 2513 deletions

View File

@@ -1,14 +1,20 @@
# Login Flow State Machine Architecture
# Login Flow State Machine (Strict)
## Problem
The current login page has unpredictable behavior due to:
- Multiple useEffect runs with different session states
- Race conditions between session loading and redirect logic
- Client-side redirects that interfere with test expectations
This document defines the canonical, deterministic login flow controller for the website.
## Solution: State Machine Pattern
Authoritative website contract:
### State Definitions
- [`docs/architecture/website/WEBSITE_CONTRACT.md`](docs/architecture/website/WEBSITE_CONTRACT.md:1)
## 1) Core rule
Login flow logic MUST be deterministic.
The same inputs MUST produce the same state and the same next action.
## 2) State machine definition (strict)
### 2.1 State definitions
```typescript
enum LoginState {
@@ -19,7 +25,7 @@ enum LoginState {
}
```
### State Transition Table
### 2.2 State transition table
| Current State | Session | ReturnTo | Next State | Action |
|---------------|---------|----------|------------|--------|
@@ -29,7 +35,7 @@ enum LoginState {
| UNAUTHENTICATED | exists | any | POST_AUTH_REDIRECT | Redirect to returnTo |
| AUTHENTICATED_WITHOUT_PERMISSIONS | exists | any | POST_AUTH_REDIRECT | Redirect to returnTo |
### Class-Based Controller
### 2.3 Class-based controller
```typescript
class LoginFlowController {
@@ -57,7 +63,7 @@ class LoginFlowController {
return this.state;
}
// Pure function - returns action, doesn't execute
// Pure function - returns action, does not execute
getNextAction(): LoginAction {
switch (this.state) {
case LoginState.UNAUTHENTICATED:
@@ -71,7 +77,7 @@ class LoginFlowController {
}
}
// Called after authentication
// Transition called after authentication
transitionToPostAuth(): void {
if (this.session) {
this.state = LoginState.POST_AUTH_REDIRECT;
@@ -80,15 +86,14 @@ class LoginFlowController {
}
```
### Benefits
## 3) Non-negotiable rules
1. **Predictable**: Same inputs always produce same outputs
2. **Testable**: Can test each state transition independently
3. **No Race Conditions**: State determined once at construction
4. **Clear Intent**: Each state has a single purpose
5. **Maintainable**: Easy to add new states or modify transitions
1. The controller MUST be constructed from explicit inputs only.
2. The controller MUST NOT perform side effects.
3. Side effects (routing) MUST be executed outside the controller.
4. The controller MUST be unit-tested per transition.
### Usage in Login Page
## 4) Usage in login page (example)
```typescript
export default function LoginPage() {
@@ -129,4 +134,4 @@ export default function LoginPage() {
}
```
This eliminates all the unpredictable behavior and makes the flow testable and maintainable.
This pattern ensures deterministic behavior and makes the flow testable.