2.9 KiB
2.9 KiB
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/orhooks/(notlib/) - 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
// 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/orhooks/
Use them if they make your life easier. Skip them if they don't.