website refactor
This commit is contained in:
76
apps/website/lib/auth/LoginFlowController.ts
Normal file
76
apps/website/lib/auth/LoginFlowController.ts
Normal file
@@ -0,0 +1,76 @@
|
||||
/**
|
||||
* Login Flow Controller
|
||||
*
|
||||
* Deterministic state machine for authentication flow.
|
||||
* Compliant with docs/architecture/website/LOGIN_FLOW_STATE_MACHINE.md
|
||||
*/
|
||||
|
||||
import type { SessionViewModel } from '@/lib/view-models/SessionViewModel';
|
||||
|
||||
export enum LoginState {
|
||||
UNAUTHENTICATED = "UNAUTHENTICATED",
|
||||
AUTHENTICATED_WITH_PERMISSIONS = "AUTHENTICATED_WITH_PERMISSIONS",
|
||||
AUTHENTICATED_WITHOUT_PERMISSIONS = "AUTHENTICATED_WITHOUT_PERMISSIONS",
|
||||
POST_AUTH_REDIRECT = "POST_AUTH_REDIRECT"
|
||||
}
|
||||
|
||||
export type LoginAction =
|
||||
| { type: 'SHOW_LOGIN_FORM' }
|
||||
| { type: 'REDIRECT'; path: string }
|
||||
| { type: 'SHOW_PERMISSION_ERROR' };
|
||||
|
||||
/**
|
||||
* LoginFlowController - Immutable, deterministic state machine
|
||||
*
|
||||
* Rules:
|
||||
* - Constructed from explicit inputs only
|
||||
* - No side effects
|
||||
* - Pure functions for state transitions
|
||||
* - Side effects (routing) executed outside
|
||||
*/
|
||||
export class LoginFlowController {
|
||||
// Immutable state
|
||||
private readonly session: SessionViewModel | null;
|
||||
private readonly returnTo: string;
|
||||
|
||||
// State machine
|
||||
private state: LoginState;
|
||||
|
||||
constructor(session: SessionViewModel | null, returnTo: string) {
|
||||
this.session = session;
|
||||
this.returnTo = returnTo;
|
||||
this.state = this.determineInitialState();
|
||||
}
|
||||
|
||||
private determineInitialState(): LoginState {
|
||||
if (!this.session) return LoginState.UNAUTHENTICATED;
|
||||
if (this.returnTo === '/dashboard') return LoginState.AUTHENTICATED_WITH_PERMISSIONS;
|
||||
return LoginState.AUTHENTICATED_WITHOUT_PERMISSIONS;
|
||||
}
|
||||
|
||||
// Pure function - no side effects
|
||||
getState(): LoginState {
|
||||
return this.state;
|
||||
}
|
||||
|
||||
// Pure function - returns action, does not execute
|
||||
getNextAction(): LoginAction {
|
||||
switch (this.state) {
|
||||
case LoginState.UNAUTHENTICATED:
|
||||
return { type: 'SHOW_LOGIN_FORM' };
|
||||
case LoginState.AUTHENTICATED_WITH_PERMISSIONS:
|
||||
return { type: 'REDIRECT', path: '/dashboard' };
|
||||
case LoginState.AUTHENTICATED_WITHOUT_PERMISSIONS:
|
||||
return { type: 'SHOW_PERMISSION_ERROR' };
|
||||
case LoginState.POST_AUTH_REDIRECT:
|
||||
return { type: 'REDIRECT', path: this.returnTo };
|
||||
}
|
||||
}
|
||||
|
||||
// Transition called after authentication
|
||||
transitionToPostAuth(): void {
|
||||
if (this.session) {
|
||||
this.state = LoginState.POST_AUTH_REDIRECT;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user