feat: initial commit
- `pnpm create t3-app@latest`
This commit is contained in:
commit
e06ecdf652
20 changed files with 3524 additions and 0 deletions
25
.env.example
Normal file
25
.env.example
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
# Since the ".env" file is gitignored, you can use the ".env.example" file to
|
||||
# build a new ".env" file when you clone the repo. Keep this file up-to-date
|
||||
# when you add new variables to `.env`.
|
||||
|
||||
# This file will be committed to version control, so make sure not to have any
|
||||
# secrets in it. If you are cloning this repo, create a copy of this file named
|
||||
# ".env" and populate it with your secrets.
|
||||
|
||||
# When adding additional environment variables, the schema in "/src/env.mjs"
|
||||
# should be updated accordingly.
|
||||
|
||||
# Prisma
|
||||
# https://www.prisma.io/docs/reference/database-reference/connection-urls#env
|
||||
DATABASE_URL="file:./db.sqlite"
|
||||
|
||||
# Next Auth
|
||||
# You can generate a new secret on the command line with:
|
||||
# openssl rand -base64 32
|
||||
# https://next-auth.js.org/configuration/options#secret
|
||||
# NEXTAUTH_SECRET=""
|
||||
NEXTAUTH_URL="http://localhost:3000"
|
||||
|
||||
# Next Auth Discord Provider
|
||||
DISCORD_CLIENT_ID=""
|
||||
DISCORD_CLIENT_SECRET=""
|
||||
35
.eslintrc.cjs
Normal file
35
.eslintrc.cjs
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
||||
const path = require("path");
|
||||
|
||||
/** @type {import("eslint").Linter.Config} */
|
||||
const config = {
|
||||
overrides: [
|
||||
{
|
||||
extends: [
|
||||
"plugin:@typescript-eslint/recommended-requiring-type-checking",
|
||||
],
|
||||
files: ["*.ts", "*.tsx"],
|
||||
parserOptions: {
|
||||
project: path.join(__dirname, "tsconfig.json"),
|
||||
},
|
||||
},
|
||||
],
|
||||
parser: "@typescript-eslint/parser",
|
||||
parserOptions: {
|
||||
project: path.join(__dirname, "tsconfig.json"),
|
||||
},
|
||||
plugins: ["@typescript-eslint"],
|
||||
extends: ["next/core-web-vitals", "plugin:@typescript-eslint/recommended"],
|
||||
rules: {
|
||||
"@typescript-eslint/consistent-type-imports": [
|
||||
"warn",
|
||||
{
|
||||
prefer: "type-imports",
|
||||
fixStyle: "inline-type-imports",
|
||||
},
|
||||
],
|
||||
"@typescript-eslint/no-unused-vars": ["warn", { argsIgnorePattern: "^_" }],
|
||||
},
|
||||
};
|
||||
|
||||
module.exports = config;
|
||||
42
.gitignore
vendored
Normal file
42
.gitignore
vendored
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
|
||||
|
||||
# dependencies
|
||||
/node_modules
|
||||
/.pnp
|
||||
.pnp.js
|
||||
|
||||
# testing
|
||||
/coverage
|
||||
|
||||
# database
|
||||
/prisma/db.sqlite
|
||||
/prisma/db.sqlite-journal
|
||||
|
||||
# next.js
|
||||
/.next/
|
||||
/out/
|
||||
next-env.d.ts
|
||||
|
||||
# production
|
||||
/build
|
||||
|
||||
# misc
|
||||
.DS_Store
|
||||
*.pem
|
||||
|
||||
# debug
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
.pnpm-debug.log*
|
||||
|
||||
# local env files
|
||||
# do not commit any .env files to git, except for the .env.example file. https://create.t3.gg/en/usage/env-variables#using-environment-variables
|
||||
.env
|
||||
.env*.local
|
||||
|
||||
# vercel
|
||||
.vercel
|
||||
|
||||
# typescript
|
||||
*.tsbuildinfo
|
||||
28
README.md
Normal file
28
README.md
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
# Create T3 App
|
||||
|
||||
This is a [T3 Stack](https://create.t3.gg/) project bootstrapped with `create-t3-app`.
|
||||
|
||||
## What's next? How do I make an app with this?
|
||||
|
||||
We try to keep this project as simple as possible, so you can start with just the scaffolding we set up for you, and add additional things later when they become necessary.
|
||||
|
||||
If you are not familiar with the different technologies used in this project, please refer to the respective docs. If you still are in the wind, please join our [Discord](https://t3.gg/discord) and ask for help.
|
||||
|
||||
- [Next.js](https://nextjs.org)
|
||||
- [NextAuth.js](https://next-auth.js.org)
|
||||
- [Prisma](https://prisma.io)
|
||||
- [Tailwind CSS](https://tailwindcss.com)
|
||||
- [tRPC](https://trpc.io)
|
||||
|
||||
## Learn More
|
||||
|
||||
To learn more about the [T3 Stack](https://create.t3.gg/), take a look at the following resources:
|
||||
|
||||
- [Documentation](https://create.t3.gg/)
|
||||
- [Learn the T3 Stack](https://create.t3.gg/en/faq#what-learning-resources-are-currently-available) — Check out these awesome tutorials
|
||||
|
||||
You can check out the [create-t3-app GitHub repository](https://github.com/t3-oss/create-t3-app) — your feedback and contributions are welcome!
|
||||
|
||||
## How do I deploy this?
|
||||
|
||||
Follow our deployment guides for [Vercel](https://create.t3.gg/en/deployment/vercel), [Netlify](https://create.t3.gg/en/deployment/netlify) and [Docker](https://create.t3.gg/en/deployment/docker) for more information.
|
||||
23
next.config.mjs
Normal file
23
next.config.mjs
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
/**
|
||||
* Run `build` or `dev` with `SKIP_ENV_VALIDATION` to skip env validation. This is especially useful
|
||||
* for Docker builds.
|
||||
*/
|
||||
await import("./src/env.mjs");
|
||||
|
||||
/** @type {import("next").NextConfig} */
|
||||
const config = {
|
||||
reactStrictMode: true,
|
||||
|
||||
/**
|
||||
* If you have `experimental: { appDir: true }` set, then you must comment the below `i18n` config
|
||||
* out.
|
||||
*
|
||||
* @see https://github.com/vercel/next.js/issues/41980
|
||||
*/
|
||||
i18n: {
|
||||
locales: ["en"],
|
||||
defaultLocale: "en",
|
||||
},
|
||||
};
|
||||
|
||||
export default config;
|
||||
43
package.json
Normal file
43
package.json
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
{
|
||||
"name": "backoffice",
|
||||
"version": "0.1.0",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"build": "next build",
|
||||
"dev": "next dev",
|
||||
"postinstall": "prisma generate",
|
||||
"lint": "next lint",
|
||||
"start": "next start"
|
||||
},
|
||||
"dependencies": {
|
||||
"@next-auth/prisma-adapter": "^1.0.5",
|
||||
"@prisma/client": "^4.14.0",
|
||||
"@t3-oss/env-nextjs": "^0.3.1",
|
||||
"next": "^13.4.2",
|
||||
"next-auth": "^4.22.1",
|
||||
"react": "18.2.0",
|
||||
"react-dom": "18.2.0",
|
||||
"zod": "^3.21.4"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/eslint": "^8.37.0",
|
||||
"@types/node": "^18.16.0",
|
||||
"@types/prettier": "^2.7.2",
|
||||
"@types/react": "^18.2.6",
|
||||
"@types/react-dom": "^18.2.4",
|
||||
"@typescript-eslint/eslint-plugin": "^5.59.6",
|
||||
"@typescript-eslint/parser": "^5.59.6",
|
||||
"autoprefixer": "^10.4.14",
|
||||
"eslint": "^8.40.0",
|
||||
"eslint-config-next": "^13.4.2",
|
||||
"postcss": "^8.4.21",
|
||||
"prettier": "^2.8.8",
|
||||
"prettier-plugin-tailwindcss": "^0.2.8",
|
||||
"prisma": "^4.14.0",
|
||||
"tailwindcss": "^3.3.0",
|
||||
"typescript": "^5.0.4"
|
||||
},
|
||||
"ct3aMetadata": {
|
||||
"initVersion": "7.14.1"
|
||||
}
|
||||
}
|
||||
2991
pnpm-lock.yaml
generated
Normal file
2991
pnpm-lock.yaml
generated
Normal file
File diff suppressed because it is too large
Load diff
8
postcss.config.cjs
Normal file
8
postcss.config.cjs
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
const config = {
|
||||
plugins: {
|
||||
tailwindcss: {},
|
||||
autoprefixer: {},
|
||||
},
|
||||
};
|
||||
|
||||
module.exports = config;
|
||||
6
prettier.config.cjs
Normal file
6
prettier.config.cjs
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
/** @type {import("prettier").Config} */
|
||||
const config = {
|
||||
plugins: [require.resolve("prettier-plugin-tailwindcss")],
|
||||
};
|
||||
|
||||
module.exports = config;
|
||||
67
prisma/schema.prisma
Normal file
67
prisma/schema.prisma
Normal file
|
|
@ -0,0 +1,67 @@
|
|||
// This is your Prisma schema file,
|
||||
// learn more about it in the docs: https://pris.ly/d/prisma-schema
|
||||
|
||||
generator client {
|
||||
provider = "prisma-client-js"
|
||||
previewFeatures = ["jsonProtocol"]
|
||||
}
|
||||
|
||||
datasource db {
|
||||
provider = "sqlite"
|
||||
// NOTE: When using mysql or sqlserver, uncomment the @db.Text annotations in model Account below
|
||||
// Further reading:
|
||||
// https://next-auth.js.org/adapters/prisma#create-the-prisma-schema
|
||||
// https://www.prisma.io/docs/reference/api-reference/prisma-schema-reference#string
|
||||
url = env("DATABASE_URL")
|
||||
}
|
||||
|
||||
model Example {
|
||||
id String @id @default(cuid())
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
}
|
||||
|
||||
// Necessary for Next auth
|
||||
model Account {
|
||||
id String @id @default(cuid())
|
||||
userId String
|
||||
type String
|
||||
provider String
|
||||
providerAccountId String
|
||||
refresh_token String? // @db.Text
|
||||
access_token String? // @db.Text
|
||||
expires_at Int?
|
||||
token_type String?
|
||||
scope String?
|
||||
id_token String? // @db.Text
|
||||
session_state String?
|
||||
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
||||
|
||||
@@unique([provider, providerAccountId])
|
||||
}
|
||||
|
||||
model Session {
|
||||
id String @id @default(cuid())
|
||||
sessionToken String @unique
|
||||
userId String
|
||||
expires DateTime
|
||||
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
||||
}
|
||||
|
||||
model User {
|
||||
id String @id @default(cuid())
|
||||
name String?
|
||||
email String? @unique
|
||||
emailVerified DateTime?
|
||||
image String?
|
||||
accounts Account[]
|
||||
sessions Session[]
|
||||
}
|
||||
|
||||
model VerificationToken {
|
||||
identifier String
|
||||
token String @unique
|
||||
expires DateTime
|
||||
|
||||
@@unique([identifier, token])
|
||||
}
|
||||
BIN
public/favicon.ico
Normal file
BIN
public/favicon.ico
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 15 KiB |
54
src/env.mjs
Normal file
54
src/env.mjs
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
import { createEnv } from "@t3-oss/env-nextjs";
|
||||
import { z } from "zod";
|
||||
|
||||
export const env = createEnv({
|
||||
/**
|
||||
* Specify your server-side environment variables schema here. This way you can ensure the app
|
||||
* isn't built with invalid env vars.
|
||||
*/
|
||||
server: {
|
||||
DATABASE_URL: z.string().url(),
|
||||
NODE_ENV: z.enum(["development", "test", "production"]),
|
||||
NEXTAUTH_SECRET:
|
||||
process.env.NODE_ENV === "production"
|
||||
? z.string().min(1)
|
||||
: z.string().min(1).optional(),
|
||||
NEXTAUTH_URL: z.preprocess(
|
||||
// This makes Vercel deployments not fail if you don't set NEXTAUTH_URL
|
||||
// Since NextAuth.js automatically uses the VERCEL_URL if present.
|
||||
(str) => process.env.VERCEL_URL ?? str,
|
||||
// VERCEL_URL doesn't include `https` so it cant be validated as a URL
|
||||
process.env.VERCEL ? z.string().min(1) : z.string().url(),
|
||||
),
|
||||
// Add `.min(1) on ID and SECRET if you want to make sure they're not empty
|
||||
DISCORD_CLIENT_ID: z.string(),
|
||||
DISCORD_CLIENT_SECRET: z.string(),
|
||||
},
|
||||
|
||||
/**
|
||||
* Specify your client-side environment variables schema here. This way you can ensure the app
|
||||
* isn't built with invalid env vars. To expose them to the client, prefix them with
|
||||
* `NEXT_PUBLIC_`.
|
||||
*/
|
||||
client: {
|
||||
// NEXT_PUBLIC_CLIENTVAR: z.string().min(1),
|
||||
},
|
||||
|
||||
/**
|
||||
* You can't destruct `process.env` as a regular object in the Next.js edge runtimes (e.g.
|
||||
* middlewares) or client-side so we need to destruct manually.
|
||||
*/
|
||||
runtimeEnv: {
|
||||
DATABASE_URL: process.env.DATABASE_URL,
|
||||
NODE_ENV: process.env.NODE_ENV,
|
||||
NEXTAUTH_SECRET: process.env.NEXTAUTH_SECRET,
|
||||
NEXTAUTH_URL: process.env.NEXTAUTH_URL,
|
||||
DISCORD_CLIENT_ID: process.env.DISCORD_CLIENT_ID,
|
||||
DISCORD_CLIENT_SECRET: process.env.DISCORD_CLIENT_SECRET,
|
||||
},
|
||||
/**
|
||||
* Run `build` or `dev` with `SKIP_ENV_VALIDATION` to skip env validation.
|
||||
* This is especially useful for Docker builds.
|
||||
*/
|
||||
skipValidation: !!process.env.SKIP_ENV_VALIDATION,
|
||||
});
|
||||
17
src/pages/_app.tsx
Normal file
17
src/pages/_app.tsx
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
import { type Session } from "next-auth";
|
||||
import { SessionProvider } from "next-auth/react";
|
||||
import { type AppType } from "next/app";
|
||||
import "~/styles/globals.css";
|
||||
|
||||
const MyApp: AppType<{ session: Session | null }> = ({
|
||||
Component,
|
||||
pageProps: { session, ...pageProps },
|
||||
}) => {
|
||||
return (
|
||||
<SessionProvider session={session}>
|
||||
<Component {...pageProps} />
|
||||
</SessionProvider>
|
||||
);
|
||||
};
|
||||
|
||||
export default MyApp;
|
||||
4
src/pages/api/auth/[...nextauth].ts
Normal file
4
src/pages/api/auth/[...nextauth].ts
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
import NextAuth from "next-auth";
|
||||
import { authOptions } from "~/server/auth";
|
||||
|
||||
export default NextAuth(authOptions);
|
||||
45
src/pages/index.tsx
Normal file
45
src/pages/index.tsx
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
import Head from "next/head";
|
||||
import Link from "next/link";
|
||||
|
||||
export default function Home() {
|
||||
return (
|
||||
<>
|
||||
<Head>
|
||||
<title>Create T3 App</title>
|
||||
<meta name="description" content="Generated by create-t3-app" />
|
||||
<link rel="icon" href="/favicon.ico" />
|
||||
</Head>
|
||||
<main className="flex min-h-screen flex-col items-center justify-center bg-gradient-to-b from-[#2e026d] to-[#15162c]">
|
||||
<div className="container flex flex-col items-center justify-center gap-12 px-4 py-16 ">
|
||||
<h1 className="text-5xl font-extrabold tracking-tight text-white sm:text-[5rem]">
|
||||
Create <span className="text-[hsl(280,100%,70%)]">T3</span> App
|
||||
</h1>
|
||||
<div className="grid grid-cols-1 gap-4 sm:grid-cols-2 md:gap-8">
|
||||
<Link
|
||||
className="flex max-w-xs flex-col gap-4 rounded-xl bg-white/10 p-4 text-white hover:bg-white/20"
|
||||
href="https://create.t3.gg/en/usage/first-steps"
|
||||
target="_blank"
|
||||
>
|
||||
<h3 className="text-2xl font-bold">First Steps →</h3>
|
||||
<div className="text-lg">
|
||||
Just the basics - Everything you need to know to set up your
|
||||
database and authentication.
|
||||
</div>
|
||||
</Link>
|
||||
<Link
|
||||
className="flex max-w-xs flex-col gap-4 rounded-xl bg-white/10 p-4 text-white hover:bg-white/20"
|
||||
href="https://create.t3.gg/en/introduction"
|
||||
target="_blank"
|
||||
>
|
||||
<h3 className="text-2xl font-bold">Documentation →</h3>
|
||||
<div className="text-lg">
|
||||
Learn more about Create T3 App, the libraries it uses, and how
|
||||
to deploy it.
|
||||
</div>
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
</>
|
||||
);
|
||||
}
|
||||
76
src/server/auth.ts
Normal file
76
src/server/auth.ts
Normal file
|
|
@ -0,0 +1,76 @@
|
|||
import { PrismaAdapter } from "@next-auth/prisma-adapter";
|
||||
import { type GetServerSidePropsContext } from "next";
|
||||
import {
|
||||
getServerSession,
|
||||
type NextAuthOptions,
|
||||
type DefaultSession,
|
||||
} from "next-auth";
|
||||
import DiscordProvider from "next-auth/providers/discord";
|
||||
import { env } from "~/env.mjs";
|
||||
import { prisma } from "~/server/db";
|
||||
|
||||
/**
|
||||
* Module augmentation for `next-auth` types. Allows us to add custom properties to the `session`
|
||||
* object and keep type safety.
|
||||
*
|
||||
* @see https://next-auth.js.org/getting-started/typescript#module-augmentation
|
||||
*/
|
||||
declare module "next-auth" {
|
||||
interface Session extends DefaultSession {
|
||||
user: {
|
||||
id: string;
|
||||
// ...other properties
|
||||
// role: UserRole;
|
||||
} & DefaultSession["user"];
|
||||
}
|
||||
|
||||
// interface User {
|
||||
// // ...other properties
|
||||
// // role: UserRole;
|
||||
// }
|
||||
}
|
||||
|
||||
/**
|
||||
* Options for NextAuth.js used to configure adapters, providers, callbacks, etc.
|
||||
*
|
||||
* @see https://next-auth.js.org/configuration/options
|
||||
*/
|
||||
export const authOptions: NextAuthOptions = {
|
||||
callbacks: {
|
||||
session: ({ session, user }) => ({
|
||||
...session,
|
||||
user: {
|
||||
...session.user,
|
||||
id: user.id,
|
||||
},
|
||||
}),
|
||||
},
|
||||
adapter: PrismaAdapter(prisma),
|
||||
providers: [
|
||||
DiscordProvider({
|
||||
clientId: env.DISCORD_CLIENT_ID,
|
||||
clientSecret: env.DISCORD_CLIENT_SECRET,
|
||||
}),
|
||||
/**
|
||||
* ...add more providers here.
|
||||
*
|
||||
* Most other providers require a bit more work than the Discord provider. For example, the
|
||||
* GitHub provider requires you to add the `refresh_token_expires_in` field to the Account
|
||||
* model. Refer to the NextAuth.js docs for the provider you want to use. Example:
|
||||
*
|
||||
* @see https://next-auth.js.org/providers/github
|
||||
*/
|
||||
],
|
||||
};
|
||||
|
||||
/**
|
||||
* Wrapper for `getServerSession` so that you don't need to import the `authOptions` in every file.
|
||||
*
|
||||
* @see https://next-auth.js.org/configuration/nextjs
|
||||
*/
|
||||
export const getServerAuthSession = (ctx: {
|
||||
req: GetServerSidePropsContext["req"];
|
||||
res: GetServerSidePropsContext["res"];
|
||||
}) => {
|
||||
return getServerSession(ctx.req, ctx.res, authOptions);
|
||||
};
|
||||
15
src/server/db.ts
Normal file
15
src/server/db.ts
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
import { PrismaClient } from "@prisma/client";
|
||||
import { env } from "~/env.mjs";
|
||||
|
||||
const globalForPrisma = globalThis as unknown as {
|
||||
prisma: PrismaClient | undefined;
|
||||
};
|
||||
|
||||
export const prisma =
|
||||
globalForPrisma.prisma ??
|
||||
new PrismaClient({
|
||||
log:
|
||||
env.NODE_ENV === "development" ? ["query", "error", "warn"] : ["error"],
|
||||
});
|
||||
|
||||
if (env.NODE_ENV !== "production") globalForPrisma.prisma = prisma;
|
||||
3
src/styles/globals.css
Normal file
3
src/styles/globals.css
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
@tailwind base;
|
||||
@tailwind components;
|
||||
@tailwind utilities;
|
||||
9
tailwind.config.ts
Normal file
9
tailwind.config.ts
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
import { type Config } from "tailwindcss";
|
||||
|
||||
export default {
|
||||
content: ["./src/**/*.{js,ts,jsx,tsx}"],
|
||||
theme: {
|
||||
extend: {},
|
||||
},
|
||||
plugins: [],
|
||||
} satisfies Config;
|
||||
33
tsconfig.json
Normal file
33
tsconfig.json
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
{
|
||||
"compilerOptions": {
|
||||
"target": "es2017",
|
||||
"lib": ["dom", "dom.iterable", "esnext"],
|
||||
"allowJs": true,
|
||||
"checkJs": true,
|
||||
"skipLibCheck": true,
|
||||
"strict": true,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"noEmit": true,
|
||||
"esModuleInterop": true,
|
||||
"module": "esnext",
|
||||
"moduleResolution": "node",
|
||||
"resolveJsonModule": true,
|
||||
"isolatedModules": true,
|
||||
"jsx": "preserve",
|
||||
"incremental": true,
|
||||
"noUncheckedIndexedAccess": true,
|
||||
"baseUrl": ".",
|
||||
"paths": {
|
||||
"~/*": ["./src/*"]
|
||||
}
|
||||
},
|
||||
"include": [
|
||||
".eslintrc.cjs",
|
||||
"next-env.d.ts",
|
||||
"**/*.ts",
|
||||
"**/*.tsx",
|
||||
"**/*.cjs",
|
||||
"**/*.mjs"
|
||||
],
|
||||
"exclude": ["node_modules"]
|
||||
}
|
||||
Reference in a new issue