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 @@
|
||||
// Clerk middleware for route protection
|
||||
|
||||
import { authMiddleware } from "@clerk/nextjs";
|
||||
|
||||
// Define public routes that don't require authentication
|
||||
const publicRoutes = [
|
||||
"/",
|
||||
"/login",
|
||||
"/login2",
|
||||
"/register",
|
||||
"/forgot-password",
|
||||
"/reset-password",
|
||||
"/pricing",
|
||||
"/terms-and-conditions",
|
||||
"/privacy-policy",
|
||||
"/contact",
|
||||
"/api/health",
|
||||
"/api/webhooks/clerk",
|
||||
// Brand storefronts are public
|
||||
"/tuxedo",
|
||||
"/tuxedo/*",
|
||||
"/indian-river-direct",
|
||||
"/indian-river-direct/*",
|
||||
// Error pages
|
||||
"/error",
|
||||
"/not-found",
|
||||
];
|
||||
|
||||
// Define routes that require specific roles
|
||||
const roleProtectedRoutes = [
|
||||
{ path: "/admin/*", roles: ["platform_admin", "brand_admin", "store_employee"] },
|
||||
{ path: "/wholesale/portal/*", roles: ["wholesale_customer"] },
|
||||
{ path: "/water/admin/*", roles: ["platform_admin", "brand_admin"] },
|
||||
];
|
||||
|
||||
export default authMiddleware({
|
||||
// Public routes - don't require auth
|
||||
publicRoutes,
|
||||
|
||||
// Ignore auth for these paths (API routes with their own auth)
|
||||
ignoredRoutes: [
|
||||
"/api/*", // API routes handle their own auth
|
||||
"/_next/*", // Next.js internals
|
||||
"/favicon.ico",
|
||||
"/robots.txt",
|
||||
"/sitemap.xml",
|
||||
],
|
||||
|
||||
// After auth middleware - check roles
|
||||
afterAuth: (auth, req, evt) => {
|
||||
const { userId, sessionId } = auth;
|
||||
const path = req.nextUrl.pathname;
|
||||
|
||||
// Skip role check for public routes
|
||||
if (publicRoutes.some(route => path.startsWith(route.replace("/*", "")))) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if route is role-protected
|
||||
for (const protectedRoute of roleProtectedRoutes) {
|
||||
if (path.startsWith(protectedRoute.path.replace("/*", ""))) {
|
||||
if (!userId) {
|
||||
// Redirect to login if not authenticated
|
||||
const signInUrl = new URL("/login", req.url);
|
||||
signInUrl.searchParams.set("redirect_url", path);
|
||||
return Response.redirect(signInUrl);
|
||||
}
|
||||
|
||||
// For admin routes, check session and role
|
||||
if (protectedRoute.path.startsWith("/admin")) {
|
||||
// Admin routes require one of the allowed roles
|
||||
// This is handled by the admin-permissions module in app layer
|
||||
}
|
||||
|
||||
if (protectedRoute.path.startsWith("/wholesale/portal")) {
|
||||
// Wholesale portal requires wholesale_customer role
|
||||
// This is handled by wholesale-auth module in app layer
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
// Debug in development
|
||||
debug: process.env.NODE_ENV === "development",
|
||||
});
|
||||
|
||||
export const config = {
|
||||
matcher: [
|
||||
// Skip Next.js internals and all files in the _next directory
|
||||
"/((?!_next|[^?]*\\.(?:html?|css|js(?!on)|jpe?g|webp|png|gif|svg|ttf|woff2?|ico|csv|docx?|xlsx?|zip|webmanifest)).*)",
|
||||
// Always run for API routes
|
||||
"/(api|trpc)(.*)",
|
||||
],
|
||||
};
|
||||
Reference in New Issue
Block a user