All checks were successful
Deploy to Staging / Build Images (pull_request) Successful in 8m40s
Deploy to Staging / Deploy to Staging (pull_request) Successful in 52s
Deploy to Staging / Verify Staging (pull_request) Successful in 8s
Deploy to Staging / Notify Staging Ready (pull_request) Successful in 7s
Deploy to Staging / Notify Staging Failure (pull_request) Has been skipped
Backend: Add authenticated endpoints for pending association CRUD (GET/POST/DELETE /api/email-ingestion/pending). Service methods for resolving (creates fuel/maintenance record) and dismissing associations. Frontend: New email-ingestion feature with types, API client, hooks, PendingAssociationBanner (dashboard), PendingAssociationList, and ResolveAssociationDialog. Mobile-first responsive with 44px touch targets and full-screen dialogs on small screens. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
61 lines
2.1 KiB
TypeScript
61 lines
2.1 KiB
TypeScript
/**
|
|
* @ai-summary Resend inbound webhook + user-facing pending association routes
|
|
* @ai-context Public webhook (no JWT) + authenticated CRUD for pending vehicle associations
|
|
*/
|
|
|
|
import { FastifyPluginAsync } from 'fastify';
|
|
import { EmailIngestionController } from './email-ingestion.controller';
|
|
|
|
/** Public webhook route - no JWT auth, uses Svix signature verification */
|
|
export const emailIngestionWebhookRoutes: FastifyPluginAsync = async (fastify) => {
|
|
const controller = new EmailIngestionController();
|
|
|
|
// POST /api/webhooks/resend/inbound - PUBLIC endpoint (no JWT auth)
|
|
// Resend authenticates via webhook signature verification (Svix)
|
|
// rawBody MUST be enabled for signature verification to work
|
|
fastify.post(
|
|
'/webhooks/resend/inbound',
|
|
{
|
|
config: {
|
|
rawBody: true,
|
|
},
|
|
},
|
|
controller.handleInboundWebhook.bind(controller)
|
|
);
|
|
};
|
|
|
|
/** Authenticated user-facing routes for pending vehicle associations */
|
|
export const emailIngestionRoutes: FastifyPluginAsync = async (fastify) => {
|
|
const controller = new EmailIngestionController();
|
|
|
|
// GET /api/email-ingestion/pending - List pending associations for authenticated user
|
|
fastify.get('/email-ingestion/pending', {
|
|
preHandler: [fastify.authenticate],
|
|
handler: controller.getPendingAssociations.bind(controller),
|
|
});
|
|
|
|
// GET /api/email-ingestion/pending/count - Get count of pending associations
|
|
fastify.get('/email-ingestion/pending/count', {
|
|
preHandler: [fastify.authenticate],
|
|
handler: controller.getPendingAssociationCount.bind(controller),
|
|
});
|
|
|
|
// POST /api/email-ingestion/pending/:id/resolve - Resolve by selecting vehicle
|
|
fastify.post<{ Params: { id: string }; Body: { vehicleId: string } }>(
|
|
'/email-ingestion/pending/:id/resolve',
|
|
{
|
|
preHandler: [fastify.authenticate],
|
|
handler: controller.resolveAssociation.bind(controller),
|
|
}
|
|
);
|
|
|
|
// DELETE /api/email-ingestion/pending/:id - Dismiss/discard a pending association
|
|
fastify.delete<{ Params: { id: string } }>(
|
|
'/email-ingestion/pending/:id',
|
|
{
|
|
preHandler: [fastify.authenticate],
|
|
handler: controller.dismissAssociation.bind(controller),
|
|
}
|
|
);
|
|
};
|