Skip to content

Commit 4e06b07

Browse files
feat: Implement multi-tenancy for pricing plans, refine Supabase middleware to defer auth guards to proxy.ts, and add image processing dependencies to the Dockerfile.
1 parent f8d1a1c commit 4e06b07

4 files changed

Lines changed: 22 additions & 18 deletions

File tree

Dockerfile

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,8 @@ FROM node:20-alpine AS base
22

33
# Install dependencies
44
FROM base AS deps
5-
RUN apk add --no-cache libc6-compat
5+
RUN apk add --no-cache libc6-compat python3 make g++ pkgconfig \
6+
cairo-dev pango-dev jpeg-dev giflib-dev librsvg-dev pixman-dev
67
WORKDIR /app
78
COPY package.json package-lock.json ./
89
RUN npm ci
@@ -35,6 +36,7 @@ WORKDIR /app
3536
ENV NODE_ENV=production
3637
ENV NEXT_TELEMETRY_DISABLED=1
3738

39+
RUN apk add --no-cache cairo pango libjpeg-turbo giflib librsvg pixman
3840
RUN addgroup --system --gid 1001 nodejs
3941
RUN adduser --system --uid 1001 nextjs
4042

app/[locale]/(public)/pricing/page.tsx

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { createClient } from "@/lib/supabase/server";
2+
import { getCurrentTenantId } from "@/lib/supabase/tenant";
23
import { HelpCircle, PackageSearch, ArrowRight } from "lucide-react";
34
import PricingClient from "./pricing-client";
45
import { getTranslations } from 'next-intl/server';
@@ -19,12 +20,14 @@ interface Plan {
1920

2021
export default async function PricingPage() {
2122
const supabase = await createClient();
23+
const tenantId = await getCurrentTenantId();
2224
const t = await getTranslations('pricing');
2325

24-
// Fetch plans from database
26+
// Fetch plans from database - filtered by tenant
2527
const { data: plans, error } = await supabase
2628
.from('plans')
2729
.select('plan_id, plan_name, price, duration_in_days, description, features, payment_provider')
30+
.eq('tenant_id', tenantId)
2831
.order('price', { ascending: true });
2932

3033
if (error) {

lib/supabase/middleware.ts

Lines changed: 10 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -30,25 +30,20 @@ export async function updateSession(request: NextRequest) {
3030
)
3131

3232
// Do not run code between createServerClient and
33-
// supabase.auth.getClaims(). A simple mistake could make it very hard to debug
33+
// supabase.auth.getUser(). A simple mistake could make it very hard to debug
3434
// issues with users being randomly logged out.
3535

36-
// IMPORTANT: If you remove getClaims() and you use server-side rendering
37-
// with the Supabase client, your users may be randomly logged out.
38-
const { data } = await supabase.auth.getClaims()
39-
const user = data?.claims
40-
41-
if (
42-
!user &&
43-
!request.nextUrl.pathname.startsWith('/login') &&
44-
!request.nextUrl.pathname.startsWith('/auth')
45-
) {
46-
// no user, potentially respond by redirecting the user to the login page
47-
const url = request.nextUrl.clone()
48-
url.pathname = '/auth/login'
49-
return NextResponse.redirect(url)
36+
// IMPORTANT: DO NOT REMOVE auth.getUser()
37+
// It refreshes the session and keeps the user logged in.
38+
try {
39+
await supabase.auth.getUser()
40+
} catch {
41+
// Session refresh failed — continue anyway, proxy.ts handles auth guards
5042
}
5143

44+
// NOTE: Auth redirects are handled by proxy.ts (the main middleware),
45+
// not here. This function only refreshes the Supabase session.
46+
5247
// IMPORTANT: You *must* return the supabaseResponse object as it is.
5348
// If you're creating a new response object with NextResponse.next() make sure to:
5449
// 1. Pass the request in it, like so:

proxy.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -119,11 +119,15 @@ export default async function proxy(request: NextRequest) {
119119

120120
// For API routes: set tenant header and pass through (no intl/auth guards)
121121
if (pathname.startsWith('/api')) {
122-
const response = NextResponse.next()
122+
request.headers.set('x-tenant-id', tenantId)
123+
const response = NextResponse.next({ request })
123124
response.headers.set('x-tenant-id', tenantId)
124125
return response
125126
}
126127

128+
// --- Inject tenant ID into request headers so server components can read it ---
129+
request.headers.set('x-tenant-id', tenantId)
130+
127131
// --- Intl Middleware ---
128132
const intlResponse = intlMiddleware(request)
129133

0 commit comments

Comments
 (0)