End-to-End: Adding a New Entity
Relevant source files
The following files were used as context for generating this wiki page:
- REVIEW.md
- packages/api/Migrations/AppDb/AppDbContextModelSnapshot.cs
- packages/web/CLAUDE.md
- packages/web/src/api/schema.ts
- packages/web/src/features/contracts/contracts.functions.ts
- packages/api.tests/Customers/CustomerServiceTests.cs
- packages/web/src/routes/_authed/admin/contracts/-components/form.tsx
This guide outlines the standardized process for implementing a new entity within the monorepo architecture, which utilizes a .NET backend and a TanStack Start frontend. The system follows a modular approach where entities are managed through a full stack comprising database migrations, service layers, API endpoints, and a React-based administration interface.
The architecture emphasizes separation of concerns by utilizing Data Transfer Objects (DTOs) for API exposure, Zod for frontend validation, and sequential ID generation via shared counters for business-facing entity numbers.
Backend Implementation
Data Modeling and Database Migration
New entities are defined within the Api.Modules namespace. Each entity typically includes a Guid Id for primary identification, an int Number for human-readable indexing, and a bool IsArchived flag for soft deletion. Relationships between entities (e.g., Contracts relating to Customers and Users) are enforced via foreign keys and configured in the AppDbContext.
The diagram illustrates typical entity relationships and standard fields found in the database schema.
Sources: packages/api/Migrations/AppDb/AppDbContextModelSnapshot.cs:64-210, packages/api.tests/Customers/CustomerServiceTests.cs:30-48
Service Layer and Business Logic
Entities must be handled by a dedicated Service class that manages CRUD operations. Key responsibilities include:
- Sequential Numbering: Using
CounterServiceto increment entity-specific keys (e.g.,Customer,Contract) from a starting value (e.g., 100,000). - Soft Deletion: Implementing
ArchiveAsyncandUnarchiveAsyncmethods instead of hard deletes. - Filtering: Excluding archived records from default
GetAllAsyncresults.
Sources: packages/api.tests/Customers/CustomerServiceTests.cs:17-28, REVIEW.md:28-40
API Configuration
Each module should have a configuration extension to register its services and database context, avoiding a "messy" Program.cs. API endpoints are expected to return DTOs rather than full database entities to maintain decoupling.
| Component | Responsibility |
|---|---|
Add{Entity}Module | Extension method for IServiceCollection to register dependencies. |
Request DTO | Input model for POST/PUT operations (e.g., CustomerRequest). |
Response DTO | Output model for GET operations to prevent schema exposure. |
Sources: REVIEW.md:4-26, REVIEW.md:75-80
Frontend Implementation
Schema Definition and Validation
Validation is handled using Zod. Every form and server function must utilize a Zod schema as the "source of truth". These schemas are typically colocated with the feature (e.g., src/features/customers/customers.schemas.ts).
Sources: packages/web/CLAUDE.md:12-23
Server Functions
Communication with the .NET API is abstracted through createServerFn. These functions handle input validation via the shared Zod schemas and map frontend sort slugs to backend-compatible SortDirection and SortColumn values.
Data flow from the UI through TanStack Start Server Functions to the .NET API.
Sources: packages/web/src/features/contracts/contracts.functions.ts:25-45, packages/web/src/features/customers/customers.functions.ts:8-20
Administration Forms
Forms are built using @tanstack/react-form and standardized UI components from shadcn/ui.
- Form Hook: Use
useFormwithdefaultValuesandvalidators. - Field Components: Utilize
TextField,Label, and a customFieldErrorcomponent. - Submission: Handle submission with a
toastfor user feedback androuter.navigatefor redirection upon success.
Sources: packages/web/src/routes/_authed/admin/contracts/-components/form.tsx:28-55, packages/web/CLAUDE.md:8-16
API Integration
After defining backend endpoints, the frontend API client must be synchronized. The src/api/schema.ts file is auto-generated from the OpenAPI spec of the .NET project.
| Endpoint Pattern | Method | Action |
|---|---|---|
/api/{entity} | GET | Fetch paged, sorted, and filtered list. |
/api/{entity} | POST | Create a new record. |
/api/{entity}/{id} | PUT | Update existing record. |
/api/{entity}/{id}/archive | PATCH | Soft delete the record. |
Sources: packages/web/src/api/schema.ts:32-150, packages/web/package.json:16
Summary
Adding a new entity requires a synchronized effort across the .NET backend (Entity modeling, Counter-based numbering, Service registration) and the TanStack Start frontend (Zod validation, Server Functions, and TanStack Forms). Adhering to the project's strict naming conventions and modular structure ensures maintainability and scalability of the administrative features.