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:
2026-06-02 05:33:42 +00:00
parent b845d69aba
commit 6ab52a2499
32 changed files with 5816 additions and 501 deletions
+94
View File
@@ -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);
}
},
};