├── .npmrc
├── packages
├── trpc
│ ├── client
│ │ ├── index.ts
│ │ └── links
│ │ │ └── httpBatchLink.ts
│ ├── index.ts
│ ├── server
│ │ ├── procedures
│ │ │ ├── index.ts
│ │ │ ├── publicProcedure.ts
│ │ │ └── protectedProcedure.ts
│ │ ├── middlewares
│ │ │ ├── openapi
│ │ │ │ └── expressMiddleware.ts
│ │ │ ├── express
│ │ │ │ └── trpcExressMiddleware.ts
│ │ │ └── auth.ts
│ │ ├── openapi.ts
│ │ ├── trpc.ts
│ │ ├── routers
│ │ │ ├── root.ts
│ │ │ └── exampleRouter.ts
│ │ └── context.ts
│ └── package.json
├── prisma
│ ├── index.ts
│ ├── .gitignore
│ ├── docker-compose.yaml
│ ├── schema.prisma
│ ├── package.json
│ └── tsconfig.json
├── ui
│ ├── postcss.config.js
│ ├── tailwind.config.js
│ ├── .eslintrc.js
│ ├── index.tsx
│ ├── header.tsx
│ ├── tsconfig.json
│ ├── button.tsx
│ ├── turbo
│ │ └── generators
│ │ │ ├── templates
│ │ │ └── component.hbs
│ │ │ └── config.ts
│ └── package.json
├── eslint-config-custom
│ ├── README.md
│ ├── package.json
│ ├── library.js
│ ├── react-internal.js
│ └── next.js
├── tailwind-config
│ ├── postcss.config.js
│ ├── package.json
│ └── tailwind.config.js
├── tsconfig
│ ├── package.json
│ ├── react-library.json
│ ├── base.json
│ └── nextjs.json
└── prettier-config
│ ├── package.json
│ └── prettier-config.js
├── tsconfig.json
├── .prettierrc.js
├── apps
├── docs
│ ├── .eslintrc.js
│ ├── next.config.js
│ ├── app
│ │ ├── page.tsx
│ │ └── layout.tsx
│ ├── next-env.d.ts
│ ├── tsconfig.json
│ ├── .gitignore
│ ├── package.json
│ └── README.md
├── web
│ ├── postcss.config.js
│ ├── .eslintrc.json
│ ├── styles
│ │ └── globals.css
│ ├── tailwind.config.js
│ ├── next.config.js
│ ├── next-env.d.ts
│ ├── pages
│ │ ├── _app.tsx
│ │ ├── _document.tsx
│ │ ├── api
│ │ │ └── hello.ts
│ │ └── index.tsx
│ ├── tsconfig.json
│ ├── .gitignore
│ ├── package.json
│ ├── utils
│ │ └── trpc.ts
│ └── README.md
└── server
│ ├── tsconfig.json
│ ├── package.json
│ └── index.ts
├── .env.example
├── .prettierignore
├── .gitignore
├── package.json
├── turbo.json
├── LICENSE
└── README.md
/.npmrc:
--------------------------------------------------------------------------------
1 | auto-install-peers = true
2 |
--------------------------------------------------------------------------------
/packages/trpc/client/index.ts:
--------------------------------------------------------------------------------
1 | export * from "./";
--------------------------------------------------------------------------------
/packages/trpc/index.ts:
--------------------------------------------------------------------------------
1 | export * from "./";
2 |
--------------------------------------------------------------------------------
/packages/prisma/index.ts:
--------------------------------------------------------------------------------
1 | export * from "@prisma/client";
2 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "tsconfig/base.json"
3 | }
4 |
--------------------------------------------------------------------------------
/.prettierrc.js:
--------------------------------------------------------------------------------
1 | module.exports = require("prettier-config/prettier-config.js");
--------------------------------------------------------------------------------
/apps/docs/.eslintrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | extends: ["custom/next"],
3 | };
4 |
--------------------------------------------------------------------------------
/apps/web/postcss.config.js:
--------------------------------------------------------------------------------
1 | module.exports = require("tailwind-config/postcss.config.js")
--------------------------------------------------------------------------------
/apps/web/.eslintrc.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": ["next/core-web-vitals", "prettier"]
3 | }
4 |
--------------------------------------------------------------------------------
/apps/web/styles/globals.css:
--------------------------------------------------------------------------------
1 | @tailwind base;
2 | @tailwind components;
3 | @tailwind utilities;
--------------------------------------------------------------------------------
/apps/web/tailwind.config.js:
--------------------------------------------------------------------------------
1 | module.exports = require("tailwind-config/tailwind.config.js")
--------------------------------------------------------------------------------
/packages/trpc/client/links/httpBatchLink.ts:
--------------------------------------------------------------------------------
1 | export { httpBatchLink } from "@trpc/client";
2 |
--------------------------------------------------------------------------------
/packages/ui/postcss.config.js:
--------------------------------------------------------------------------------
1 | module.exports = require("tailwind-config/postcss.config.js")
--------------------------------------------------------------------------------
/packages/ui/tailwind.config.js:
--------------------------------------------------------------------------------
1 | module.exports = require("tailwind-config/tailwind.config.js")
--------------------------------------------------------------------------------
/packages/ui/.eslintrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | extends: ["custom/react-internal"],
3 | };
4 |
--------------------------------------------------------------------------------
/packages/prisma/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | # Keep environment variables out of version control
3 | .env
4 |
--------------------------------------------------------------------------------
/packages/ui/index.tsx:
--------------------------------------------------------------------------------
1 | // component exports
2 | export * from "./button";
3 | export * from "./header";
4 |
--------------------------------------------------------------------------------
/apps/docs/next.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | reactStrictMode: true,
3 | transpilePackages: ["ui"],
4 | };
5 |
--------------------------------------------------------------------------------
/packages/trpc/server/procedures/index.ts:
--------------------------------------------------------------------------------
1 | export * from "./protectedProcedure";
2 | export * from "./publicProcedure";
--------------------------------------------------------------------------------
/packages/eslint-config-custom/README.md:
--------------------------------------------------------------------------------
1 | # `@turbo/eslint-config`
2 |
3 | Collection of internal eslint configurations.
4 |
--------------------------------------------------------------------------------
/packages/trpc/server/middlewares/openapi/expressMiddleware.ts:
--------------------------------------------------------------------------------
1 | export { createOpenApiExpressMiddleware } from "trpc-openapi";
2 |
--------------------------------------------------------------------------------
/packages/ui/header.tsx:
--------------------------------------------------------------------------------
1 | export function Header({ text }: { text: string }): JSX.Element {
2 | return
{text} ;
3 | }
4 |
--------------------------------------------------------------------------------
/packages/trpc/server/procedures/publicProcedure.ts:
--------------------------------------------------------------------------------
1 | import { t } from "../trpc";
2 |
3 | export const publicProcedure = t.procedure;
4 |
--------------------------------------------------------------------------------
/packages/trpc/server/middlewares/express/trpcExressMiddleware.ts:
--------------------------------------------------------------------------------
1 | export { createExpressMiddleware } from "@trpc/server/adapters/express";
2 |
--------------------------------------------------------------------------------
/packages/tailwind-config/postcss.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | plugins: {
3 | tailwindcss: {},
4 | autoprefixer: {},
5 | },
6 | }
7 |
--------------------------------------------------------------------------------
/packages/ui/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "tsconfig/react-library.json",
3 | "include": ["."],
4 | "exclude": ["dist", "build", "node_modules"]
5 | }
6 |
--------------------------------------------------------------------------------
/apps/web/next.config.js:
--------------------------------------------------------------------------------
1 | /** @type {import('next').NextConfig} */
2 | const nextConfig = {
3 | reactStrictMode: true,
4 | transpilePackages: ["ui"]
5 | }
6 |
7 | module.exports = nextConfig
8 |
--------------------------------------------------------------------------------
/packages/trpc/server/procedures/protectedProcedure.ts:
--------------------------------------------------------------------------------
1 | import { isAuthed } from "../middlewares/auth";
2 | import { t } from "../trpc";
3 |
4 | export const protectedProcedure = t.procedure.use(isAuthed);
5 |
--------------------------------------------------------------------------------
/packages/tsconfig/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "tsconfig",
3 | "version": "0.0.0",
4 | "private": true,
5 | "license": "MIT",
6 | "publishConfig": {
7 | "access": "public"
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/packages/tailwind-config/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "tailwind-config",
3 | "version": "0.0.0",
4 | "private": true,
5 | "license": "MIT",
6 | "publishConfig": {
7 | "access": "public"
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/apps/server/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "tsconfig/base.json",
3 | "compilerOptions": {
4 | "target": "es6",
5 | "module": "commonjs",
6 | "rootDir": "./",
7 | "outDir": "./build"
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/apps/docs/app/page.tsx:
--------------------------------------------------------------------------------
1 | import { Button, Header } from "ui";
2 |
3 | export default function Page(): JSX.Element {
4 | return (
5 | <>
6 |
7 |
8 | >
9 | );
10 | }
11 |
--------------------------------------------------------------------------------
/apps/web/next-env.d.ts:
--------------------------------------------------------------------------------
1 | ///
2 | ///
3 |
4 | // NOTE: This file should not be edited
5 | // see https://nextjs.org/docs/basic-features/typescript for more information.
6 |
--------------------------------------------------------------------------------
/apps/docs/next-env.d.ts:
--------------------------------------------------------------------------------
1 | ///
2 | ///
3 |
4 | // NOTE: This file should not be edited
5 | // see https://nextjs.org/docs/basic-features/typescript for more information.
6 |
--------------------------------------------------------------------------------
/.env.example:
--------------------------------------------------------------------------------
1 | SERVER_DEPLOY_URL=
2 | NEXT_PUBLIC_SERVER_PORT=3002
3 |
4 | DATABASE_URL="postgresql://USER:PASSWORD@HOST:PORT/DATABASE"
5 |
6 | # Docker compose DB connection string
7 | # DATABASE_URL="postgresql://postgres:postgres@localhost:5001/prisma"
--------------------------------------------------------------------------------
/apps/docs/app/layout.tsx:
--------------------------------------------------------------------------------
1 | export default function RootLayout({
2 | children,
3 | }: {
4 | children: React.ReactNode;
5 | }): JSX.Element {
6 | return (
7 |
8 | {children}
9 |
10 | );
11 | }
12 |
--------------------------------------------------------------------------------
/apps/docs/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "tsconfig/nextjs.json",
3 | "compilerOptions": {
4 | "plugins": [{ "name": "next" }]
5 | },
6 | "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
7 | "exclude": ["node_modules"]
8 | }
9 |
--------------------------------------------------------------------------------
/packages/eslint-config-custom/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "eslint-config-custom",
3 | "license": "MIT",
4 | "version": "0.0.0",
5 | "private": true,
6 | "devDependencies": {
7 | "@vercel/style-guide": "^4.0.2",
8 | "eslint-config-turbo": "^1.10.12"
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/apps/web/pages/_app.tsx:
--------------------------------------------------------------------------------
1 | import type { AppProps } from "next/app";
2 | import "../styles/globals.css";
3 | import { trpc } from "../utils/trpc";
4 |
5 | function App({ Component, pageProps }: AppProps) {
6 | return ;
7 | }
8 |
9 | export default trpc.withTRPC(App);
10 |
--------------------------------------------------------------------------------
/packages/prettier-config/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "prettier-config",
3 | "version": "0.0.0",
4 | "private": true,
5 | "license": "MIT",
6 | "publishConfig": {
7 | "access": "public"
8 | },
9 | "devDependencies": {
10 | "prettier-plugin-tailwindcss": "^0.5.3"
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/packages/ui/button.tsx:
--------------------------------------------------------------------------------
1 | "use client";
2 |
3 | export function Button(): JSX.Element {
4 | return (
5 | // eslint-disable-next-line no-alert
6 | alert("booped")} type="button">
7 | Boop
8 |
9 | );
10 | }
11 |
--------------------------------------------------------------------------------
/packages/trpc/server/openapi.ts:
--------------------------------------------------------------------------------
1 | import { generateOpenApiDocument } from "trpc-openapi";
2 | import { appRouter } from "./routers/root";
3 |
4 | export const openApiDocument = generateOpenApiDocument(appRouter, {
5 | title: "tRPC OpenAPI",
6 | version: "1.0.0",
7 | baseUrl: "http://localhost:3002/api",
8 | });
9 |
--------------------------------------------------------------------------------
/apps/web/pages/_document.tsx:
--------------------------------------------------------------------------------
1 | import { Html, Head, Main, NextScript } from "next/document";
2 |
3 | export default function Document() {
4 | return (
5 |
6 |
8 |
9 |
10 |
11 |
12 | );
13 | }
14 |
--------------------------------------------------------------------------------
/.prettierignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | .next
3 | public
4 | **/**/node_modules
5 | **/**/.next
6 | **/**/public
7 |
8 | *.lock
9 | *.log
10 | *.test.ts
11 |
12 | .gitignore
13 | .npmignore
14 | .prettierignore
15 | .DS_Store
16 | .eslintignore
17 | packages/prisma/zod
18 | packages/prisma/enums
19 | apps/web/public/embed
20 |
--------------------------------------------------------------------------------
/packages/tsconfig/react-library.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "https://json.schemastore.org/tsconfig",
3 | "display": "React Library",
4 | "extends": "./base.json",
5 | "compilerOptions": {
6 | "jsx": "react-jsx",
7 | "lib": ["ES2015", "DOM"],
8 | "module": "ESNext",
9 | "target": "es6"
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/packages/prisma/docker-compose.yaml:
--------------------------------------------------------------------------------
1 | services:
2 | database:
3 | image: postgres
4 | ports:
5 | - 5001:5432
6 | environment:
7 | - POSTGRES_USER=postgres
8 | - POSTGRES_PASSWORD=postgres
9 | - POSTGRES_DB=prisma
10 | volumes:
11 | - pgdata:/var/lib/postgresql/data
12 | volumes:
13 | pgdata:
--------------------------------------------------------------------------------
/packages/trpc/server/trpc.ts:
--------------------------------------------------------------------------------
1 | import { inferAsyncReturnType, initTRPC } from "@trpc/server";
2 | import { OpenApiMeta } from "trpc-openapi";
3 | import { createContext } from "./context";
4 |
5 | export type Context = inferAsyncReturnType;
6 | export const t = initTRPC.context().meta().create();
7 |
--------------------------------------------------------------------------------
/packages/ui/turbo/generators/templates/component.hbs:
--------------------------------------------------------------------------------
1 | import * as React from "react";
2 |
3 | interface Props {
4 | children?: React.ReactNode;
5 | }
6 |
7 | export const {{ pascalCase name }} = ({ children }: Props) => {
8 | return (
9 |
10 |
{{ name }}
11 | {children}
12 |
13 | );
14 | };
15 |
--------------------------------------------------------------------------------
/packages/trpc/server/routers/root.ts:
--------------------------------------------------------------------------------
1 | import { t } from "../trpc";
2 | import { exampleRouter } from "./exampleRouter";
3 |
4 | // Create routes in /routers and add them in appRouter/index.ts
5 | export const appRouter = t.router({
6 | // Add new routes here
7 | example: exampleRouter,
8 | });
9 |
10 | export type AppRouter = typeof appRouter;
11 |
--------------------------------------------------------------------------------
/apps/web/pages/api/hello.ts:
--------------------------------------------------------------------------------
1 | // Next.js API route support: https://nextjs.org/docs/api-routes/introduction
2 | import type { NextApiRequest, NextApiResponse } from 'next'
3 |
4 | type Data = {
5 | name: string
6 | }
7 |
8 | export default function handler(
9 | req: NextApiRequest,
10 | res: NextApiResponse
11 | ) {
12 | res.status(200).json({ name: 'Example call from NextJs server' })
13 | }
14 |
--------------------------------------------------------------------------------
/packages/tailwind-config/tailwind.config.js:
--------------------------------------------------------------------------------
1 | /** @type {import('tailwindcss').Config} */
2 | module.exports = {
3 | content: [
4 | // apps content
5 | `src/**/*.{js,ts,jsx,tsx}`,
6 | `./pages/**/*.{js,ts,jsx,tsx}`,
7 | `./components/**/*.{js,ts,jsx,tsx}`,
8 | // packages content
9 | '../../packages/**/*.{js,ts,jsx,tsx}',
10 | ],
11 | theme: {
12 | extend: {},
13 | },
14 | plugins: [],
15 | }
16 |
17 |
--------------------------------------------------------------------------------
/packages/prettier-config/prettier-config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | semi: true,
3 | bracketSpacing: true,
4 | bracketSameLine: true,
5 | singleQuote: false,
6 | printWidth: 110,
7 | plugins: [
8 | /**
9 | * **NOTE** tailwind plugin must come last!
10 | * @see https://github.com/tailwindlabs/prettier-plugin-tailwindcss#compatibility-with-other-prettier-plugins
11 | */
12 | "prettier-plugin-tailwindcss",
13 | ],
14 | };
15 |
--------------------------------------------------------------------------------
/packages/prisma/schema.prisma:
--------------------------------------------------------------------------------
1 | // This is your Prisma schema file,
2 | // learn more about it in the docs: https://pris.ly/d/prisma-schema
3 |
4 | generator client {
5 | provider = "prisma-client-js"
6 | }
7 |
8 | datasource db {
9 | provider = "postgresql"
10 | url = env("DATABASE_URL")
11 | }
12 |
13 | model Example {
14 | id Int @id @default(autoincrement())
15 | createdAt DateTime @default(now())
16 | name String @unique
17 | }
--------------------------------------------------------------------------------
/packages/trpc/server/middlewares/auth.ts:
--------------------------------------------------------------------------------
1 | import { TRPCError } from "@trpc/server";
2 | import { t } from "../trpc";
3 |
4 | // Middleware
5 | export const isAuthed = t.middleware(({ next, ctx }) => {
6 | if (!ctx.userSession) {
7 | throw new TRPCError({
8 | code: "UNAUTHORIZED",
9 | });
10 | }
11 |
12 | return next({
13 | ctx: {
14 | // Infers the `userSession` as non-nullable
15 | userSession: ctx.userSession,
16 | },
17 | });
18 | });
19 |
--------------------------------------------------------------------------------
/apps/web/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "tsconfig/nextjs.json",
3 | "compilerOptions": {
4 | "lib": [
5 | "dom",
6 | "dom.iterable",
7 | "esnext"
8 | ],
9 | "allowJs": true,
10 | "noEmit": true,
11 | "incremental": true,
12 | "module": "esnext",
13 | "resolveJsonModule": true,
14 | "jsx": "preserve",
15 | "strict": true
16 | },
17 | "include": [
18 | "next-env.d.ts",
19 | "**/*.ts",
20 | "**/*.tsx"
21 | ]
22 | }
23 |
--------------------------------------------------------------------------------
/apps/web/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | /node_modules
5 | /.pnp
6 | .pnp.js
7 |
8 | # testing
9 | /coverage
10 |
11 | # next.js
12 | /.next/
13 | /out/
14 |
15 | # production
16 | /build
17 |
18 | # misc
19 | .DS_Store
20 | *.pem
21 |
22 | # debug
23 | npm-debug.log*
24 | yarn-debug.log*
25 | yarn-error.log*
26 |
27 | # local env files
28 | .env*.local
29 |
30 | # vercel
31 | .vercel
32 |
33 | # typescript
34 | *.tsbuildinfo
35 | next-env.d.ts
36 |
--------------------------------------------------------------------------------
/apps/docs/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | /node_modules
5 | /.pnp
6 | .pnp.js
7 |
8 | # testing
9 | /coverage
10 |
11 | # next.js
12 | /.next/
13 | /out/
14 |
15 | # production
16 | /build
17 |
18 | # misc
19 | .DS_Store
20 | *.pem
21 |
22 | # debug
23 | npm-debug.log*
24 | yarn-debug.log*
25 | yarn-error.log*
26 |
27 | # local env files
28 | .env.local
29 | .env.development.local
30 | .env.test.local
31 | .env.production.local
32 |
33 | # vercel
34 | .vercel
35 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | node_modules
5 | .pnp
6 | .pnp.js
7 |
8 | # testing
9 | coverage
10 |
11 | # next.js
12 | .next/
13 | out/
14 | build
15 |
16 | # misc
17 | .DS_Store
18 | *.pem
19 |
20 | # debug
21 | npm-debug.log*
22 | yarn-debug.log*
23 | yarn-error.log*
24 |
25 | # local env files
26 | .env
27 | .env.local
28 | .env.development.local
29 | .env.test.local
30 | .env.production.local
31 |
32 | # turbo
33 | .turbo
34 |
35 | # vercel
36 | .vercel
37 |
38 | # misc
39 | local_notes.txt
40 |
--------------------------------------------------------------------------------
/packages/trpc/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@template/trpc",
3 | "version": "1.0.0",
4 | "main": "index.ts",
5 | "private": true,
6 | "scripts": {
7 | "test": "echo \"Error: no test specified\" && exit 1"
8 | },
9 | "keywords": [],
10 | "author": "",
11 | "license": "ISC",
12 | "dependencies": {
13 | "@trpc/client": "^10.38.2",
14 | "@trpc/server": "^10.38.2",
15 | "@types/express": "^4.17.17",
16 | "@types/node": "^20.6.0",
17 | "trpc-openapi": "^1.2.0",
18 | "zod": "^3.22.2",
19 | "@template/prisma": "*"
20 | },
21 | "description": ""
22 | }
23 |
--------------------------------------------------------------------------------
/packages/trpc/server/context.ts:
--------------------------------------------------------------------------------
1 | import type { CreateExpressContextOptions } from "@trpc/server/adapters/express";
2 | import { PrismaClient } from "@template/prisma";
3 |
4 | // created for each request
5 | export const createContext = ({ req, res }: CreateExpressContextOptions) => {
6 | const prisma = new PrismaClient();
7 | // return { } // No Context
8 |
9 | // Example context
10 | // Hardcoding userSession, normally you would call getSession from something like nextAuth to populate this
11 | // Check ./routers/exampleInput.exampleInput
12 | return { userSession: true, prisma: prisma };
13 | };
14 |
--------------------------------------------------------------------------------
/packages/ui/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "ui",
3 | "version": "0.0.0",
4 | "main": "./index.tsx",
5 | "types": "./index.tsx",
6 | "license": "MIT",
7 | "scripts": {
8 | "lint": "eslint .",
9 | "generate:component": "turbo gen react-component"
10 | },
11 | "devDependencies": {
12 | "@turbo/gen": "^1.10.12",
13 | "@types/node": "^20.5.2",
14 | "@types/react": "^18.2.0",
15 | "@types/react-dom": "^18.2.0",
16 | "eslint-config-custom": "*",
17 | "react": "^18.2.0",
18 | "tsconfig": "*",
19 | "typescript": "^4.5.2",
20 | "tailwind-config": "*"
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/packages/tsconfig/base.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "https://json.schemastore.org/tsconfig",
3 | "display": "Default",
4 | "compilerOptions": {
5 | "composite": false,
6 | "declaration": true,
7 | "declarationMap": true,
8 | "esModuleInterop": true,
9 | "forceConsistentCasingInFileNames": true,
10 | "inlineSources": false,
11 | "isolatedModules": true,
12 | "moduleResolution": "node",
13 | "noUnusedLocals": false,
14 | "noUnusedParameters": false,
15 | "preserveWatchOutput": true,
16 | "skipLibCheck": true,
17 | "strict": true,
18 | "strictNullChecks": true
19 | },
20 | "exclude": ["node_modules"]
21 | }
22 |
--------------------------------------------------------------------------------
/packages/tsconfig/nextjs.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "https://json.schemastore.org/tsconfig",
3 | "display": "Next.js",
4 | "extends": "./base.json",
5 | "compilerOptions": {
6 | "plugins": [{ "name": "next" }],
7 | "allowJs": true,
8 | "declaration": false,
9 | "declarationMap": false,
10 | "incremental": true,
11 | "jsx": "preserve",
12 | "lib": ["dom", "dom.iterable", "esnext"],
13 | "module": "esnext",
14 | "noEmit": true,
15 | "resolveJsonModule": true,
16 | "strictNullChecks": true,
17 | "strict": true,
18 | "target": "es5"
19 | },
20 | "include": ["src", "next-env.d.ts"],
21 | "exclude": ["node_modules"]
22 | }
23 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "private": true,
3 | "scripts": {
4 | "build": "turbo run build",
5 | "dev": "dotenv -- turbo run dev",
6 | "prisma": "dotenv -- yarn workspace @template/prisma",
7 | "lint": "turbo run lint",
8 | "format": "prettier --write \"**/*.{ts,tsx,md}\""
9 | },
10 | "devDependencies": {
11 | "eslint": "^8.47.0",
12 | "prettier": "^3.0.2",
13 | "prettier-config": "*",
14 | "tsconfig": "*",
15 | "turbo": "latest",
16 | "dotenv-cli": "^7.3.0"
17 | },
18 | "name": "trpc-server-client-turborepo-template",
19 | "packageManager": "yarn@1.22.19",
20 | "workspaces": [
21 | "apps/*",
22 | "packages/*"
23 | ]
24 | }
25 |
--------------------------------------------------------------------------------
/apps/docs/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "docs",
3 | "version": "1.0.0",
4 | "private": true,
5 | "scripts": {
6 | "dev": "next dev --port 3001",
7 | "build": "next build",
8 | "start": "next start",
9 | "lint": "next lint"
10 | },
11 | "dependencies": {
12 | "next": "^13.4.19",
13 | "react": "^18.2.0",
14 | "react-dom": "^18.2.0",
15 | "ui": "*"
16 | },
17 | "devDependencies": {
18 | "@next/eslint-plugin-next": "^13.4.19",
19 | "@types/node": "^17.0.12",
20 | "@types/react": "^18.0.22",
21 | "@types/react-dom": "^18.0.7",
22 | "eslint-config-custom": "*",
23 | "tsconfig": "*",
24 | "typescript": "^4.5.3"
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/packages/prisma/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@template/prisma",
3 | "version": "1.0.0",
4 | "description": "",
5 | "main": "./index.ts",
6 | "types": "./index.ts",
7 | "scripts": {
8 | "test": "echo \"Error: no test specified\" && exit 1",
9 | "migrate": "prisma migrate dev",
10 | "studio": "prisma studio",
11 | "db-up": "docker-compose up -d"
12 | },
13 | "keywords": [],
14 | "author": "",
15 | "license": "ISC",
16 | "dependencies": {
17 | "@prisma/client": "^5.3.1",
18 | "@types/node": "^20.6.2",
19 | "prisma": "^5.3.1",
20 | "ts-node": "^10.9.1",
21 | "typescript": "^5.2.2"
22 | },
23 | "devDependencies": {
24 | "dotenv-cli": "^7.3.0"
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/packages/prisma/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "tsconfig/base.json",
3 | "compilerOptions": {
4 | "target": "es2016" /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */,
5 | "module": "commonjs" /* Specify what module code is generated. */,
6 | "outDir": "./dist" /* Specify an output folder for all emitted files. */,
7 | "esModuleInterop": true /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */,
8 | "forceConsistentCasingInFileNames": true /* Ensure that casing is correct in imports. */,
9 | "strict": true /* Enable all strict type-checking options. */,
10 | "skipLibCheck": true /* Skip type checking all .d.ts files. */
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/turbo.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "https://turbo.build/schema.json",
3 | "globalDotEnv": [".env"],
4 | "globalDependencies": ["**/.env.*local"],
5 | "pipeline": {
6 | "build": {
7 | "dependsOn": ["^build"],
8 | "outputs": [".next/**", "!.next/cache/**"],
9 | "dotEnv": [
10 | ".env.production.local",
11 | ".env.local",
12 | ".env.production",
13 | ".env"
14 | ]
15 | },
16 | "dev": {
17 | "cache": false,
18 | "persistent": false,
19 | "dotEnv": [
20 | ".env.development.local",
21 | ".env.local",
22 | ".env.development",
23 | ".env"
24 | ]
25 | },
26 | "test": {
27 | "dotEnv": [".env.test.local", ".env.test", ".env"]
28 | },
29 | "migrate":{
30 | "cache": false
31 | },
32 | "lint": {}
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/packages/eslint-config-custom/library.js:
--------------------------------------------------------------------------------
1 | const { resolve } = require("node:path");
2 |
3 | const project = resolve(process.cwd(), "tsconfig.json");
4 |
5 | /*
6 | * This is a custom ESLint configuration for use with
7 | * typescript packages.
8 | *
9 | * This config extends the Vercel Engineering Style Guide.
10 | * For more information, see https://github.com/vercel/style-guide
11 | *
12 | */
13 |
14 | module.exports = {
15 | extends: [
16 | "@vercel/style-guide/eslint/node",
17 | "@vercel/style-guide/eslint/typescript",
18 | ].map(require.resolve),
19 | parserOptions: {
20 | project,
21 | },
22 | globals: {
23 | React: true,
24 | JSX: true,
25 | },
26 | settings: {
27 | "import/resolver": {
28 | typescript: {
29 | project,
30 | },
31 | },
32 | },
33 | ignorePatterns: ["node_modules/", "dist/"],
34 | };
35 |
--------------------------------------------------------------------------------
/apps/server/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "server",
3 | "version": "1.0.0",
4 | "description": "",
5 | "main": "index.ts",
6 | "scripts": {
7 | "build": "esbuild index.ts --bundle --platform=node --outfile=build/index.js --external:swagger-ui-dist",
8 | "dev": "nodemon index.ts",
9 | "test": "echo \"Error: no test specified\" && exit 1"
10 | },
11 | "keywords": [],
12 | "author": "",
13 | "license": "ISC",
14 | "dependencies": {
15 | "@template/trpc": "*",
16 | "@types/express": "^4.17.17",
17 | "@types/node": "^20.5.8",
18 | "@types/swagger-ui-express": "^4.1.3",
19 | "cors": "^2.8.5",
20 | "express": "^4.18.2",
21 | "nodemon": "^3.0.1",
22 | "swagger-ui-express": "^5.0.0",
23 | "ts-node": "^10.9.1",
24 | "typescript": "^5.2.2"
25 | },
26 | "devDependencies": {
27 | "@types/cors": "^2.8.13",
28 | "esbuild": "^0.19.3",
29 | "tsconfig": "*"
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/packages/ui/turbo/generators/config.ts:
--------------------------------------------------------------------------------
1 | import type { PlopTypes } from "@turbo/gen";
2 |
3 | // Learn more about Turborepo Generators at https://turbo.build/repo/docs/core-concepts/monorepos/code-generation
4 |
5 | export default function generator(plop: PlopTypes.NodePlopAPI): void {
6 | // A simple generator to add a new React component to the internal UI library
7 | plop.setGenerator("react-component", {
8 | description: "Adds a new react component",
9 | prompts: [
10 | {
11 | type: "input",
12 | name: "name",
13 | message: "What is the name of the component?",
14 | },
15 | ],
16 | actions: [
17 | {
18 | type: "add",
19 | path: "{{pascalCase name}}.tsx",
20 | templateFile: "templates/component.hbs",
21 | },
22 | {
23 | type: "append",
24 | path: "index.tsx",
25 | pattern: /(?\/\/ component exports)/g,
26 | template: 'export * from "./{{pascalCase name}}";',
27 | },
28 | ],
29 | });
30 | }
31 |
--------------------------------------------------------------------------------
/apps/web/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "web",
3 | "version": "0.1.0",
4 | "private": true,
5 | "scripts": {
6 | "dev": "next dev",
7 | "build": "next build",
8 | "start": "next start",
9 | "lint": "next lint"
10 | },
11 | "dependencies": {
12 | "@tanstack/react-query": "^4.33.0",
13 | "@trpc/client": "^10.38.1",
14 | "@trpc/next": "^10.38.1",
15 | "@trpc/react-query": "^10.38.1",
16 | "@types/node": "20.5.6",
17 | "@types/react": "18.2.21",
18 | "@types/react-dom": "18.2.7",
19 | "eslint": "8.48.0",
20 | "eslint-config-next": "13.4.19",
21 | "eslint-plugin-prettier": "^5.0.0",
22 | "next": "13.4.19",
23 | "react": "18.2.0",
24 | "react-dom": "18.2.0",
25 | "typescript": "5.2.2",
26 | "ui": "*",
27 | "zod": "^3.22.2",
28 | "@template/trpc": "*"
29 | },
30 | "devDependencies": {
31 | "autoprefixer": "^10.4.15",
32 | "eslint-config-custom": "*",
33 | "postcss": "^8.4.28",
34 | "tailwind-config": "*",
35 | "tailwindcss": "^3.3.3",
36 | "tsconfig": "*"
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/packages/eslint-config-custom/react-internal.js:
--------------------------------------------------------------------------------
1 | const { resolve } = require("node:path");
2 |
3 | const project = resolve(process.cwd(), "tsconfig.json");
4 |
5 | /*
6 | * This is a custom ESLint configuration for use with
7 | * internal (bundled by their consumer) libraries
8 | * that utilize React.
9 | *
10 | * This config extends the Vercel Engineering Style Guide.
11 | * For more information, see https://github.com/vercel/style-guide
12 | *
13 | */
14 |
15 | module.exports = {
16 | extends: [
17 | "@vercel/style-guide/eslint/browser",
18 | "@vercel/style-guide/eslint/typescript",
19 | "@vercel/style-guide/eslint/react",
20 | ].map(require.resolve),
21 | parserOptions: {
22 | project,
23 | },
24 | globals: {
25 | JSX: true,
26 | },
27 | settings: {
28 | "import/resolver": {
29 | typescript: {
30 | project,
31 | },
32 | },
33 | },
34 | ignorePatterns: ["node_modules/", "dist/", ".eslintrc.js"],
35 | // add rules configurations here
36 | rules: {
37 | "import/no-default-export": "off",
38 | },
39 | };
40 |
--------------------------------------------------------------------------------
/packages/eslint-config-custom/next.js:
--------------------------------------------------------------------------------
1 | const { resolve } = require("node:path");
2 |
3 | const project = resolve(process.cwd(), "tsconfig.json");
4 |
5 | /*
6 | * This is a custom ESLint configuration for use with
7 | * Next.js apps.
8 | *
9 | * This config extends the Vercel Engineering Style Guide.
10 | * For more information, see https://github.com/vercel/style-guide
11 | *
12 | */
13 |
14 | module.exports = {
15 | extends: [
16 | "@vercel/style-guide/eslint/typescript",
17 | "@vercel/style-guide/eslint/browser",
18 | "@vercel/style-guide/eslint/react",
19 | "@vercel/style-guide/eslint/next",
20 | "eslint-config-turbo",
21 | ].map(require.resolve),
22 | parserOptions: {
23 | project,
24 | },
25 | globals: {
26 | React: true,
27 | JSX: true,
28 | },
29 | settings: {
30 | "import/resolver": {
31 | typescript: {
32 | project,
33 | },
34 | },
35 | },
36 | ignorePatterns: ["node_modules/", "dist/"],
37 | // add rules configurations here
38 | rules: {
39 | "import/no-default-export": "off",
40 | },
41 | };
42 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2023 Manak Kumar Singh
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/apps/web/utils/trpc.ts:
--------------------------------------------------------------------------------
1 | import { httpBatchLink } from '@template/trpc/client/links/httpBatchLink';
2 | import { createTRPCNext } from '@trpc/next';
3 | import type { AppRouter } from '@template/trpc/server/routers/root';
4 |
5 | function getBaseUrl() {
6 | if (process.env.SERVER_DEPLOY_URL)
7 | return `https://${process.env.SERVER_DEPLOY_URL}`;
8 |
9 | // assume localhost
10 | return `http://localhost:${process.env.NEXT_PUBLIC_SERVER_PORT}`;
11 | }
12 |
13 | export const trpc = createTRPCNext({
14 | config(opts) {
15 | return {
16 | links: [
17 | httpBatchLink({
18 | /**
19 | * If you want to use SSR, you need to use the server's full URL
20 | * @link https://trpc.io/docs/ssr
21 | **/
22 | url: `${getBaseUrl()}/api/trpc`,
23 |
24 | // You can pass any HTTP headers you wish here
25 | async headers() {
26 | return {
27 | // authorization: getAuthCookie(),
28 | };
29 | },
30 | }),
31 | ],
32 | };
33 | },
34 | /**
35 | * @link https://trpc.io/docs/ssr
36 | **/
37 | ssr: false,
38 | });
--------------------------------------------------------------------------------
/apps/server/index.ts:
--------------------------------------------------------------------------------
1 | import { createContext } from "@template/trpc/server/context";
2 | import { createExpressMiddleware } from "@template/trpc/server/middlewares/express/trpcExressMiddleware";
3 | import { appRouter } from "@template/trpc/server/routers/root";
4 | import cors from "cors";
5 | import express from "express";
6 |
7 | import swaggerUi from "swagger-ui-express";
8 |
9 | import { createOpenApiExpressMiddleware } from "@template/trpc/server/middlewares/openapi/expressMiddleware";
10 | import { openApiDocument } from "@template/trpc/server/openapi";
11 |
12 | const port: number = 3002 as const;
13 |
14 | // Initialize the express engine
15 | const app: express.Application = express();
16 |
17 | app.use(cors());
18 |
19 | // Handle incoming tRPC requests
20 | app.use(
21 | "/api/trpc",
22 | createExpressMiddleware({
23 | router: appRouter,
24 | createContext,
25 | }),
26 | );
27 |
28 | // Handle incoming OpenAPI requests
29 | app.use("/api", createOpenApiExpressMiddleware({ router: appRouter, createContext }));
30 |
31 | // Serve Swagger UI with our OpenAPI schema
32 | app.use("/", swaggerUi.serve);
33 | app.get("/", swaggerUi.setup(openApiDocument));
34 |
35 | // Server setup
36 | app.listen(port, () => {
37 | console.log(`started server on [::]:${port}, url: http://localhost:${port}`);
38 | });
39 |
--------------------------------------------------------------------------------
/apps/docs/README.md:
--------------------------------------------------------------------------------
1 | ## Getting Started
2 |
3 | First, run the development server:
4 |
5 | ```bash
6 | yarn dev
7 | ```
8 |
9 | Open [http://localhost:3001](http://localhost:3001) with your browser to see the result.
10 |
11 | You can start editing the page by modifying `app/page.tsx`. The page auto-updates as you edit the file.
12 |
13 | To create [API routes](https://nextjs.org/docs/app/building-your-application/routing/router-handlers) add an `api/` directory to the `app/` directory with a `route.ts` file. For individual endpoints, create a subfolder in the `api` directory, like `api/hello/route.ts` would map to [http://localhost:3001/api/hello](http://localhost:3001/api/hello).
14 |
15 | ## Learn More
16 |
17 | To learn more about Next.js, take a look at the following resources:
18 |
19 | - [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API.
20 | - [Learn Next.js](https://nextjs.org/learn/foundations/about-nextjs) - an interactive Next.js tutorial.
21 |
22 | You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js/) - your feedback and contributions are welcome!
23 |
24 | ## Deploy on Vercel
25 |
26 | The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_source=github.com&utm_medium=referral&utm_campaign=turborepo-readme) from the creators of Next.js.
27 |
28 | Check out our [Next.js deployment documentation](https://nextjs.org/docs/deployment) for more details.
29 |
--------------------------------------------------------------------------------
/apps/web/README.md:
--------------------------------------------------------------------------------
1 | This is a [Next.js](https://nextjs.org/) project bootstrapped with [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app).
2 |
3 | ## Getting Started
4 |
5 | First, run the development server:
6 |
7 | ```bash
8 | npm run dev
9 | # or
10 | yarn dev
11 | # or
12 | pnpm dev
13 | ```
14 |
15 | Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.
16 |
17 | You can start editing the page by modifying `pages/index.tsx`. The page auto-updates as you edit the file.
18 |
19 | [API routes](https://nextjs.org/docs/api-routes/introduction) can be accessed on [http://localhost:3000/api/hello](http://localhost:3000/api/hello). This endpoint can be edited in `pages/api/hello.ts`.
20 |
21 | The `pages/api` directory is mapped to `/api/*`. Files in this directory are treated as [API routes](https://nextjs.org/docs/api-routes/introduction) instead of React pages.
22 |
23 | This project uses [`next/font`](https://nextjs.org/docs/basic-features/font-optimization) to automatically optimize and load Inter, a custom Google Font.
24 |
25 | ## Learn More
26 |
27 | To learn more about Next.js, take a look at the following resources:
28 |
29 | - [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API.
30 | - [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial.
31 |
32 | You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js/) - your feedback and contributions are welcome!
33 |
34 | ## Deploy on Vercel
35 |
36 | The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js.
37 |
38 | Check out our [Next.js deployment documentation](https://nextjs.org/docs/deployment) for more details.
39 |
--------------------------------------------------------------------------------
/apps/web/pages/index.tsx:
--------------------------------------------------------------------------------
1 | import { useEffect } from "react";
2 | import { Button } from "ui";
3 | import { trpc } from "../utils/trpc";
4 |
5 | export default function Home() {
6 | useEffect(() => {
7 | const asyncFn = async () => {
8 | // An API call for NextJS Server
9 | const sendRequest = await fetch("http://localhost:3000/api/hello");
10 | const data = await sendRequest.json();
11 | console.log(data);
12 | };
13 |
14 | asyncFn();
15 | }, []);
16 |
17 | // API call for apps/api Express tRPC server
18 | const {
19 | data: exampleCall,
20 | isLoading: isExampleCallLoading,
21 | isError: isExampleCallError,
22 | } = trpc.example.exampleInput.useQuery({
23 | id: "someStringId",
24 | });
25 |
26 | // Database call
27 | const {
28 | data: exampleDbCall,
29 | isLoading: isDbCallLoading,
30 | isError: dbCallError,
31 | } = trpc.example.prismaExample.useQuery();
32 |
33 | return (
34 |
35 |
36 |
Web Page
37 | {isExampleCallError ? (
38 |
Something went wrong
39 | ) : isExampleCallLoading ? (
40 |
Loading...
41 | ) : (
42 |
43 |
User Details
44 |
45 | ID : {exampleCall?.id}
46 |
47 |
48 | User Session : {exampleCall?.hasSession ? "true" : "false"}
49 |
50 |
51 | )}
52 |
53 |
54 |
55 |
Database Call
56 | {dbCallError ? (
57 |
Something is wrong with the database
58 | ) : isDbCallLoading ? (
59 |
Calling database...
60 | ) : (
61 |
{JSON.stringify(exampleDbCall)}
62 | )}
63 |
64 |
65 |
66 |
67 |
68 |
69 | );
70 | }
71 |
--------------------------------------------------------------------------------
/packages/trpc/server/routers/exampleRouter.ts:
--------------------------------------------------------------------------------
1 | import { z } from "zod";
2 | import { protectedProcedure, publicProcedure } from "../procedures";
3 | import { t } from "../trpc";
4 |
5 | export const exampleRouter = t.router({
6 | // http://localhost:3002/api/example.exampleApi
7 | exampleApi: publicProcedure
8 | .meta({
9 | openapi: {
10 | method: "GET",
11 | path: "/example.exampleApi",
12 | tags: ["example"],
13 | description: "Calling exampleApi",
14 | },
15 | })
16 | .input(z.void())
17 | .output(z.object({ message: z.string() }))
18 | .query(() => {
19 | return { message: "Sending message from route" };
20 | }),
21 |
22 | // http://localhost:3002/api/example.exampleInput?id=123123
23 | exampleInput: publicProcedure
24 | .meta({ openapi: { method: "GET", path: "/example.exampleInput", tags: ["example"] } })
25 | .input(z.object({ id: z.string() }))
26 | .output(z.object({ id: z.string(), hasSession: z.boolean() }))
27 | .query(({ input, ctx }) => {
28 | // return { id: req.input, name: 'Bilbo'};
29 |
30 | // Add context in context.ts file and call it using req.ctx
31 | return { id: input.id, hasSession: ctx.userSession };
32 | }),
33 |
34 | superSimple: publicProcedure
35 | .meta({ openapi: { method: "POST", path: "/example.superSimple", tags: ["example"] } })
36 | .input(z.object({ simpleInput: z.string() }))
37 | .output(z.object({ givenString: z.string() }))
38 | .mutation(({ input }) => {
39 | return { givenString: input.simpleInput };
40 | }),
41 |
42 | // Change userSession to true / false in /context.ts for this procedure to work
43 | protectedExample: protectedProcedure
44 | .meta({ openapi: { method: "GET", path: "/example.protectedExample", tags: ["example"] } })
45 | .input(z.void())
46 | .output(z.object({ context: z.boolean(), message: z.string() }))
47 | .query(({ ctx }) => {
48 | return { context: ctx.userSession, message: "Protected example message" };
49 | }),
50 |
51 | prismaExample: publicProcedure
52 | .meta({ openapi: { method: "GET", path: "/example.prismaExample", tags: ["exampleDB"] } })
53 | .input(z.void())
54 | .output(
55 | z.object({
56 | context: z.boolean(),
57 | dbData: z.array(z.object({ id: z.number(), createdAt: z.date(), name: z.string() })),
58 | }),
59 | )
60 | .query(async ({ ctx }) => {
61 | const getExampleData = await ctx.prisma.example.findMany();
62 | console.log("Database Data : ", getExampleData);
63 | return { context: ctx.userSession, dbData: getExampleData };
64 | }),
65 | });
66 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # tRPC Server Client Turborepo Template
2 |
3 | 🚧 **This is a TEMPLATE** 🚧
4 |
5 | A clean **template** designed to kickstart your project, sparing you the effort of configuring everything from scratch.
6 |
7 | This is a straightforward monorepo that includes an Express tRPC server with Prisma ORM. The server interacts with a Next.js application and provides a wide range of features through tRPC.
8 |
9 | With this template, you can quickly set up a powerful server-client architecture for your web application. The combination of Express, tRPC, Prisma and Next.js offers a seamless development experience and enables you to build robust and efficient applications with the ease of adding API documentation through OpenApi and SwaggerUI which comes integrated into this template.
10 |
11 | Feel free to use this template as a starting point for your projects and customize it according to your specific requirements.
12 |
13 | ## What's inside?
14 |
15 | This Turborepo includes the following packages/apps:
16 |
17 | ### Apps and Packages
18 |
19 | - `apps/docs`: A simple [Next.js](https://nextjs.org/) app that can be used to compare changes made to the `apps/web` application. It serves as a reference to understand the modifications.
20 | - `apps/server`: This is a TypeScript Express [tRPC](https://trpc.io/) server with [swaggerUI](https://github.com/swagger-api/swagger-ui). It provides the backend functionality for your application and handles API requests. `packages/trpc` is connected to the server and contains all the procedures.
21 | - `apps/web`: another [Next.js](https://nextjs.org/) app with [tRPC](https://trpc.io/) Client which interacts with `api` package. It also incorporates [TailwindCSS](https://tailwindcss.com/) for styling.
22 | - `packages/trpc`: everything related to [tRPC](https://trpc.io/) including procedures and [trpc-openapi](https://github.com/jlalmes/trpc-openapi) exists in this package folder which is currently being used by `server`.
23 | - `packages/ui`: a stub React component library shared by both `web` and `docs` applications. It includes reusable components and is styled using [TailwindCSS](https://tailwindcss.com/).
24 | - `packages/prisma`: A powerful database ORM that offers type safety and is utilized by the `trpc` package to enhance the developer experience.
25 | - `packages/eslint-config-custom`: `eslint` configurations (includes `eslint-config-next` and `eslint-config-prettier`)
26 | - `packages/tsconfig`: `tsconfig.json`s used throughout the monorepo
27 | - `packages/tailwind-config`: tailwind configuration which is used throughout the monorepo
28 | - `packages/prettier-config`: This package includes the styling configuration for Prettier, ensuring consistent code formatting throughout the monorepo
29 |
30 | ### Project Setup
31 |
32 | In the root directory, install dependencies by running.
33 |
34 | ```
35 | cd trpc-server-client-turborepo-template
36 | yarn
37 | ```
38 |
39 | **Setting up .env file** - Copy .env.example file and rename it to .env in the root directory
40 |
41 | #### Setting up Database
42 |
43 | To configure the database for your project, you have two options:
44 |
45 | 1. If you have postgresql database ready, add the connection string to `DATABASE_URL`.
46 |
47 | 2. If you don't have a database and have Docker installed on your system, you can easily set it up using the following script command in your CLI:
48 |
49 | ```
50 | yarn prisma db-up
51 | ```
52 |
53 | Note : To check the environment details you can find the docker-compose file in `packages/prisma/docker-compose.yaml`
54 |
55 | ### Scripts
56 |
57 | Scripts can be ran in the root directory by typing the following in cli.
58 |
59 | - `yarn run dev` : Runs the entire monorepo.
60 | - `yarn prisma studio` : Runs prisma studio from `package/prisma`
61 | - `yarn prisma migrate` : Runs prisma database migrations from `package/prisma`
62 | - `yarn prisma db-up` : Installs/Runs postgresql image from `package/prisma` in Docker.
63 |
64 | ### Build
65 |
66 | To build all apps and packages, run the following command:
67 |
68 | ```
69 | cd trpc-server-client-turborepo-template
70 | yarn
71 | ```
72 |
73 | ### Remote Caching
74 |
75 | Turborepo can use a technique known as [Remote Caching](https://turbo.build/repo/docs/core-concepts/remote-caching) to share cache artifacts across machines, enabling you to share build caches with your team and CI/CD pipelines.
76 |
77 | By default, Turborepo will cache locally. To enable Remote Caching you will need an account with Vercel. If you don't have an account you can [create one](https://vercel.com/signup), then enter the following commands:
78 |
79 | ```
80 | cd trpc-server-client-turborepo-template
81 | npx turbo login
82 | ```
83 |
84 | This will authenticate the Turborepo CLI with your [Vercel account](https://vercel.com/docs/concepts/personal-accounts/overview).
85 |
86 | Next, you can link your Turborepo to your Remote Cache by running the following command from the root of your Turborepo:
87 |
88 | ```
89 | npx turbo link
90 | ```
91 |
92 | ## Contributions
93 |
94 | I welcome contributions to help improve this template! If you have any issues or recommendations for enhancements, please feel free to raise them. Your feedback is valuable and will help me make this template even better.
95 |
96 | To contribute, you can:
97 |
98 | - **Raise an issue**: If you encounter any problems or have suggestions for improvements, please create an issue on this GitHub repository. I will review it and work together with you to find a solution.
99 |
100 | - **Submit a pull request**: If you have a specific improvement in mind, you can fork the repository, make your changes, and submit a pull request. I will review your changes and merge them if they align with the project's goals.
101 |
102 | By contributing to this template, you'll be helping not only me but also the community by making it more robust and user-friendly!
103 | At the moment I would really appreciate some help with file structure recommendations for Turborepo for the technologies inside the repository.
104 |
105 | Thank you for your support!
106 |
--------------------------------------------------------------------------------