Files
gridpilot.gg/docs/architecture/website/COMMAND_MODELS.md
2026-01-13 02:42:58 +01:00

119 lines
2.9 KiB
Markdown

Command Models
This document defines Command Models as a concept for frontend form handling.
**IMPORTANT**: Command Models are **optional UX helpers**. They are NOT enforced by ESLint rules and do not belong in the strict architecture contract.
## 1) Definition
Command Models (also called Form Models) are UX-only write models used to:
- Collect user input
- Track form state (dirty, touched, submitting)
- Perform basic UX validation
- Build Command DTOs for submission
**Command Models are NOT:**
- Domain models
- View models
- Security boundaries
- Required for the architecture
## 2) Purpose
Use Command Models when:
- Forms have complex state management
- Multiple fields need validation
- You want to centralize form logic
- Building DTOs is non-trivial
**Don't use Command Models when:**
- Forms are simple (use React state directly)
- You're building a quick prototype
- The form logic is trivial
## 3) Core Rules
If you use Command Models:
**They MUST:**
- Live in `components/` or `hooks/` (not `lib/`)
- Be write-only (never reused for reads)
- Be discarded after submission
- Only perform UX validation
**They MUST NOT:**
- Contain business logic
- Enforce domain rules
- Reference View Models or Domain Entities
- Be sent to the API directly (use `toCommand()`)
## 4) Example
```typescript
// In your component file or hooks/
export class SignupFormModel {
email = '';
password = '';
isSubmitting = false;
isValid(): boolean {
// UX validation only
return this.email.includes('@') && this.password.length >= 8;
}
toCommand(): SignupCommandDto {
return {
email: this.email,
password: this.password,
};
}
}
// Usage
export function SignupForm() {
const [form] = useState(() => new SignupFormModel());
async function handleSubmit() {
if (!form.isValid()) return;
form.isSubmitting = true;
const result = await signupMutation.mutateAsync(form.toCommand());
form.isSubmitting = false;
}
return (
<form onSubmit={handleSubmit}>
<input value={form.email} onChange={e => form.email = e.target.value} />
{/* ... */}
</form>
);
}
```
## 5) Key Principle
**Command Models are optional.** The backend must validate everything.
If you don't use Command Models, that's fine! Just:
- Use React state for form data
- Let the backend handle validation
- Return clear errors from mutations
## 6) Comparison
| Approach | When to Use | Where |
|----------|-------------|-------|
| **React State** | Simple forms, prototypes | Component |
| **Command Model** | Complex forms, multi-step | Component/Hook |
| **View Model** | Read-only UI state | `lib/view-models/` |
| **Service** | Business orchestration | `lib/services/` |
## 7) Summary
Command Models are **optional UX sugar**. They:
- Help organize complex forms
- Are NOT required by the architecture
- Don't need ESLint enforcement
- Should stay in `components/` or `hooks/`
Use them if they make your life easier. Skip them if they don't.