feat: add OEM code copy tracking, PostHog analytics, Postal email integration

- Add oem_code_copies table and analytics module for tracking part code copies
- Integrate PostHog for frontend product analytics (VIN decode, OEM copy events)
- Switch email service from stub to Postal API with proper error handling
- Add copy button to parts panel with clipboard + server-side logging
- Add admin copy-logs page with filtering and top-copied-codes view
- Add VIN report endpoint for users to flag unrecognized chassis numbers
- Add Postal email env vars to config schema

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Sase Dev
2026-02-17 18:09:07 +00:00
parent dcbeb83ccc
commit f2126754a6
42 changed files with 1307 additions and 223 deletions

View File

@@ -5,6 +5,7 @@ import postgres from "postgres";
import { randomUUID } from "crypto";
import * as schema from "../database/schema/core";
import type { EmailService } from "../email/email.service";
let authInstance: ReturnType<typeof betterAuth> | null = null;
@@ -13,7 +14,12 @@ interface SocialCredentials {
googleClientSecret?: string;
}
export function createAuth(databaseUrl: string, secret: string, baseUrl: string, social?: SocialCredentials) {
interface AuthOptions {
social?: SocialCredentials;
emailService?: EmailService;
}
export function createAuth(databaseUrl: string, secret: string, baseUrl: string, options?: AuthOptions) {
if (authInstance) return authInstance;
const client = postgres(databaseUrl, { max: 5 });
@@ -35,13 +41,30 @@ export function createAuth(databaseUrl: string, secret: string, baseUrl: string,
emailAndPassword: {
enabled: true,
minPasswordLength: 8,
sendResetPassword: async (data) => {
if (options?.emailService) {
await options.emailService.sendPasswordReset(data.user.email, data.url);
} else {
console.log(`[DEV] Password reset URL for ${data.user.email}: ${data.url}`);
}
},
},
...(social?.googleClientId && social?.googleClientSecret
emailVerification: {
sendVerificationEmail: async (data) => {
if (options?.emailService) {
await options.emailService.sendEmailVerification(data.user.email, data.url);
} else {
console.log(`[DEV] Verification URL for ${data.user.email}: ${data.url}`);
}
},
sendOnSignUp: true,
},
...(options?.social?.googleClientId && options?.social?.googleClientSecret
? {
socialProviders: {
google: {
clientId: social.googleClientId,
clientSecret: social.googleClientSecret,
clientId: options.social.googleClientId,
clientSecret: options.social.googleClientSecret,
},
},
}