Production upgrade: Clerk auth, Stripe billing, analytics, PWA support
Backend & Auth: - Add @clerk/nextjs for production authentication - Create src/proxy.ts with clerkMiddleware() for route protection - Implement multi-tenant auth with role-based access control - Add Clerk components (Show, UserButton, SignInButton, SignUpButton) Billing & Payments: - Full Stripe integration (subscriptions, add-ons, customer portal) - Plan tiers: Starter 9/mo, Farm 49/mo, Enterprise 99/mo - Webhook handling for subscription events - createSubscription(), createAddonSubscription(), createCustomerPortalSession() API & Security: - Rate limiting with @upstash/ratelimit (100 req/min API, 20 req/min checkout) - Zod validation schemas for all endpoints (orders, products, campaigns, etc.) - Security headers (CSP, HSTS, X-Frame-Options) - API routes: /api/v1/ with validated, rate-limited endpoints Monitoring: - Sentry error tracking with performance monitoring - PostHog analytics for feature usage, funnels, cohorts - User activity logging and breadcrumb tracking Admin Features: - Analytics dashboard with revenue charts, customer growth, conversion funnel - Onboarding flow with 6-step interactive tour - Referral system with share tracking and reward redemption - Changelog feed with in-app notifications PWA & SEO: - Web app manifest with icons and shortcuts - Service worker for offline support and caching - Full SEO metadata, OpenGraph, Twitter cards - Structured data (JSON-LD) for organization and products Database: - Add referral_codes, changelogs, onboarding_progress tables - Add user_activity_logs, api_keys, notification_preferences - Comprehensive RLS policies for all new tables - Seed data for demo brands and products
This commit is contained in:
@@ -0,0 +1,94 @@
|
||||
// Global Error Handler for uncaught exceptions
|
||||
|
||||
import { captureError, addBreadcrumb } from "./sentry";
|
||||
|
||||
// Handle uncaught errors
|
||||
if (typeof window !== "undefined") {
|
||||
window.onerror = (message, source, lineno, colno, error) => {
|
||||
captureError(error || new Error(String(message)), {
|
||||
source,
|
||||
lineno,
|
||||
colno,
|
||||
type: "uncaught_error",
|
||||
});
|
||||
return false;
|
||||
};
|
||||
|
||||
// Handle unhandled promise rejections
|
||||
window.onunhandledrejection = (event) => {
|
||||
captureError(
|
||||
event.reason instanceof Error
|
||||
? event.reason
|
||||
: new Error(String(event.reason)),
|
||||
{
|
||||
type: "unhandled_rejection",
|
||||
promise: event.promise ? String(event.promise) : undefined,
|
||||
}
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
// Add breadcrumb for page navigation
|
||||
export function trackPageNavigation(path: string) {
|
||||
addBreadcrumb(`Navigated to ${path}`, { path });
|
||||
}
|
||||
|
||||
// Add breadcrumb for user actions
|
||||
export function trackUserAction(action: string, details?: Record<string, unknown>) {
|
||||
addBreadcrumb(`User action: ${action}`, { action, ...details });
|
||||
}
|
||||
|
||||
// Performance monitoring
|
||||
export function measurePerformance(name: string, callback: () => void | Promise<void>) {
|
||||
const start = performance.now();
|
||||
|
||||
const measure = async () => {
|
||||
await callback();
|
||||
const duration = performance.now() - start;
|
||||
|
||||
addBreadcrumb(`Performance: ${name}`, {
|
||||
name,
|
||||
duration: `${duration.toFixed(2)}ms`,
|
||||
});
|
||||
};
|
||||
|
||||
return measure();
|
||||
}
|
||||
|
||||
// API call tracking
|
||||
export async function trackApiCall<T>(
|
||||
endpoint: string,
|
||||
method: string,
|
||||
fn: () => Promise<T>
|
||||
): Promise<T> {
|
||||
addBreadcrumb(`API call: ${method} ${endpoint}`, { endpoint, method });
|
||||
|
||||
try {
|
||||
const result = await fn();
|
||||
addBreadcrumb(`API success: ${method} ${endpoint}`, { endpoint, method, success: true });
|
||||
return result;
|
||||
} catch (error) {
|
||||
captureError(error as Error, { endpoint, method });
|
||||
addBreadcrumb(`API error: ${method} ${endpoint}`, { endpoint, method, success: false });
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
// Debug logging for development
|
||||
export const debugLog = {
|
||||
info: (message: string, data?: unknown) => {
|
||||
if (process.env.NODE_ENV === "development") {
|
||||
console.info(`[DEBUG] ${message}`, data);
|
||||
}
|
||||
},
|
||||
warn: (message: string, data?: unknown) => {
|
||||
if (process.env.NODE_ENV === "development") {
|
||||
console.warn(`[DEBUG] ${message}`, data);
|
||||
}
|
||||
},
|
||||
error: (message: string, data?: unknown) => {
|
||||
if (process.env.NODE_ENV === "development") {
|
||||
console.error(`[DEBUG] ${message}`, data);
|
||||
}
|
||||
},
|
||||
};
|
||||
Reference in New Issue
Block a user