Forms & Validation
Relevant source files
The following files were used as context for generating this wiki page:
Hearth employs a unified validation strategy that links client-side user interfaces with server-side processing. The system uses Zod schemas as the single source of truth to ensure data integrity across Server Actions, AI-assisted tools, and manual entry forms. This architecture guarantees that data conforms to expected formats before it reaches the database, providing immediate feedback to users through specific error messages.
Sources: CLAUDE.md:155-161, src/lib/actions/home.ts:74-82
Core Architecture
The system centers on Server Actions as the primary write path. When you submit a form, the application captures FormData, validates it against a domain-specific Zod schema, and performs the database operation.
Data Flow
The diagram shows how user input moves from the client to the server, including the offline-aware path that queues operations in IndexedDB when the server is unreachable.
Sources: CLAUDE.md:103-109, src/components/ContractForm.tsx:75-81
Validation Strategy
Hearth utilizes three primary mechanisms to ensure data completeness and accuracy:
- Zod Schemas: Defined in
src/lib/validation/, these schemas validate types, required fields, and constraints (e.g.,contractSchema,propertySchema). - State Management: The
ActionStatetype tracks the result of an operation, including success messages, error strings, and the values that failed validation. - Full Form Updates: The
fullFormUpdatehelper ensures that only fields present in theFormDataare updated during partial edits, preventing unintended data loss.
Sources: src/lib/actions/home.ts:74-82, src/lib/validation/fullFormUpdate.ts:8-16, src/lib/form-state.ts:6-12
Key Validation Components
| Component | Responsibility | Source File |
|---|---|---|
firstIssueMessage | Converts complex Zod error objects into a single user-friendly string. | src/lib/actions/home.ts:67-69 |
formDataToStringValues | Serializes FormData into a plain object to persist user input after a validation failure. | src/lib/form-state.ts:14-22 |
fullFormUpdate | Merges new form data with existing record values, respecting schema constraints. | src/lib/validation/fullFormUpdate.ts:8-23 |
safeParse | Executes Zod validation without throwing, returning a success/error object. | src/lib/actions/home.ts:75 |
AI & Extraction Review
Forms support automated data entry through a three-stage extraction pipeline (Text -> Heuristics -> Cloud AI). Because AI extraction is not a guarantee of accuracy, the system implements a "Needs Review" state.
Review Workflow
When a document is uploaded, the system populates form fields automatically. If AI or heuristic extraction is used, the system:
- Highlights affected fields in the UI (accent for heuristics, blue for AI).
- Requires a manual confirmation checkbox or per-field review before reminders are activated.
- Sets
extraction_pendingto true in the database until confirmed.
Sources: src/components/ContractForm.tsx:128-137, src/components/ExtractionReviewPanel.tsx:55-63, src/lib/actions/home.ts:160-168
This sequence illustrates the interaction between document upload, field population, and user confirmation.
Sources: src/components/ContractForm.tsx:143-162, src/components/ExtractionReviewPanel.tsx:90-110
Guarded AI Writes
The AI Assistant uses "guarded write" tools to propose data changes. These tools do not write directly to the database. Instead, they:
- Receive parameters from the LLM.
- Validate the parameters against the standard Zod schemas (e.g.,
contractSchema). - Return a
proposed_actionto the client. - The user must explicitly click a confirmation button in the UI to trigger the actual Server Action.
Sources: src/lib/chat/tools.ts:25-35, src/lib/chat/tools.ts:218-228
Implementation Details
Server Action Pattern
Every domain action follows a consistent pattern of authentication, validation, command execution, and redirection.
export async function createProperty(
_prevState: ActionState,
formData: FormData,
): Promise<ActionState> {
const user = await requireUser(); // 1. Auth & Module Check
const parsed = propertySchema.safeParse(formToPropertyInput(formData)); // 2. Validation
if (!parsed.success) {
return {
error: firstIssueMessage(parsed.error),
values: formDataToStringValues(formData, PROPERTY_FORM_FIELDS),
};
}
const property = await createPropertyCommand(parsed.data, user.id); // 3. Command Execution
redirect(`/home/${property.id}`); // 4. Navigation
}
Sources: src/lib/actions/home.ts:86-100
Offline Awareness
Forms use makeOfflineAwareAction to wrapper standard Server Actions. If the user is offline, the form submission is intercepted, and the data is stored in IndexedDB for later synchronization.
Sources: src/components/ContractForm.tsx:63-73, CLAUDE.md:144-148
Summary
Forms and validation in Hearth provide a secure, privacy-first environment for managing household data. By centralizing logic in Zod schemas and enforcing human-in-the-loop review for AI-generated data, the system maintains high data quality while reducing manual entry friction. The consistent use of Server Actions and ActionState ensures a predictable experience for both developers and users across all device types and network conditions.