Projects Router
Relevant source files
The following files were used as context for generating this wiki page:
The Projects Router is a core tRPC module within the Easy Asphalt application responsible for managing driveway estimation projects. It serves as the primary interface between the frontend and the backend business logic, handling operations such as project creation, retrieval, AI-powered edge detection, material pricing, and shareable link generation.
This router implements protectedProcedure for most operations to ensure user-data isolation, requiring a valid user session. It also includes publicProcedure endpoints for shared project access, allowing third-party contractors to view estimates without requiring authentication.
Sources: server/routers/projects.ts:1-20, README.md:120-135
Core Functionality and Architecture
The Projects Router coordinates several specialized services to provide a comprehensive estimation workflow. It integrates with S3 for photo storage, LLM vision services for edge detection, and a custom pricing service for regional cost calculations.
Project Lifecycle Flow
The following diagram illustrates the typical lifecycle of a project from initial photo upload to contractor sharing.
The workflow begins with uploadPhotoAndDetectEdges, which handles binary image data and invokes AI services. Subsequent steps involve querying material costs via getPricing before persisting the full estimate.
Sources: server/routers/projects.ts:54-150, todo.md:10-40
API Endpoints Summary
The Projects Router exposes a variety of tRPC queries and mutations. These are categorized by their access level and primary function.
Protected Procedures (Authenticated)
| Procedure Name | Type | Input Parameters | Description |
|---|---|---|---|
list | Query | None | Retrieves all projects owned by the authenticated user. |
getById | Query | projectId: number | Fetches full details of a specific project, including corner points. |
create | Mutation | Project Details Object | Persists a new driveway estimate and sends email notifications. |
update | Mutation | projectId, updates | Modifies existing project metadata like name or notes. |
delete | Mutation | projectId: number | Removes a project record from the database. |
getPricing | Query | zipCode, material, sqFt, depth | Calculates cost based on regional data and material volume. |
generateMaterialPreview | Mutation | photoUrl, material | Triggers AI image generation for material visualization. |
createShareLink | Mutation | projectId, contractorEmail | Generates a unique token for public project viewing. |
downloadPDF | Mutation | projectId | Generates a Base64 encoded PDF document for local saving. |
Sources: server/routers/projects.ts:24-320, README.md:120-135
Public Procedures (Unauthenticated)
| Procedure Name | Type | Input Parameters | Description |
|---|---|---|---|
getSharedProject | Query | shareToken: string | Accesses project data via a secure, unique sharing token. |
Sources: server/routers/projects.ts:333-353
Technical Implementation Details
Data Modeling and Persistence
Projects are stored in the projects table, while public access is managed via the projectShares table. The router uses Drizzle ORM to interface with the MySQL/TiDB database.
The cornerPoints are stored as a JSON string in the database and parsed back into an array of {x: number, y: number} objects by the list and getById procedures before being returned to the client.
Sources: drizzle/schema.ts:39-93, server/routers/projects.ts:28-32
AI Integration and Pricing Logic
The router leverages vision models and image generation for advanced features:
- Edge Detection: Processes a
photoBase64input to determine driveway boundaries and calculate square footage. - Material Preview: Uses the
generateImageservice to create photorealistic overlays of materials like "hotmix" or "gravel" on the original photo. - Pricing Engine: Combines area, depth, and material type to query
materialPricescached by ZIP code.
Security and Validation
All inputs are validated using zod schemas. Ownership is strictly enforced by checking the ctx.user.id against the project.userId in the database.
// Example of ownership validation in getById
const project = await getProjectById(input.projectId);
if (!project || project.userId !== ctx.user.id) {
throw new TRPCError({
code: "NOT_FOUND",
message: "Project not found",
});
}
Sources: server/routers/projects.ts:40-48, server/routers/projects.test.ts:38-50
Conclusion
The Projects Router is the central orchestration point for the Easy Asphalt estimation engine. By combining traditional CRUD operations with AI vision, regional pricing caches, and secure sharing mechanisms, it enables a seamless transition from a simple driveway photo to a professional contractor-ready estimate.