- 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
- 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
- We are using Express as a middleware for separating traffics between customer path (/) with admin dashboard path (/sell) for sellers.
- Using
cross-env
andnodemon
indev
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.
- 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 tohttp://localhost:3000/sell/create-first-user
. See more here
- Use Zod validation schema for both client-side and server-side
- Integrate Zod validators with
@hookform/resolvers/zod
. See here
- Important: Whenever a new collection is created, make sure to add it in
payload.config.ts
and also runnpm 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
- For users collection, we have 3 types of users:
admin
,buyer
andseller
. See here - Plug the users collection in your payload config. See here
- 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
- 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
.
- @react-email/components
- React Email templates with responsive design here.
- Apple Email Receipt Example
- Using
@react-email/components
, we can render our email templates in React into a React component.
export const ReceiptEmailHtml = (props: ReceiptEmailProps) =>
render(<ReceiptEmail {...props} />, {
pretty: true,
});
- 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
const nextConfig = {
images: {
domains: ["nextmarket.up.railway.app", "localhost"],
},
};
- With AWS CodePipeline, CodeBuild, Elastic Beanstalk and EC2
- Using a EC2 instance saving plan, and deploy ECS Cluster with EC2 launch type. And use an Elastic Ip Address would save lots of cost over using ALB.
- Example of creating ECS deployment with EC2 launch type
- Routing from Route53 to EC2 instance
- 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.
- 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
- Using Docker with Hostinger
- It is better to automate the build from Github Actions. Follow similar Video Tutorial
npm i @payloadcms/plugin-cloud-storage @aws-sdk/client-s3 @aws-sdk/lib-storage aws-crt
- (Optional) Add
resolution
topackage.json
to improve build time withcopyfiles
. - (Optional) Declare main entry to application in
package.json
asmain: dist/server.js
- (Important) Make sure to includes all local and production domains inside
next.config.mjs
:
- Deploy this NextApp in AWS Lambda (may not be possible)
- Deploy this NextApp in AWS EKS
- Fix Email Receipt
- Fix Mobile View Cart