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.
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
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
Application Architecture
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.
- We will keep polling /thank-you page until order is set with
isPaid
= true.
- Create Stripe webhook in Stripe dashboard, under Developer mode. Update environment variable
STRIPE_WEBHOOK_SECRET
.
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.
- 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