THE SUMMARYAI-generated
Multi-Tenant E-commerce Tutorial - Part 2: Detailed Summary
Key Concepts:
- Multi-tenancy, E-commerce, Payload CMS, Stripe Connect, Product Reviews, Vendor Subdomains, Deployment, Cart, Checkout, Star Rating, Global Store (zustand), Hydration Errors, Webhooks, Access Control, Subdomain Rewrites, Storage Adapters (Vercel Blob).
1. Addressing Mistakes from Part 1:
- Node Version Incompatibility:
- The tutorial was initially developed using Node v21.7.3.
- Upgrading to the latest LTS version (e.g., 22.14.0) can cause "module not found" errors, particularly when running scripts like
generate types. - Fix 1: Downgrade to Node v21.7.3.
- Fix 2: Add
"type": "module"topackage.json.
- Typing Issue in Plugins User Access:
- The
rolesproperty in theuserscollection was not correctly typed. - Fix: Import
configfrom./payload-typesto properly typeuser.roles.
- The
2. Chapter 17: Product Page Development
- Objective: Develop a product page with detailed product information.
- Step 1: Create
get oneProcedure:- Create a base procedure called
get oneinsrc/modules/products/server/procedures.ts. - Input: Zod object with only the
IDof the product. - Query:
- Destructure
contextandinput. - Fetch product data using
context.database.findByIDwith the productID. - Return the product.
- Destructure
- Create a base procedure called
- Step 2: Create Product ID Route:
- Create a
page.tsxfile insideapp/tenants/[slug]/home/products/[productID]. - Interface
propsto destructureproductIDandslugfrom the promise. - Asynchronous method to destructure
productIDandslugfromparams. - Implement prefetching using
useQueryanduseSuspenseQuery. - Create a
ProductViewcomponent and pass inproductIDandtenant slug.
- Create a
- Step 3: Create Product View Component:
- Create
ProductView.tsxinsidesrc/modules/products/UI/views. - Define
propsacceptingproductIDandtenant slug. - Build the UI:
- Use
next/imageto display the product image (using placeholder if no image is available). - Implement a grid layout with product name, price, tenant details, ratings, and description.
- Create a
StarRatingcomponent for displaying ratings. - Implement a mobile-specific view for ratings.
- Add a button to add the item to the cart.
- Display refund policy information.
- Use
- Create
- Step 4: Modify Product Card Link:
- Update the
hreflink in theProductCardcomponent to usegenerateTenantURLwith the tenant slug and product ID.
- Update the
- Technical Terms:
depth: Controls how many levels of related data are populated in a query.generateTenantURL: A utility function to generate URLs with the tenant slug.useSuspenseQuery: A React Query hook for fetching data with suspense.TRPC: A library for building type-safe APIs.
- Logical Connections:
- The
get oneprocedure provides the data for theProductViewcomponent. - The
ProductCardcomponent links to theProductViewcomponent.
- The
- Data:
- The product data includes name, price, description, image, tenant, and refund policy.
- Conclusion:
- A responsive product view is created, displaying detailed product information.
3. Chapter 18: Cart and Checkout (UI Only)
- Objective: Implement the cart functionality and checkout page UI.
- Step 1: Add Zustand (Global Store):
- Install
zustandusingbun add zustand. - Create a
useCartStore.tsfile insidesrc/modules/checkout/store. - Define interfaces:
TenantCart:productIDs(array of strings).CartState:tenantCarts(object with tenant slugs as keys andTenantCartas values),addProduct,removeProduct,clearCart,clearAllCarts,getCartByTenant.
- Implement
useCartStoreusingcreateandpersistfromzustand. - Store cart data in
localStorageusingcreateJSONStorage.
- Install
- Step 2: Implement Cart Functionality:
tenantCarts: Empty object initially.addProduct: Adds a product ID to theproductIDsarray for a specific tenant.removeProduct: Removes a product ID from theproductIDsarray for a specific tenant.clearCart: Clears theproductIDsarray for a specific tenant.clearAllCarts: Clears all tenant carts.getCartByTenant: Returns theproductIDsarray for a specific tenant.
- Step 3: Create
useCartHook:- Create a
useCart.tsfile insidesrc/modules/checkout/hooks. - Import
useCartStoreand destructure its methods. - Implement helper methods:
toggleProduct: Adds or removes a product based on its presence in the cart.isProductInCart: Checks if a product is in the cart.clearTenantCart: Clears the cart for a specific tenant.
- Return an object with product IDs,
addProduct,removeProduct,clearCart,clearAllCarts,isProductInCart, andtotalItems.
- Create a
- Step 4: Implement Add to Cart Button:
- Create a
CartButton.tsxcomponent insidesrc/modules/products/UI. - Accept
tenant slugandproductIDas props. - Use the
useCarthook to get cart functionality. - Implement the button logic:
- If the product is in the cart, display "Remove from Cart" and a white background.
- Otherwise, display "Add to Cart" and a pink background.
- Use
toggleProductto add or remove the product.
- Replace the original button in
ProductViewwith theCartButtoncomponent.
- Create a
- Step 5: Fix Hydration Errors:
- Use
next/dynamicto dynamically load theCartButtoncomponent without server-side rendering (SSR). - Add a loading fallback with a disabled button.
- Use
- Step 6: Implement Checkout Button:
- Create a
CheckoutButton.tsxcomponent insidesrc/modules/checkout/UI/components. - Accept
tenant slugand optionalclassNameandhideIfEmptyprops. - Use the
useCarthook to get the total number of items in the cart. - If
hideIfEmptyis true and the cart is empty, returnnull. - Display a button with a shopping cart icon and the total number of items.
- Link the button to the checkout page using
generateTenantURL. - Add dynamic loading without SSR to avoid hydration errors.
- Add a loading skeleton.
- Create a
- Step 7: Add Checkout Button to Navbar:
- Import the
CheckoutButtoncomponent into theNavbarcomponent insrc/modules/tenants/UI. - Pass in the tenant slug.
- Import the
- Technical Terms:
Zustand: A minimalist state management library.Hydration Error: An error that occurs when the server-rendered HTML doesn't match the client-rendered HTML.Dynamic Import: A way to load modules asynchronously.SSR (Server-Side Rendering): Rendering a React component on the server.
- Logical Connections:
- The
useCartStoreprovides the cart data to theuseCarthook. - The
useCarthook provides the cart functionality to theCartButtonandCheckoutButtoncomponents.
- The
- Conclusion:
- The cart functionality is implemented using Zustand.
- The UI is modified to display the cart and checkout buttons.
- Dynamic loading is used to avoid hydration errors.
4. Chapter 19: Checkout Page UI
- Objective: Implement the checkout page UI.
- Step 1: Create Checkout Route:
- Create a
page.tsxfile insideapp/tenants/[slug]/checkout. - Render a "Checkout Page" div.
- Create a
- Step 2: Create Checkout Layout:
- Create a
layout.tsxfile insideapp/tenants/[slug]/checkout. - Copy the
Navbarcomponent fromsrc/modules/tenants/UItosrc/modules/checkout/UI/components. - Modify the
Navbarcomponent to display "Checkout" text and a "Continue Shopping" button. - Copy the layout from
app/tenants/[slug]/homeand simplify it. - Remove prefetching, suspense, and hydration boundary.
- Import the
Navbarcomponent from the checkout module.
- Create a
- Step 3: Implement Checkout Page:
- Create a
CheckoutView.tsxcomponent insidesrc/modules/checkout/UI/views. - Accept
tenant slugas a prop. - Render a div including the tenant slug.
- Mark the component as a client component (
use client).
- Create a
- Step 4: Create Checkout Procedures:
- Copy the
products/serverfolder tocheckout/server. - Rename
products routertocheckout router. - Remove the
get oneprocedure. - Modify the
get manyprocedure to fetch products based on an array of IDs. - Add validation to check if all products were found.
- Copy the
- Step 5: Add Checkout Router to TRPC:
- Import the
checkout routerintosrc/server/api/root.ts. - Add the
checkout routerto the TRPC router.
- Import the
- Step 6: Fetch Products in Checkout View:
- Use
useTRPCanduseQueryto fetch products based on the product IDs from the cart. - Display the products using
JSON.stringify.
- Use
- Step 7: Implement Error Handling:
- Use
useEffectto check for errors in theuseQueryhook. - If a "not found" error occurs, clear all carts and display a warning message using
useToast.
- Use
- Step 8: Display Checkout Items:
- Implement a grid layout with two columns: one for rendering items and one for the checkout sidebar.
- Create a
CheckoutItem.tsxcomponent insidesrc/modules/checkout/UI/components. - Pass props to the
CheckoutItemcomponent:imageURL,name,productURL,tenantURL,tenantName,price, andonRemove. - Implement the UI for the
CheckoutItemcomponent, including an image, product name, tenant details, price, and a "Remove" button.
- Step 9: Implement Checkout Sidebar:
- Create a
CheckoutSidebar.tsxcomponent insidesrc/modules/checkout/UI/components. - Accept props:
total,onCheckout,isCancelled, andisPending. - Implement the UI for the
CheckoutSidebarcomponent, including the total price and a "Checkout" button.
- Create a
- Step 10: Implement Loading and Empty States:
- Add loading and empty states to the
CheckoutViewcomponent. - Display a loading icon while the data is being fetched.
- Display a "No products found" message if the cart is empty.
- Add loading and empty states to the
- Step 11: Implement Cancelled State:
- Add a cancelled state to the
CheckoutSidebarcomponent. - Display an error message if the checkout is cancelled.
- Add a cancelled state to the
- Technical Terms:
Route Group: A way to group routes in Next.js.Layout: A component that wraps a route and provides a consistent UI.TRPC Error: An error that can be thrown from a TRPC procedure.UseToast: A hook for displaying toast notifications.
- Logical Connections:
- The
checkout routerprovides the data for theCheckoutViewcomponent. - The
CheckoutItemcomponent displays the individual items in the cart. - The
CheckoutSidebarcomponent displays the total price and the checkout button.
- The
- Conclusion:
- The checkout page UI is implemented, including the checkout items, sidebar, loading state, empty state, and cancelled state.
5. Chapter 20: Stripe Integration
- Objective: Integrate Stripe payment processing into the application.
- Step 1: Create Stripe Project:
- Create a new Stripe account or use an existing one.
- Obtain the Stripe secret key from the Stripe dashboard.
- Step 2: Install Stripe SDK:
- Install the Stripe SDK using
bun add Stripe.
- Install the Stripe SDK using
- Step 3: Create Stripe Util:
- Create a
stripe.tsfile insidelib. - Import
stripefromstripe. - Export a
stripeinstance with the Stripe secret key and API version.
- Create a
- Step 4: Create Protected Procedure:
- Create a
protected procedureinsrc/server/api/trpc.tsthat extends thebase procedure. - Check if the user is authenticated.
- If not, throw a
TRPC errorwith codeunauthorized. - Add the session user to the context.
- Create a
- Step 5: Implement Purchase Procedure:
- Create a
purchaseprocedure insrc/modules/checkout/server/procedures.tsusing theprotected procedure. - Input: Zod object with
productIDs(array of strings) andtenant slug. - Mutation:
- Fetch products from the database based on the
productIDsandtenant slug. - Fetch the tenant from the database based on the
tenant slug. - Create line items for the Stripe checkout session.
- Create a Stripe checkout session with customer, success URL, cancel URL, mode, line items, and metadata.
- Return the checkout URL.
- Fetch products from the database based on the
- Create a
- Step 6: Implement Checkout View:
- Use
useTRPCanduseMutationto call thepurchaseprocedure. - Implement
onSuccessandonErrorcallbacks to handle the checkout result. - Redirect the user to the Stripe checkout page on success.
- Display an error message if the checkout fails.
- Use
- Step 7: Implement Checkout States Hook:
- Create a
useCheckoutStates.tsfile insidesrc/modules/checkout/hooks. - Use
useQueryStateto manage thesuccessandcancelstates.
- Create a
- Step 8: Implement Webhook Route:
- Create a
route.tsfile insideapp/api/stripe/webhooks. - Import necessary modules.
- Validate the Stripe webhook signature.
- Handle the
checkout.session.completedevent. - Fetch the user and the expanded session.
- Create orders in the database for each line item.
- Return a 200 OK response.
- Create a
- Step 9: Create Orders Collection:
- Create an
orders.tsfile insidesrc/collections. - Define the
orderscollection with fields for name, user, product, and Stripe checkout session ID.
- Create an
- Step 10: Add Orders Collection to Payload Config:
- Import the
orderscollection intopayload.config.ts. - Add the
orderscollection to thecollectionsarray.
- Import the
- Step 11: Configure Stripe Webhook:
- Download and install the Stripe CLI.
- Log in to Stripe using
stripe login. - Listen for webhook events using
stripe listen forward to. - Copy the signing secret.
- Add the signing secret to the environment variables.
- Technical Terms:
Stripe Connect: A Stripe feature that allows platforms to facilitate payments between third-party sellers and buyers.Protected Procedure: A TRPC procedure that requires the user to be authenticated.Line Item: A product or service being purchased in a Stripe checkout session.Webhook: A mechanism for receiving real-time notifications from Stripe.
- Logical Connections:
- The
purchaseprocedure creates a Stripe checkout session. - The webhook route handles the
checkout.session.completedevent and creates orders in the database.
- The
- Data:
- The Stripe checkout session contains information about the customer, line items, and total amount.
- The orders collection stores information about the user, product, and Stripe checkout session ID.
- Conclusion:
- Stripe payment processing is integrated into the application.
- A webhook route is implemented to handle Stripe events and create orders.
- A protected procedure is used to ensure that only authenticated users can initiate a purchase.
6. Chapter 21: Library Implementation
- Objective: Implement the orders/purchases library feature.
- Step 1: Fix Invalid Checkout:
- Modify the
checkout viewto redirect to/libraryon successful purchase. - Invalidate the
library get manyquery to refetch the library data.
- Modify the
- Step 2: Create Get One Library Procedure:
- Create a
get oneprocedure insrc/modules/library/server/procedures.ts. - Input: Zod object with the
productID. - Query:
- Fetch the order based on the
productIDand the user's ID. - Fetch the product based on the
productID. - Return the product.
- Fetch the order based on the
- Create a
- Step 3: Develop Library Product ID UI:
- Create a
page.tsxfile insideapp/library/[productID]. - Implement prefetching using
useQuery. - Render the
ProductViewcomponent.
- Create a
- Step 4: Develop Library Product View:
- Create a
ProductView.tsxcomponent insidesrc/modules/library/UI/views. - Accept
productIDas a prop. - Fetch the product data using
useSuspenseQuery. - Implement the UI for the product view, including the product name and a "Back to Library" button.
- Create a
- Step 5: Modify Product Card:
- Update the
ProductCardcomponent to link to the library page.
- Update the
- Step 6: Add Library Button:
- Add a library button to the search input component.
- Technical Terms:
Prefetching: Fetching data before it is needed to improve performance.Suspense: A React feature that allows components to "wait" for data to load.
- Logical Connections:
- The
get onelibrary procedure provides the data for theProductViewcomponent. - The
ProductCardcomponent links to theProductViewcomponent.
- The
- Conclusion:
- The orders/purchases library feature is implemented, allowing users to view their purchased products.
7. Chapter 22: Reviews Implementation
- Objective: Implement the reviews feature, allowing users to leave reviews for purchased products.
- Step 1: Create Reviews Collection:
- Create a
reviews.tsfile insidesrc/collections. - Define the
reviewscollection with fields for description, rating, product, and user.
- Create a
- Step 2: Add Reviews Collection to Payload Config:
- Import the
reviewscollection intopayload.config.ts. - Add the
reviewscollection to thecollectionsarray.
- Import the
- Step 3: Create Reviews Procedures:
- Create a
procedures.tsfile insidesrc/modules/reviews/server. - Implement the following procedures:
get one: Fetches a single review for a product and user.create: Creates a new review.update: Updates an existing review.
- Create a
- Step 4: Add Reviews Router to TRPC:
- Import the
reviews routerintosrc/server/api/root.ts. - Add the
reviews routerto the TRPC router.
- Import the
- Step 5: Develop Review Sidebar:
- Create a
ReviewSidebar.tsxcomponent insidesrc/modules/library/UI/components. - Accept
productIDas a prop. - Fetch the review data using
useSuspenseQuery. - Render the
ReviewFormcomponent.
- Create a
- Step 6: Develop Review Form:
- Create a
ReviewForm.tsxcomponent insidesrc/components. - Implement the UI for the review form, including a star picker and a text area.
- Use
useFormandzodResolverto handle form validation. - Implement the
onSubmitmethod to create or update the review.
- Create a
- Step 7: Implement Star Picker:
- Create a
StarPicker.tsxcomponent insidesrc/components. - Implement the UI for the star picker, allowing users to select a rating.
- Create a
- Technical Terms:
Zod: A TypeScript-first schema declaration and validation library.UseForm: A React Hook for managing form state.ZodResolver: A resolver that integrates Zod withuseForm.
- Logical Connections:
- The
reviews routerprovides the data for theReviewSidebarcomponent. - The
ReviewFormcomponent allows users to create or update reviews.
- The
- Conclusion:
- The reviews feature is implemented, allowing users to leave reviews for purchased products.
8. Chapter 23: Aggregating Reviews
- Objective: Aggregate reviews and display them in the product cards and product views.
- Step 1: Modify Products Get Many Procedure:
- Modify the
get manyprocedure insrc/modules/products/server/procedures.tsto calculate the average review rating and the number of reviews for each product. - Use
promise.allto fetch the reviews for each product in parallel.
- Modify the
- Step 2: Modify Product List:
- Modify the
ProductListcomponent insrc/modules/products/UI/componentsto display the average review rating and the number of reviews.
- Modify the
- Step 3: Modify Products Get One Procedure:
- Modify the
get oneprocedure insrc/modules/products/server/procedures.tsto calculate the average review rating and the rating distribution for a single product.
- Modify the
- Step 4: Modify Product View:
- Modify the
ProductViewcomponent insrc/modules/products/UI/viewsto display the average review rating, the number of reviews, and the rating distribution.
- Modify the
- Step 5: Implement Copy URL Button:
- Add a button to the
ProductViewcomponent that copies the current URL to the clipboard.
- Add a button to the
- Step 6: Modify Library Procedures:
- Modify the
get manyprocedure insrc/modules/library/server/procedures.tsto calculate the average review rating and the number of reviews for each product.
- Modify the
- Technical Terms:
Promise.all: A method that takes an array of promises and returns a single promise that resolves when all of the input promises have resolved.
- Logical Connections:
- The
get manyandget oneprocedures provide the review data to theProductListandProductViewcomponents.
- The
- Conclusion:
- The reviews are aggregated and displayed in the product cards and product views.
- A copy URL button is implemented in the product view.
9. Chapter 24: Access Control
- Objective: Implement access control to restrict access to sensitive data and operations in the CMS.
- Step 1: Create Access Control Util:
- Create an
access.tsfile insidelib. - Export an
is super adminfunction that checks if a user has the "super-admin" role.
- Create an
- Step 2: Implement Access Control in Users Collection:
- Restrict create and update operations to super admins.
- Allow users to update their own profile.
- Restrict delete operations to super admins.
- Hide the users collection from non-admin users.
- Restrict the role field to super admins.
- Step 3: Implement Access Control in Categories Collection:
- Restrict all operations (create, read, update, delete) to super admins.
- Step 4: Implement Access Control in Products Collection:
- Allow read access to all users.
- Restrict create access to tenants who have submitted their Stripe details.
- Step 5: Implement Access Control in Tags Collection:
- Restrict all operations (create, read, update, delete) to super admins.
- Step 6: Implement Access Control in Tenants Collection:
- Restrict create and delete operations to super admins.
- Allow users to update their own tenant.
- Restrict the Stripe account ID and Stripe details submitted fields to super admins.
- Step 7: Implement Access Control in Orders and Reviews Collections:
- Restrict all operations (create, read, update, delete) to super admins.
- Step 8: Implement Access Control in Media Collection:
- Allow read and create access to all users.
- Restrict delete operations to super admins.
- Hide the media collection from non-admin users.
- Step 9: Restrict Purchased Content:
- Modify the
get oneandget manyprocedures in theproductsmodule to prevent thecontentfield from being loaded for non-authenticated users.
- Modify the
- Technical Terms:
Access Control: A mechanism for restricting access to sensitive data and operations.Role-Based Access Control (RBAC): A type of access control that assigns permissions based on the user's role.
- Logical Connections:
- The
is super adminutil is used to determine if a user has the "super-admin" role. - The access control settings in the collections restrict access to sensitive data and operations.
- The
- Conclusion:
- Access control is implemented to restrict access to sensitive data and operations in the CMS.
- The
is super adminutil is used to determine if a user has the "super-admin" role. - The access control settings in the collections restrict access to sensitive data and operations.
10. Chapter 25: Stripe Connect
- Objective: Implement Stripe Connect to enable fee sharing.
- Step 1: Set Up Stripe Connect:
- Set up Stripe Connect in the Stripe dashboard.
- Step 2: Modify Register Procedure:
- Modify the
registerprocedure insrc/modules/auth/server/procedures.tsto assign a Stripe account ID to each tenant. - Create a Stripe account using
stripe.accounts.create.
- Modify the
- Step 3: Create Verify Procedure:
- Create a
verifyprocedure insrc/modules/checkout/server/procedures.ts. - Fetch the user and the tenant.
- Create an account link using
stripe.accountLinks.create. - Return the account link URL.
- Create a
- Step 4: Add Verify Button to CMS:
- Create a
StripeVerify.tsxcomponent insidesrc/components. - Add a "Verify Account" button that links to the
/stripe-verifyroute. - Add the
StripeVerifycomponent to thebefore nav linkssection in theadminconfiguration inpayload.config.ts.
- Create a
- Step 5: Implement Stripe Verify Page:
- Create a
page.tsxfile insideapp/admin/tenants/stripe-verify. - Use
useTRPCanduseMutationto call theverifyprocedure. - Redirect the user to the account link URL on success.
- Redirect the user to the root page on error.
- Create a
- Step 6: Implement Webhook Route:
- Add
account.updatedto the list of permitted events in the webhook route. - Handle the
account.updatedevent. - Update the
stripe details submittedfield in thetenantscollection.
- Add
- Step 7: Modify Purchase Procedure:
- Modify the
purchaseprocedure insrc/modules/checkout/server/procedures.tsto take a fee percentage. - Calculate the platform fee amount.
- Add the
application fee amountandstripe accountto the payment intent data.
- Modify the
- Technical Terms:
Stripe Account Link: A URL that allows users to connect their Stripe account to the platform.Application Fee: A fee that the platform takes from each transaction.
- Logical Connections:
- The
registerprocedure creates a Stripe account for each tenant. - The
verifyprocedure creates an account link that allows tenants to connect their Stripe account to the platform. - The webhook route updates the
stripe details submittedfield in thetenantscollection. - The
purchaseprocedure takes a fee percentage from each transaction.
- The
- Conclusion:
- Stripe Connect is implemented, allowing the platform to take a fee percentage from each transaction.
- A user-facing Stripe verification page is created.
- An admin action is added to prompt users to verify their account before creating products.
11. Chapter 26: General Improvements
- Objective: Implement general improvements to the application, including soft delete, private products, rich text elements, and missing suspense wrappers.
- Step 1: Implement Soft Delete:
- Disable the delete option in the
productscollection for non-admin users. - Add an
is archivedfield to theproductscollection. - Modify the
get manyandget oneprocedures in theproductsmodule to filter out archived products.
- Disable the delete option in the
- Step 2: Implement Private Products:
- Add an
is privatefield to theproductscollection. - Modify the
get manyprocedure in theproductsmodule to filter out private products from the public storefront.
- Add an
- Step 3: Add Rich Text Elements:
- Install the
@payloadcms/richtext-lexicalpackage. - Enable the lexical editor in the
payload.config.tsfile. - Change the
contentanddescriptionfields in theproductscollection to use therich texttype.
- Install the
- Step 4: Add Missing Suspense Wrappers:
- Identify components that use
useSuspenseQuerybut are not wrapped in aSuspensecomponent. - Wrap those components in a
Suspensecomponent and provide a fallback.
- Identify components that use
- Technical Terms:
Soft Delete: A way to delete data without permanently removing it from the database.Rich Text Element: A text editor that allows users to format text and add media.Suspense Wrapper: A React component that allows components to "wait" for data to load.
- Logical Connections:
- The
is archivedandis privatefields are used to filter products in theget manyandget oneprocedures. - The
rich texttype allows users to format text and add media to thecontentanddescriptionfields. - The
Suspensecomponent allows components to "wait" for data to load.
- The
- Conclusion:
- Soft delete and private products are implemented.
- Rich text elements are added to the
contentanddescriptionfields. - Missing suspense wrappers are added to improve the user experience.
12. Chapter 27: Subdomain Rewrites
- Objective: Implement subdomain rewrites to enable tenant-specific subdomains.
- Step 1: Add Root Domain to Environment Variables:
- Add a
NEXT_PUBLIC_ROOT_DOMAINenvironment variable to the.envfile.
- Add a
- Step 2: Modify Generate Tenant URL Method:
- Modify the
generateTenantURLmethod inlib/utils.tsto generate URLs with the tenant slug as a subdomain.
- Modify the
- Step 3: Implement Middleware:
- Create a
middleware.tsfile in thesrcdirectory. - Implement a middleware function that rewrites requests to the correct tenant-specific subdomain.
- Create a
- Step 4: Update Stripe URLs:
- Update the Stripe success and cancel URLs to use the new subdomain format.
- Step 5: Add Cookie Settings:
- Add proper cookie settings to the
generateOutCookiemethod insrc/modules/auth/utils.ts.
- Add proper cookie settings to the
- Technical Terms:
Subdomain Rewrite: A technique for rewriting URLs to use subdomains.Middleware: A function that intercepts requests and responses.
- Logical Connections:
- The
generateTenantURLmethod generates the URLs that are used in the middleware. - The middleware rewrites the requests to the correct tenant-specific subdomain.
- The
- Conclusion:
- Subdomain rewrites are implemented, allowing tenants to have their own subdomains.
- The
generateTenantURLmethod is modified to generate URLs with the tenant slug as a subdomain. - A middleware function is implemented to rewrite requests to the correct tenant-specific subdomain.
13. Chapter 28: Deployment
- Objective: Prepare the application for deployment to Versel.
- Step 1: Run Build:
- Run
bun run buildto check for any errors.
- Run
- Step 2: Add Dynamic Force Dynamic:
- Add
export const dynamic = 'force-dynamic'to thepage.tsxfiles in theauthandlibrarymodules.
- Add
- Step 3: Deploy to Versel:
- Deploy the application to Versel.
- Step 4: Update Environment Variables:
- Update the environment variables in
AI summaries can miss context or contain errors. Check important details against the original video.