- Implemented client-side validation functions for tax ID, VAT ID, IBAN, BIC, and website URL. - Added debug logging functionality to assist in development. - Created a comprehensive validation function for company form data. feat: initialize database with Prisma migrations - Added a server-side script to run Prisma migrations and check database health. - Ensured safe initialization of the database to prevent concurrent migrations. feat: comprehensive server-side error logging - Developed an error logging system that captures detailed error context, including request details and stack traces. - Implemented logging functions for different error types (route, action, database, API, startup). fix: validate user ID existence in audit logs - Updated the logging function to validate that the user ID exists in the database before logging actions. fix: update schemas for optional fields and validation - Modified schemas to allow for nullable fields and refined validation logic for tax ID, VAT ID, IBAN, and BIC. feat: enhance error boundary for better debugging - Improved error boundary to log detailed error information in development mode. - Added a debug panel to the main application layout for real-time error tracking. feat: implement company deletion functionality in admin routes - Added a new API route for deleting companies with appropriate logging. - Integrated delete confirmation in the admin interface for better user experience. fix: handle API errors gracefully - Wrapped API actions in try-catch blocks to log errors and return appropriate responses. feat: generate and save invoice PDFs - Implemented functionality to generate and save invoice PDFs upon status updates. - Added a new column in the database for storing the URL of the generated PDF. chore: update Docker image reference - Changed the Docker image reference to point to the new Git repository. chore: update package dependencies - Added @radix-ui/react-tooltip for enhanced UI components. - Updated package-lock.json to reflect new dependencies.
3.9 KiB
/**
- Error Logging Usage Examples
- Use these patterns in your routes to get better error debugging */
// ============================================================================ // PATTERN 1: In a loader (data fetching) // ============================================================================
import { json, type LoaderFunction } from "react-router"; import { logRouteError } from "@/lib/error-logger.server"; import prisma from "@/lib/prisma.server";
export const loader: LoaderFunction = async ({ request, params }) => { try { const company = await prisma.company.findUnique({ where: { id: params.id }, });
if (!company) {
throw new Error(`Company not found: ${params.id}`);
}
return json({ company });
} catch (error) { logRouteError(error, { request, route: request.url, userId: params.userId, // if available metadata: { companyId: params.id, }, }); throw error; // Re-throw to let React Router handle it } };
// ============================================================================ // PATTERN 2: In an action (mutation/form submission) // ============================================================================
import { logActionError } from "@/lib/error-logger.server";
export const action: LoaderFunction = async ({ request, params }) => { try { const formData = await request.formData(); const result = await prisma.company.update({ where: { id: params.id }, data: { name: formData.get("name") }, }); return json({ success: true, result }); } catch (error) { logActionError(error, { request, action: "UPDATE_COMPANY", metadata: { companyId: params.id, method: request.method, }, }); throw error; } };
// ============================================================================ // PATTERN 3: In an API route (POST/PUT/DELETE) // ============================================================================
import { logApiError } from "@/lib/error-logger.server";
export const action: LoaderFunction = async ({ request }) => { try { const data = await request.json();
// Validate
if (!data.name) {
return json(
{ error: "Name is required" },
{ status: 400 }
);
}
// Process
const result = await prisma.company.create({ data });
return json({ success: true, result }, { status: 201 });
} catch (error) { logApiError(error, { request, endpoint: "/api/companies", statusCode: 500, metadata: { method: request.method, }, }); return json( { error: "Internal server error" }, { status: 500 } ); } };
// ============================================================================ // PATTERN 4: Database operations with error context // ============================================================================
import { logDatabaseError } from "@/lib/error-logger.server";
async function fetchCompanyWithUsers(companyId: string) { try { return await prisma.company.findUnique({ where: { id: companyId }, include: { users: true }, }); } catch (error) { logDatabaseError(error, "company.findUnique", { metadata: { companyId }, }); throw error; } }
// ============================================================================ // OUTPUT EXAMPLE (Server Console) // ============================================================================
/*
[ROUTE_ERROR] | 2026-05-02T22:10:30.123Z | Company not found | route: /companies/123 | GET /companies/123 | user: user-id-456 Stack at Object.loader (file:///app/routes/companies.$id.tsx:12:13) at process._tickCallback (internal/timers.ts:203:26) Metadata: { "companyId": "123" }
*/