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:
@@ -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,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user