This is a T3 Stack project bootstrapped with create-t3-app
.
This project is a guestbook / twitter clone. It allows users to create, like, and comment posts.
- Authentication with Discord and GitHub.
- Create, read, edit, and delete posts: You can edit a post by clicking on the post. Edit and delete are only possible on your own posts.
- Like and unlike posts (only possible on other users posts).
- Comment on posts (only possible on other users posts), delete comments (only the author of the comment can delete it).
- Visit your user profile (by clicking on your username). (
/user
route) - Add an address to your profile.
- Subscribe to a paid plan to unlock the ability to post messages (by clicking on the "Subscribe" button in the
/user
route). The subscription is handled by Stripe. The subscription is cancelled after 30 days. You can use the test credit card nuumber to test the subscription (see Stripe Local Setup below).
These instructions will get you a copy of the project up and running on your local machine for development and testing purposes.
- Node.js v 18. Just run
nvm use
to use the correct version. - Docker
- Docker Compose
- Stripe CLI installed globally (
npm i -g stripe
)
- To get started, clone the repository and run
npm install
in the root. - Copy
.env.example
, rename it to.env
. DATABASE_URL
is the connection string to your database. Just useDATABASE_URL=mysql://root:password@localhost:3306/testdb
for now.- For authentication paste your Discord client ID and secret in
DISCORD_CLIENT_ID
andDISCORD_CLIENT_SECRET
(same goes for GitHub). You can get these from the Discord Developer Portal. - Run
npm run docker:up
to start the database. - Run
npx prisma db push
to push the schema to your database and generate the TypeScript types for the Prisma Client based on your schema. Make sure to restart the TS Server after this step so that it can detect the generated types. - Run
npm run db:seed
to seed the database (OPTIONAL). - Run
npm run dev
to start the development server. - Install and run Stripe by following Stripe Local Setup below (OPTIONAL).
- Open http://localhost:3000 with your browser to see the result.
- Run
npx prisma studio
to open the Prisma Studio to view your database. - Run
npm run docker:down
to stop the database when you’re done. This will also delete all the data in your database.
- Install the Stripe CLI by running
npm install -g stripe
. - Run
stripe login
and follow the prompts to connect your Stripe account. - Run
npm run stripe:listen
to start the Stripe CLI. - In your .env file, add the following environment variables:
STRIPE_PK
STRIPE_SK
STRIPE_WEBHOOK_SECRET
- The webhook secret provided by the Stripe CLI.STRIPE_PRICE_ID
- The price ID of your Stripe product.
- To test Stripe you can use the following test card numbers:
4242 4242 4242 4242
- A successful payment.- For more test card numbers, refer to the Stripe documentation.
- Before running the tests, make sure you have the database running with
npm run docker:up
. Also make sure you have the database seeded withnpm run db:seed
. - Run
npm run test
to run the tests.
The libs
folder contains shared libraries for mocking and testing the backend (prisma and tRPC).
The prisma schema. It contains the database schema and migrations. It also contains the seed data.
Static assets.
React components.
Validation for environment variables.
All the pages of the website.
Next.js API routes.
The NextAuth.js authentication slug route. This is used to authenticate users with Discord and GitHub (more providers can be added).
The tRPC API entrypoint. This file is here to handle all the API requests.
The backend, which is a tRPC server. It contains the tRPC router, context, and the prisma client.
A helper function to get the user session from the NextAuth.js session.
The prisma client. It is used to initialize the Prisma client at global scope and to query the database.
The Stripe API. It contains the Stripe API client and the Stripe API routes. It also contains the Stripe webhook handler. The Stripe API routes are used to create a Stripe checkout session and to retrieve the Stripe customer.
It contains the tRPC router with the tRPC queries and mutations. The tRPC router is used to initialize the tRPC router at global scope. The tRPC router is also used to handle the tRPC queries and mutations. The tRPC queries and mutations are used to retrieve and update data in the database. The tRPC queries and mutations are also used to retrieve and update data in the Stripe API.
Global CSS files, but we use Tailwind CSS for most of our styles.
Next Auth type declarations.
Utility functions.
This file is the main front-end entrypoint to tRPC
The frontend is built with Next.js. It uses Tailwind CSS for styling. It uses tRPC for data fetching and state management. It uses NextAuth.js for authentication.
The backend is built with tRPC and Typescript. It uses Prisma as an ORM with Zod as schema validation. It uses Tanstack Query for declarative, always-up-to-date and auto-managed queries and mutations. It uses Stripe for payments. It uses NextAuth.js for authentication. It also uses Docker to quick and easy run the database locally.
The whole Next.js application is deployed at Vercel. The MySQL database is deployed at Planetscale.
tRPC enables the creation of end-to-end typesafe APIs while eliminating code generation and runtime bloat. It takes advantage of TypeScript's excellent inference capabilities to deduce your API router's type definitions, providing complete typesafety and autocompletion when calling API procedures from your frontend.
Prisma is a modern database toolkit. It replaces traditional ORMs and makes database access easy with an auto-generated query builder for TypeScript & Node.js. By generating types from a Prisma schema, you can use Prisma Client to access your database inside your application’s TypeScript code with guaranteed type-safety and autocompletion.
Zod is a schema validation library built on top of Typescript. Write a schema that represents a single source of truth for your data, and Zod will ensure that your data is valid throughout your application, even across network boundaries and external APIs.
Stripe is a payment processing platform. It is used to process payments for the website.
NextAuth.js is a complete open source authentication solution for Next.js applications. It is used to authenticate users with Discord and GitHub (more providers can be added) with a complex and secure OAuth flow. NextAuth.js also provides a session management system with support for JWT and database sessions (Prisma is used for database sessions).
tRPC is used for the API. It is a typesafe API framework for TypeScript. It is used to create an API router with queries and mutations. It is also used to create an API client to call the API router from the frontend.
- Query #1:
post.getAllMessages
- Get all the posts. - Query #2:
post.getAllComments
- Get all comments. - Mutation #1:
post.postMessage
- Create a new post. - Mutation #2:
post.deleteMessage
- Delete a message. - Mutation #3:
post.updateMessage
- Edit a message. - Mutation #4:
post.likeMessage
- Like a message. - Mutation #5:
post.unlikeMessage
- Unlike a message. - Mutation #6:
post.addComment
- Comment on a post. - Mutation #7:
post.deleteComment
- Delete a comment.
- Query #1:
user.subscriptionStatus
- Get the user's subscription status. - Query #2:
user.getUserAddress
- Get the user's address. - Mutation #1:
user.addUserAddress
- Create the user's address. - Mutation #2:
user.updateUserAddress
- Update the user's address.
- Query #1:
stripe.createCheckoutSession
- Create a Stripe checkout session. - Query #2:
stripe.createBillingPortalSession
- Create a Stripe billing portal session.
- Query #1:
auth.getSession
- Get the user's session. - Query #2:
auth.getSecretMessage
- Get the secret message.
The database is defined in the prisma/schema.prisma
file. The Prisma Schema is the single source of truth for the database. It is used to generate the Prisma Client, which is used to access the database from the backend. It is also used to generate the TypeScript types for the database schema, which is used to access the database from the frontend.
The database is a MySQL database. It is hosted on Planet Scale.
For all use cases check out the API Design chapter.
- I made the decision that a post can have multiple likes but one user can like one specific post just once. If the user likes the post again, the like will be removed. This is done to prevent spamming likes by one user. If a user deletes a post, all likes on that post will be deleted as well.
- A user can only have one single address. If the user adds a new address, the old address will be overwritten. This is done to prevent spamming addresses. If a user deletes their account, the address will be deleted as well.
- I made the decision that a user can only have one single subscription. If the user subscribes again, the old subscription will be overwritten. If a user deletes their account, the subscription will be deleted as well.
- One or more posts can have one or more categories (many-to-many relationship). I decided to implement this many-to-many relation as an explicit m-n-relation. It consists now of two models with m-n-relation (Post and Category) and one additional model that represents the relation table of the two models (CategoriesOnPost).
This project is deployed on Vercel. Here is a step by step guide on how to deploy the project to Vercel:
- Create a new project on Vercel and link it to your GitHub repository.
- Add the following environment variables to your Vercel project:
DATABASE_URL
- Your database connection string (You can use Planet Scale to get a free online MySQL database in under 5 minutes.)DISCORD_CLIENT_ID
- Your Discord client ID.DISCORD_CLIENT_SECRET
- Your Discord client secret.NEXTAUTH_SECRET
- A secret for NextAuth.js.GITHUB_SECRET
- A GitHub client secret.GITHUB_ID
- A GitHub client ID.
- Deploy your project to Vercel.
- Create a
.env.production
file in the root of your project and add theDATABASE_URL
environment variable of your production database (e.g. the database url from your database hosted on Planet Scale). - Run
npx prisma migrate dev
to to create a new migration. - You can now run
npm run prisma:migrate:deploy:prod
to apply the latest migration to your production database.
Please refer to the Vercel documentation for more information on how to deploy your Next.js project to Vercel.