Skip to content

Latest commit

 

History

History
198 lines (146 loc) · 9.16 KB

README.md

File metadata and controls

198 lines (146 loc) · 9.16 KB

Digital marketplace (NextJs Monolith):

  • Fullstack approach, monolith NextJS app with combined Express, NextJs, Payload CMS backends in only 1 server or 1 serverless instance (AWS Lambda or GCP Function).
  • tRPC (Typescript Remote Procedure Call) to ensure end-to-end type-safty.
  • Next14, Tailwind, Shadcn UI,Lucide react, Zustand LocalStorage
  • Other techstacks: Payload CMS with Mongo DB abstraction.
  • Reference Payload starting templates

Getting Started

  • Install Shadcn UI with npx shadcn-ui@latest init
  • Choose the color theme that you want to use, and copy the theme to src/app/globals.css

Express Middleware for NextJs

  • We are using Express as a middleware for separating traffics between customer path (/) with admin dashboard path (/sell) for sellers.
  • Using cross-env and nodemon in dev mode will automatically restart the express server on file changes.
  • We also need to add a few custom decorators in tsconfig.server.json to make Express works:
{
  "extends": "./tsconfig.json",
  "compilerOptions": {
    "module": "CommonJS",
    "outDir": "dist",
    "noEmit": false,
    "jsx": "react"
  },
  "include": ["src/server.ts", "src/payload.config.ts"]
}
  • Express will be the first point-of-entry for both rendering and TRPC api requests.

Express Frontier Server

Payload Configuration (MongoDB, alternative: Postgres)

  • Create payload.config.ts and export a default config.
  • For editor in payload config, we can choose SlateJs[https://www.slatejs.org/] or Lexical[https://lexical.dev/].
  • Install payload adapters for MongoDb (alternative: Postgres), and webpack bundler for our Express server:
npm i @payloadcms/richtext-slate @payloadcms/bundler-webpack @payloadcms
/db-mongodb --save
  • For viewing payload Admin dashboard, please see http://localhost:3000/sell
  • Important note: You should not have any users document in your database, in order to be redirected to http://localhost:3000/sell/create-first-user. See more here

Payload Collections on MongoDB

Zod Validation with react-hook-form

TRPC and tanstack/react-query

  • Important: Whenever a new collection is created, make sure to add it in payload.config.ts and also run npm run generate:types
  • Provides both FE and BE typesafe APIs with @trpc/server and @trpc/client. See here
  • Create a Providers wrapper component, which will provide the trpc context to your app. Providers and Providers in layout.tsx
<trpc.Provider client={trpcClient} queryClient={queryClient}>
  <QueryClientProvider client={queryClient}>{children}</QueryClientProvider>
</trpc.Provider>
  • At this point of time, TRPC v11 is still in beta, and TRPC v10 can only support tanstack/react-query v4.36.1. See here

MongoDB Collections

  • For users collection, we have 3 types of users: admin, buyer and seller. See here
  • Plug the users collection in your payload config. See here

Email Signup Confirmation

  • This project uses resend for email confirmation. See resend SMTP docs
  • Alternatives are AWS SES, Google Mail (500 emails limit), Mailchimp. Make sure to use the email providers, which our confirmation emails would not be landed in Spam folder.
  • Note: we must add DNS records to prove our domain, so resend can work. See here Resend DNS Records Sign up flows

Application Architecture

  • Payload Application Architecture
  • Checkout Flow with Stripe hosted url

Stripe Checkout

  • Go to Stripe account, activate Test Mode, and select Developers tab.
  • Use this credit card number for testing: 4242 4242 4242 4242. Other details can be anything.
  • Create Transaction Fee Line Item
  • Get Line Item PriceId for Transaction Fee
  • We will keep polling /thank-you page until order is set with isPaid = true.
  • Stripe Checkout With webhook
  • Create Stripe webhook in Stripe dashboard, under Developer mode. Update environment variable STRIPE_WEBHOOK_SECRET.
  • Stripe Checkout With webhook

Email templates

export const ReceiptEmailHtml = (props: ReceiptEmailProps) =>
  render(<ReceiptEmail {...props} />, {
    pretty: true,
  });

Dockerize the project

  • Build the docker image and run with external port of 8080, and internal port of 3000
  • Make sure to ignore node_modules in .dockerignore to avoid platform issues between x86-64 and arm64
  • Railway could build the app with or without Docker. But with Docker, we need to specify environment variables that we pass from Railway app to Docker container.
docker build -t next-marketplace .
docker ps
docker run -dp 8080:3000 next-marketplace
  ARG NEXT_PUBLIC_SERVER_URL
  ARG PAYLOAD_SECRET
  ARG MONGODB_URL
  ARG TRANSACTION_FEE_PRICE_ID
  ARG STRIPE_SECRET_KEY
  ARG STRIPE_WEBHOOK_SECRET
  ARG RESEND_API_KEY

Railway app Deployments

const nextConfig = {
  images: {
    domains: ["nextmarket.up.railway.app", "localhost"],
  },
};

AWS EC2 Deployment

ECS Fargate deployment with CDK (tested and working)

  • Follow the instructions here: ECS Fargate deployment with CDK
  • Dockerfile will require to have FROM --platform=linux/amd64
  • Although this is working. The cost for Application Load Balancer would be around 30$ a month
  • The cost for Fargate is around 3 times more than EC2 instance, approximately 200-300$ a year for 1 VCPU and 1GB memory.

Github Actions Deployment to AWS EC2 with Docker (Cheaper option)

  • Avoid costly build with AWS CodeBuild and AWS CodePipeline. Github workflow is free.
  • Using Route 53 and Cloudfront with EC2 (public IP Address) origin to distribute dynamic website traffic.
  • Github Actions deployment to AWS EC2 with Docker
  • Route 53 and Cloudfront to EC2
  • Cost: EC2 (t2.micro) 60-100$/year, a public IP (43$ a year), Route 53 and Cloudfront cost.
  • Video Tutorial

Hostinger Deployment (Cheapest)

S3 storage for medi and product_files collections

npm i @payloadcms/plugin-cloud-storage @aws-sdk/client-s3 @aws-sdk/lib-storage aws-crt

Optimizations

  • (Optional) Add resolution to package.json to improve build time with copyfiles.
  • (Optional) Declare main entry to application in package.json as main: dist/server.js
  • (Important) Make sure to includes all local and production domains inside next.config.mjs:

TODO

  • Deploy this NextApp in AWS Lambda (may not be possible)
  • Deploy this NextApp in AWS EKS
  • Fix Email Receipt
  • Fix Mobile View Cart