chore(scaffold): Next.js 16 + Tailwind 4 + vitest project skeleton

This commit is contained in:
Dave 2026-09-16 09:37:43 +02:00
parent 6cfc7ee7cf
commit d55103ae2d
11 changed files with 3361 additions and 0 deletions

3
.env.example Normal file
View file

@ -0,0 +1,3 @@
NEXT_PUBLIC_PB_URL=http://127.0.0.1:8090
PB_SUPERUSER_EMAIL=admin@example.com
PB_SUPERUSER_PASSWORD=change-me-please

7
.gitignore vendored Normal file
View file

@ -0,0 +1,7 @@
node_modules/
.next/
.env.local
next-env.d.ts
*.tsbuildinfo
pocketbase/pocketbase
pocketbase/pb_data/

7
next.config.ts Normal file
View file

@ -0,0 +1,7 @@
import type { NextConfig } from "next";
const nextConfig: NextConfig = {
reactStrictMode: true,
};
export default nextConfig;

3198
package-lock.json generated Normal file

File diff suppressed because it is too large Load diff

32
package.json Normal file
View file

@ -0,0 +1,32 @@
{
"name": "client-board",
"version": "0.1.0",
"private": true,
"scripts": {
"dev": "next dev",
"build": "next build",
"start": "next start",
"pb": "cd pocketbase && ./pocketbase serve --http=127.0.0.1:8090",
"test": "vitest run --project unit",
"test:integration": "vitest run --project integration",
"test:all": "vitest run",
"seed": "tsx scripts/seed-demo.ts",
"lint": "next lint"
},
"dependencies": {
"next": "16.2.6",
"pocketbase": "^0.26.9",
"react": "19.2.4",
"react-dom": "19.2.4"
},
"devDependencies": {
"@tailwindcss/postcss": "^4.1.13",
"@types/node": "^24.5.2",
"@types/react": "^19.2.2",
"@types/react-dom": "^19.2.1",
"tailwindcss": "^4.1.13",
"tsx": "^4.20.6",
"typescript": "^5.9.2",
"vitest": "^3.2.4"
}
}

5
postcss.config.mjs Normal file
View file

@ -0,0 +1,5 @@
const config = {
plugins: { "@tailwindcss/postcss": {} },
};
export default config;

9
src/app/globals.css Normal file
View file

@ -0,0 +1,9 @@
@import "tailwindcss";
:root {
color-scheme: dark;
}
body {
@apply bg-neutral-950 text-neutral-100 antialiased;
}

17
src/app/layout.tsx Normal file
View file

@ -0,0 +1,17 @@
import type { Metadata } from "next";
import "./globals.css";
export const metadata: Metadata = {
title: "Client Board",
description: "Project tracking for client work",
};
export default function RootLayout({
children,
}: Readonly<{ children: React.ReactNode }>) {
return (
<html lang="en">
<body>{children}</body>
</html>
);
}

10
src/app/page.tsx Normal file
View file

@ -0,0 +1,10 @@
export default function Home() {
return (
<main className="p-8">
<h1 className="text-2xl font-semibold">Client Board</h1>
<p className="mt-2 text-neutral-400">
The board UI arrives in Plan 1b. Sign in at <code>/login</code>.
</p>
</main>
);
}

42
tsconfig.json Normal file
View file

@ -0,0 +1,42 @@
{
"compilerOptions": {
"target": "ES2022",
"lib": [
"dom",
"dom.iterable",
"esnext"
],
"allowJs": true,
"skipLibCheck": true,
"strict": true,
"noEmit": true,
"esModuleInterop": true,
"module": "esnext",
"moduleResolution": "bundler",
"resolveJsonModule": true,
"isolatedModules": true,
"jsx": "react-jsx",
"incremental": true,
"plugins": [
{
"name": "next"
}
],
"paths": {
"@/*": [
"./src/*"
]
}
},
"include": [
"next-env.d.ts",
"**/*.ts",
"**/*.tsx",
".next/types/**/*.ts",
".next/dev/types/**/*.ts"
],
"exclude": [
"node_modules",
"pocketbase"
]
}

31
vitest.config.ts Normal file
View file

@ -0,0 +1,31 @@
import { defineConfig } from "vitest/config";
import path from "node:path";
export default defineConfig({
resolve: {
alias: { "@": path.resolve(__dirname, "./src") },
},
test: {
projects: [
{
resolve: { alias: { "@": path.resolve(__dirname, "./src") } },
test: {
name: "unit",
environment: "node",
include: ["src/**/*.test.ts"],
},
},
{
resolve: { alias: { "@": path.resolve(__dirname, "./src") } },
test: {
name: "integration",
environment: "node",
include: ["tests/integration/**/*.test.ts"],
hookTimeout: 30_000,
testTimeout: 30_000,
poolOptions: { forks: { singleFork: true } },
},
},
],
},
});