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.email = e.target.value} /> {/* ... */}
); } ``` ## 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.