nextjs-hackathon-stack 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (83) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +83 -0
  3. package/dist/index.js +152 -0
  4. package/package.json +54 -0
  5. package/template/.cursor/agents/business-intelligence.md +38 -0
  6. package/template/.cursor/agents/code-reviewer.md +74 -0
  7. package/template/.cursor/agents/frontend.md +45 -0
  8. package/template/.cursor/agents/security-researcher.md +49 -0
  9. package/template/.cursor/agents/technical-lead.md +36 -0
  10. package/template/.cursor/agents/test-qa.md +85 -0
  11. package/template/.cursor/rules/ai.mdc +53 -0
  12. package/template/.cursor/rules/architecture.mdc +42 -0
  13. package/template/.cursor/rules/coding-standards.mdc +53 -0
  14. package/template/.cursor/rules/components.mdc +33 -0
  15. package/template/.cursor/rules/data-fetching.mdc +63 -0
  16. package/template/.cursor/rules/forms.mdc +59 -0
  17. package/template/.cursor/rules/general.mdc +52 -0
  18. package/template/.cursor/rules/nextjs.mdc +46 -0
  19. package/template/.cursor/rules/security.mdc +54 -0
  20. package/template/.cursor/rules/supabase.mdc +36 -0
  21. package/template/.cursor/rules/testing.mdc +116 -0
  22. package/template/.cursor/skills/create-api-route/SKILL.md +62 -0
  23. package/template/.cursor/skills/create-feature/SKILL.md +52 -0
  24. package/template/.cursor/skills/review-branch/SKILL.md +61 -0
  25. package/template/.cursor/skills/security-audit/SKILL.md +69 -0
  26. package/template/.env.example +24 -0
  27. package/template/.requirements/README.md +15 -0
  28. package/template/.requirements/auth.md +50 -0
  29. package/template/.requirements/template.md +25 -0
  30. package/template/README.md +98 -0
  31. package/template/components.json +19 -0
  32. package/template/drizzle.config.ts +10 -0
  33. package/template/eslint.config.ts +66 -0
  34. package/template/middleware.ts +10 -0
  35. package/template/next.config.ts +31 -0
  36. package/template/package.json.tmpl +62 -0
  37. package/template/playwright.config.ts +22 -0
  38. package/template/src/app/(auth)/login/page.tsx +12 -0
  39. package/template/src/app/(protected)/layout.tsx +19 -0
  40. package/template/src/app/(protected)/page.tsx +16 -0
  41. package/template/src/app/api/auth/callback/route.ts +21 -0
  42. package/template/src/app/globals.css +1 -0
  43. package/template/src/app/layout.tsx +21 -0
  44. package/template/src/e2e/chat.spec.ts +8 -0
  45. package/template/src/e2e/home.spec.ts +8 -0
  46. package/template/src/e2e/login.spec.ts +21 -0
  47. package/template/src/features/auth/__tests__/login-form.test.tsx +43 -0
  48. package/template/src/features/auth/__tests__/use-auth.test.ts +46 -0
  49. package/template/src/features/auth/actions/login.action.ts +38 -0
  50. package/template/src/features/auth/actions/logout.action.ts +10 -0
  51. package/template/src/features/auth/components/login-form.tsx +80 -0
  52. package/template/src/features/auth/hooks/use-auth.ts +17 -0
  53. package/template/src/features/chat/__tests__/chat-ui.test.tsx +30 -0
  54. package/template/src/features/chat/__tests__/route.test.ts +19 -0
  55. package/template/src/features/chat/api/route.ts +16 -0
  56. package/template/src/features/chat/components/chat-ui.tsx +47 -0
  57. package/template/src/features/chat/hooks/use-chat.ts +1 -0
  58. package/template/src/features/tts/__tests__/route.test.ts +13 -0
  59. package/template/src/features/tts/__tests__/tts-player.test.tsx +20 -0
  60. package/template/src/features/tts/api/route.ts +14 -0
  61. package/template/src/features/tts/components/tts-player.tsx +59 -0
  62. package/template/src/features/video/__tests__/route.test.ts +13 -0
  63. package/template/src/features/video/__tests__/video-generator.test.tsx +20 -0
  64. package/template/src/features/video/api/route.ts +14 -0
  65. package/template/src/features/video/components/video-generator.tsx +56 -0
  66. package/template/src/shared/__tests__/ai.test.ts +8 -0
  67. package/template/src/shared/__tests__/minimax-media.test.ts +57 -0
  68. package/template/src/shared/__tests__/providers.test.tsx +14 -0
  69. package/template/src/shared/__tests__/schema.test.ts +18 -0
  70. package/template/src/shared/__tests__/supabase-client.test.ts +13 -0
  71. package/template/src/shared/__tests__/supabase-server.test.ts +22 -0
  72. package/template/src/shared/components/providers.tsx +19 -0
  73. package/template/src/shared/db/index.ts +7 -0
  74. package/template/src/shared/db/schema.ts +15 -0
  75. package/template/src/shared/lib/ai.ts +8 -0
  76. package/template/src/shared/lib/minimax-media.ts +63 -0
  77. package/template/src/shared/lib/supabase/client.ts +8 -0
  78. package/template/src/shared/lib/supabase/middleware.ts +40 -0
  79. package/template/src/shared/lib/supabase/server.ts +26 -0
  80. package/template/src/test-setup.ts +1 -0
  81. package/template/tailwind.css +20 -0
  82. package/template/tsconfig.json +31 -0
  83. package/template/vitest.config.ts +33 -0
@@ -0,0 +1,52 @@
1
+ ---
2
+ name: create-feature
3
+ description: Scaffold a new feature following TDD and project conventions. Use when starting a new feature or user story.
4
+ ---
5
+
6
+ # Create Feature Skill
7
+
8
+ ## Process
9
+
10
+ ### 1. Requirements First
11
+ - Check `.requirements/` for existing spec
12
+ - If none exists, ask the user to describe the feature
13
+ - Document in `.requirements/<feature-name>.md` using the Given/When/Then template
14
+
15
+ ### 2. Create Feature Structure
16
+ ```
17
+ src/features/<feature-name>/
18
+ ├── components/
19
+ ├── actions/
20
+ ├── hooks/
21
+ ├── api/
22
+ └── __tests__/
23
+ ```
24
+
25
+ ### 3. TDD: RED Phase
26
+ Write ALL test files first:
27
+ - `__tests__/<component>.test.tsx` — component tests
28
+ - `__tests__/use-<feature>.test.ts` — hook tests
29
+ - `__tests__/<action>.test.ts` — action tests
30
+
31
+ Run `npm run test:unit` — all tests must FAIL (RED).
32
+
33
+ ### 4. TDD: GREEN Phase
34
+ Implement minimum code to pass each test:
35
+ - Components → actions → hooks → API routes
36
+
37
+ Run `npm run test:unit` — all tests must PASS (GREEN).
38
+
39
+ ### 5. Refactor
40
+ Clean up while keeping tests green.
41
+
42
+ ### 6. Verify
43
+ ```bash
44
+ npm run test:coverage # Must show 100%
45
+ npm run lint # Must pass with 0 warnings
46
+ npm run typecheck # Must pass with 0 errors
47
+ ```
48
+
49
+ ## Guardrails
50
+ - NEVER start implementation before tests exist
51
+ - 100% coverage before marking done
52
+ - Follow `features/* → shared/*` dependency direction
@@ -0,0 +1,61 @@
1
+ ---
2
+ name: review-branch
3
+ description: Review current branch changes against develop. Runs full code quality checklist.
4
+ disable-model-invocation: true
5
+ ---
6
+
7
+ # Review Branch Skill
8
+
9
+ ## Process
10
+
11
+ ### 1. Get Changes
12
+ ```bash
13
+ git diff develop...HEAD
14
+ ```
15
+ Or for a specific branch:
16
+ ```bash
17
+ git diff develop...<branch-name>
18
+ ```
19
+
20
+ ### 2. Check Each Changed File Against:
21
+
22
+ #### Code Quality
23
+ - Zero `any` types
24
+ - Zero comments
25
+ - Functions ≤ 20 lines, files ≤ 200 lines
26
+ - No magic numbers/strings
27
+
28
+ #### Tests
29
+ - Test files exist for every changed source file
30
+ - Tests cover new code paths
31
+ - No implementation-detail testing
32
+
33
+ #### Architecture
34
+ - Correct imports (features → shared only)
35
+ - Server Actions for mutations
36
+ - Edge runtime on AI routes
37
+
38
+ #### Security
39
+ - Input validation at boundaries
40
+ - Auth checks present
41
+ - No exposed secrets
42
+
43
+ ### 3. Generate Report
44
+ ```
45
+ ## Branch Review: <branch-name>
46
+
47
+ ### Changed Files
48
+ - [list each file]
49
+
50
+ ### Issues Found
51
+ - [file:line]: [issue] → [fix]
52
+
53
+ ### Verdict: PASS / FAIL
54
+ ```
55
+
56
+ ### 4. Run Automated Checks
57
+ ```bash
58
+ npm run lint
59
+ npm run typecheck
60
+ npm run test:coverage
61
+ ```
@@ -0,0 +1,69 @@
1
+ ---
2
+ name: security-audit
3
+ description: Run a security audit on the codebase. Checks OWASP Top 10, RLS, secrets, and dependencies.
4
+ disable-model-invocation: true
5
+ ---
6
+
7
+ # Security Audit Skill
8
+
9
+ ## Process
10
+
11
+ ### 1. Dependency Audit
12
+ ```bash
13
+ npm audit
14
+ ```
15
+ Categorize findings by: Critical / High / Medium / Low
16
+
17
+ ### 2. Secret Scan
18
+ Search for hardcoded secrets:
19
+ ```bash
20
+ grep -r "sk_" src/ --include="*.ts"
21
+ grep -r "apiKey\s*=" src/ --include="*.ts"
22
+ grep -r "password\s*=" src/ --include="*.ts"
23
+ ```
24
+ Check `.env.example` has no real values.
25
+
26
+ ### 3. RLS Verification
27
+ For each table in `src/shared/db/schema.ts`:
28
+ - Confirm RLS is enabled in Supabase dashboard
29
+ - Confirm explicit policies exist
30
+
31
+ ### 4. Auth Coverage
32
+ - Verify `middleware.ts` protects all non-public routes
33
+ - Check every `route.ts` in protected features has auth check
34
+ - Verify `app/(protected)/layout.tsx` has server-side auth check
35
+
36
+ ### 5. Input Validation
37
+ - Every `route.ts` has Zod schema validation
38
+ - Every `.action.ts` has Zod schema validation
39
+
40
+ ### 6. XSS Check
41
+ ```bash
42
+ grep -r "dangerouslySetInnerHTML" src/ --include="*.tsx"
43
+ ```
44
+
45
+ ### 7. Security Headers
46
+ Verify in `next.config.ts`:
47
+ - `Content-Security-Policy`
48
+ - `Strict-Transport-Security`
49
+ - `X-Frame-Options`
50
+
51
+ ## Output Format
52
+ ```
53
+ ## Security Audit Report
54
+
55
+ ### Critical 🔴
56
+ [findings]
57
+
58
+ ### High 🟠
59
+ [findings]
60
+
61
+ ### Medium 🟡
62
+ [findings]
63
+
64
+ ### Low 🟢
65
+ [findings]
66
+
67
+ ### Passed ✅
68
+ [clean checks]
69
+ ```
@@ -0,0 +1,24 @@
1
+ # =============================================================================
2
+ # REQUIRED — fill these in before running npm run dev
3
+ # =============================================================================
4
+
5
+ # Supabase — https://supabase.com > Project Settings > API
6
+ NEXT_PUBLIC_SUPABASE_URL=https://your-project-id.supabase.co
7
+ NEXT_PUBLIC_SUPABASE_ANON_KEY=your-anon-key
8
+
9
+ # Supabase DB — https://supabase.com > Project Settings > Database > Connection string (URI)
10
+ DATABASE_URL=postgresql://postgres:[password]@db.your-project-id.supabase.co:5432/postgres
11
+
12
+ # MiniMax — https://www.minimaxi.chat > API Keys
13
+ MINIMAX_API_KEY=your-minimax-api-key
14
+
15
+ # Vercel AI Gateway — https://vercel.com > AI > Gateways
16
+ # Format: https://gateway.ai.vercel.app/v1/{team-id}/{gateway-id}
17
+ AI_GATEWAY_URL=https://gateway.ai.vercel.app/v1/your-team-id/your-gateway-id
18
+
19
+ # =============================================================================
20
+ # OPTIONAL
21
+ # =============================================================================
22
+
23
+ # App URL (used for OAuth callbacks)
24
+ NEXT_PUBLIC_APP_URL=http://localhost:3000
@@ -0,0 +1,15 @@
1
+ # Requirements
2
+
3
+ This directory contains feature requirements written in Given/When/Then format.
4
+
5
+ ## Structure
6
+ - `README.md` — this file
7
+ - `template.md` — requirement template
8
+ - `auth.md` — authentication requirements
9
+ - `<feature>.md` — per-feature requirements
10
+
11
+ ## Process
12
+ 1. Define requirements BEFORE starting implementation
13
+ 2. Each acceptance criterion maps to at least one test case
14
+ 3. Validate implementation against criteria before marking done
15
+ 4. Use the `business-intelligence` Cursor agent to help define requirements
@@ -0,0 +1,50 @@
1
+ # Feature: Authentication
2
+
3
+ ## User Story
4
+ As a user, I want to sign in with email and password so that I can access protected features.
5
+
6
+ ## Acceptance Criteria
7
+
8
+ ### AC1: Successful Login
9
+ **Given** I am on the login page
10
+ **When** I enter valid email and password
11
+ **Then** I am redirected to the home page and my session is established
12
+
13
+ ### AC2: Invalid Credentials
14
+ **Given** I am on the login page
15
+ **When** I enter an incorrect email or password
16
+ **Then** I see an error message "Invalid login credentials"
17
+
18
+ ### AC3: Validation Errors
19
+ **Given** I am on the login page
20
+ **When** I submit the form with an invalid email format
21
+ **Then** I see "Invalid email" validation error before the form is submitted
22
+
23
+ ### AC4: Password Minimum Length
24
+ **Given** I am on the login page
25
+ **When** I enter a password shorter than 8 characters
26
+ **Then** I see "Password must be at least 8 characters" error
27
+
28
+ ### AC5: Logout
29
+ **Given** I am authenticated
30
+ **When** I trigger logout
31
+ **Then** My session is cleared and I am redirected to the login page
32
+
33
+ ### AC6: Protected Route Guard
34
+ **Given** I am not authenticated
35
+ **When** I navigate to any protected route
36
+ **Then** I am redirected to the login page
37
+
38
+ ## Test Cases
39
+ - [ ] TC1: Valid credentials → redirect to home
40
+ - [ ] TC2: Wrong password → error message
41
+ - [ ] TC3: Empty email → validation error
42
+ - [ ] TC4: Invalid email format → validation error
43
+ - [ ] TC5: Short password → validation error
44
+ - [ ] TC6: Logout → redirect to login
45
+ - [ ] TC7: Unauthenticated → redirect to login
46
+
47
+ ## Out of Scope
48
+ - Social OAuth (Google, GitHub) — can be added later
49
+ - Password reset flow — future enhancement
50
+ - MFA — future enhancement
@@ -0,0 +1,25 @@
1
+ # Feature: [Feature Name]
2
+
3
+ ## User Story
4
+ As a [user type], I want [goal] so that [reason].
5
+
6
+ ## Acceptance Criteria
7
+
8
+ ### AC1: [Scenario Name]
9
+ **Given** [initial context]
10
+ **When** [action taken]
11
+ **Then** [expected outcome]
12
+
13
+ ### AC2: [Error Scenario]
14
+ **Given** [initial context]
15
+ **When** [invalid action]
16
+ **Then** [error behavior]
17
+
18
+ ## Test Cases
19
+ - [ ] TC1: [Happy path]
20
+ - [ ] TC2: [Validation error]
21
+ - [ ] TC3: [Auth error]
22
+ - [ ] TC4: [Edge case]
23
+
24
+ ## Out of Scope
25
+ - [What this feature does NOT cover]
@@ -0,0 +1,98 @@
1
+ # {{projectName}}
2
+
3
+ Full-stack Next.js 15 hackathon starter.
4
+
5
+ ## Stack
6
+
7
+ | Layer | Tool |
8
+ |---|---|
9
+ | Framework | Next.js 15 + App Router |
10
+ | Database | Supabase (PostgreSQL) |
11
+ | Auth | Supabase Auth |
12
+ | ORM | Drizzle (schema + migrations) |
13
+ | Runtime Queries | supabase-js (RLS active) |
14
+ | State | TanStack Query v5 |
15
+ | Forms | React Hook Form + Zod |
16
+ | UI | shadcn/ui + Tailwind CSS v4 |
17
+ | AI | Vercel AI SDK + MiniMax |
18
+ | Testing | Vitest + Playwright |
19
+
20
+ ## Getting Started
21
+
22
+ ### 1. Add your API keys
23
+
24
+ `.env.local` was created automatically. Fill in the values:
25
+
26
+ ```bash
27
+ # Supabase — https://supabase.com > Project Settings > API
28
+ NEXT_PUBLIC_SUPABASE_URL=https://your-project-id.supabase.co
29
+ NEXT_PUBLIC_SUPABASE_ANON_KEY=your-anon-key
30
+ DATABASE_URL=postgresql://postgres:[password]@db.your-project-id.supabase.co:5432/postgres
31
+
32
+ # MiniMax — https://www.minimaxi.chat > API Keys
33
+ MINIMAX_API_KEY=your-minimax-api-key
34
+
35
+ # Vercel AI Gateway — https://vercel.com > AI > Gateways
36
+ AI_GATEWAY_URL=https://gateway.ai.vercel.app/v1/your-team-id/your-gateway-id
37
+ ```
38
+
39
+ ### 2. Run the dev server
40
+
41
+ ```bash
42
+ npm run dev
43
+ ```
44
+
45
+ ### 3. Apply database migrations
46
+
47
+ ```bash
48
+ npm run db:generate
49
+ npm run db:migrate
50
+ ```
51
+
52
+ ## Scripts
53
+
54
+ ```bash
55
+ npm run dev # Start dev server
56
+ npm run build # Production build
57
+ npm run lint # Lint (0 warnings allowed)
58
+ npm run typecheck # TypeScript check
59
+ npm run test # Unit tests
60
+ npm run test:coverage # Tests with coverage (100% required)
61
+ npm run test:e2e # Playwright e2e tests
62
+ npm run db:generate # Generate Drizzle migrations
63
+ npm run db:migrate # Apply migrations
64
+ ```
65
+
66
+ ## Environment Variables
67
+
68
+ | Variable | Where to get it |
69
+ |---|---|
70
+ | `NEXT_PUBLIC_SUPABASE_URL` | Supabase > Project Settings > API |
71
+ | `NEXT_PUBLIC_SUPABASE_ANON_KEY` | Supabase > Project Settings > API |
72
+ | `DATABASE_URL` | Supabase > Project Settings > Database > URI |
73
+ | `MINIMAX_API_KEY` | minimaxi.chat > API Keys |
74
+ | `AI_GATEWAY_URL` | Vercel > AI > Gateways |
75
+ | `NEXT_PUBLIC_APP_URL` | Your deployment URL (default: `http://localhost:3000`) |
76
+
77
+ See `.env.example` for all required variables with comments.
78
+
79
+ ## Architecture
80
+
81
+ Feature-based structure:
82
+ ```
83
+ src/
84
+ ├── app/ # Next.js routing + layouts
85
+ ├── features/ # auth | chat | video | tts
86
+ ├── shared/ # lib | db | components/ui
87
+ └── e2e/ # Playwright tests
88
+ ```
89
+
90
+ Dependency direction: `features/* → shared/*` (never reverse).
91
+
92
+ ## Cursor AI Setup
93
+
94
+ Cursor rules, agents, and skills are preconfigured in `.cursor/`.
95
+
96
+ - **Rules**: always-on guardrails for coding standards, architecture, security
97
+ - **Agents**: specialized roles (technical-lead, frontend, test-qa, etc.)
98
+ - **Skills**: repeatable workflows (`/create-feature`, `/create-api-route`, etc.)
@@ -0,0 +1,19 @@
1
+ {
2
+ "$schema": "https://ui.shadcn.com/schema.json",
3
+ "style": "new-york",
4
+ "rsc": true,
5
+ "tsx": true,
6
+ "tailwind": {
7
+ "config": "",
8
+ "css": "src/app/globals.css",
9
+ "baseColor": "slate",
10
+ "cssVariables": true
11
+ },
12
+ "aliases": {
13
+ "components": "@/shared/components/ui",
14
+ "utils": "@/shared/lib/utils",
15
+ "ui": "@/shared/components/ui",
16
+ "lib": "@/shared/lib",
17
+ "hooks": "@/shared/hooks"
18
+ }
19
+ }
@@ -0,0 +1,10 @@
1
+ import { defineConfig } from "drizzle-kit";
2
+
3
+ export default defineConfig({
4
+ schema: "./src/shared/db/schema.ts",
5
+ out: "./src/shared/db/migrations",
6
+ dialect: "postgresql",
7
+ dbCredentials: {
8
+ url: process.env["DATABASE_URL"] ?? "",
9
+ },
10
+ });
@@ -0,0 +1,66 @@
1
+ import js from "@eslint/js";
2
+ import tseslint from "typescript-eslint";
3
+ import reactPlugin from "eslint-plugin-react";
4
+ import reactHooksPlugin from "eslint-plugin-react-hooks";
5
+ import nextPlugin from "@next/eslint-plugin-next";
6
+ import importPlugin from "eslint-plugin-import-x";
7
+ import vitestPlugin from "eslint-plugin-vitest";
8
+ import playwrightPlugin from "eslint-plugin-playwright";
9
+
10
+ export default tseslint.config(
11
+ js.configs.recommended,
12
+ ...tseslint.configs.strictTypeChecked,
13
+ ...tseslint.configs.stylisticTypeChecked,
14
+ {
15
+ languageOptions: {
16
+ parserOptions: {
17
+ projectService: true,
18
+ tsconfigRootDir: import.meta.dirname,
19
+ },
20
+ },
21
+ plugins: {
22
+ react: reactPlugin,
23
+ "react-hooks": reactHooksPlugin,
24
+ "@next/next": nextPlugin,
25
+ "import-x": importPlugin,
26
+ },
27
+ rules: {
28
+ "@typescript-eslint/no-explicit-any": "error",
29
+ "@typescript-eslint/no-unused-vars": ["error", { argsIgnorePattern: "^_" }],
30
+ "@typescript-eslint/consistent-type-imports": "error",
31
+ "@typescript-eslint/no-non-null-assertion": "error",
32
+ "no-console": "warn",
33
+ "react/react-in-jsx-scope": "off",
34
+ "react-hooks/rules-of-hooks": "error",
35
+ "react-hooks/exhaustive-deps": "error",
36
+ "import-x/order": [
37
+ "error",
38
+ {
39
+ groups: ["builtin", "external", "internal", "parent", "sibling", "index"],
40
+ "newlines-between": "always",
41
+ alphabetize: { order: "asc" },
42
+ },
43
+ ],
44
+ },
45
+ settings: {
46
+ react: { version: "detect" },
47
+ },
48
+ },
49
+ {
50
+ files: ["**/*.test.ts", "**/*.test.tsx"],
51
+ plugins: { vitest: vitestPlugin },
52
+ rules: {
53
+ ...vitestPlugin.configs.recommended.rules,
54
+ },
55
+ },
56
+ {
57
+ files: ["src/e2e/**/*.spec.ts"],
58
+ plugins: { playwright: playwrightPlugin },
59
+ rules: {
60
+ ...playwrightPlugin.configs["flat/recommended"].rules,
61
+ },
62
+ },
63
+ {
64
+ ignores: [".next/**", "node_modules/**", "dist/**"],
65
+ }
66
+ );
@@ -0,0 +1,10 @@
1
+ import { type NextRequest } from "next/server";
2
+ import { updateSession } from "@/shared/lib/supabase/middleware";
3
+
4
+ export async function middleware(request: NextRequest) {
5
+ return updateSession(request);
6
+ }
7
+
8
+ export const config = {
9
+ matcher: ["/((?!_next/static|_next/image|favicon.ico|.*\\.(?:svg|png|jpg|jpeg|gif|webp)$).*)"],
10
+ };
@@ -0,0 +1,31 @@
1
+ import type { NextConfig } from "next";
2
+
3
+ const nextConfig: NextConfig = {
4
+ experimental: {
5
+ typedRoutes: true,
6
+ },
7
+ headers: async () => [
8
+ {
9
+ source: "/(.*)",
10
+ headers: [
11
+ { key: "X-Frame-Options", value: "DENY" },
12
+ { key: "X-Content-Type-Options", value: "nosniff" },
13
+ { key: "Referrer-Policy", value: "strict-origin-when-cross-origin" },
14
+ { key: "Strict-Transport-Security", value: "max-age=63072000; includeSubDomains; preload" },
15
+ {
16
+ key: "Content-Security-Policy",
17
+ value: [
18
+ "default-src 'self'",
19
+ "script-src 'self' 'unsafe-eval' 'unsafe-inline'",
20
+ "style-src 'self' 'unsafe-inline'",
21
+ "img-src 'self' data: blob: https:",
22
+ "font-src 'self'",
23
+ "connect-src 'self' https://*.supabase.co wss://*.supabase.co",
24
+ ].join("; "),
25
+ },
26
+ ],
27
+ },
28
+ ],
29
+ };
30
+
31
+ export default nextConfig;
@@ -0,0 +1,62 @@
1
+ {
2
+ "name": "{{projectName}}",
3
+ "version": "0.1.0",
4
+ "private": true,
5
+ "scripts": {
6
+ "dev": "next dev --turbopack",
7
+ "build": "next build",
8
+ "start": "next start",
9
+ "lint": "eslint . --max-warnings 0",
10
+ "lint:fix": "eslint . --fix",
11
+ "typecheck": "tsc --noEmit",
12
+ "test": "vitest run",
13
+ "test:unit": "vitest run --reporter=verbose",
14
+ "test:watch": "vitest",
15
+ "test:coverage": "vitest run --coverage",
16
+ "test:e2e": "playwright test",
17
+ "db:generate": "drizzle-kit generate",
18
+ "db:migrate": "drizzle-kit migrate",
19
+ "db:studio": "drizzle-kit studio"
20
+ },
21
+ "dependencies": {
22
+ "next": "^15",
23
+ "@supabase/supabase-js": "^2",
24
+ "@supabase/ssr": "^0",
25
+ "drizzle-orm": "^0.45",
26
+ "drizzle-zod": "^0.7",
27
+ "@tanstack/react-query": "^5",
28
+ "ai": "^4",
29
+ "@ai-sdk/react": "^1",
30
+ "react-hook-form": "^7",
31
+ "@hookform/resolvers": "^3",
32
+ "zod": "^3",
33
+ "react": "^19",
34
+ "react-dom": "^19"
35
+ },
36
+ "devDependencies": {
37
+ "typescript": "^5",
38
+ "@types/node": "^22",
39
+ "@types/react": "^19",
40
+ "@types/react-dom": "^19",
41
+ "drizzle-kit": "^0.30",
42
+ "vitest": "^3",
43
+ "@vitejs/plugin-react": "latest",
44
+ "@testing-library/react": "^16",
45
+ "@testing-library/jest-dom": "latest",
46
+ "@testing-library/user-event": "latest",
47
+ "@vitest/coverage-v8": "latest",
48
+ "@playwright/test": "^1.49",
49
+ "tailwindcss": "^4",
50
+ "@tailwindcss/postcss": "^4",
51
+ "postcss": "^8",
52
+ "eslint": "^9",
53
+ "@eslint/js": "^9",
54
+ "typescript-eslint": "^8",
55
+ "@next/eslint-plugin-next": "^15",
56
+ "eslint-plugin-react": "latest",
57
+ "eslint-plugin-react-hooks": "latest",
58
+ "eslint-plugin-import-x": "latest",
59
+ "eslint-plugin-vitest": "latest",
60
+ "eslint-plugin-playwright": "latest"
61
+ }
62
+ }
@@ -0,0 +1,22 @@
1
+ import { defineConfig, devices } from "@playwright/test";
2
+
3
+ export default defineConfig({
4
+ testDir: "./src/e2e",
5
+ fullyParallel: true,
6
+ forbidOnly: !!process.env["CI"],
7
+ retries: process.env["CI"] ? 2 : 0,
8
+ workers: process.env["CI"] ? 1 : undefined,
9
+ reporter: "html",
10
+ use: {
11
+ baseURL: "http://localhost:3000",
12
+ trace: "on-first-retry",
13
+ },
14
+ projects: [
15
+ { name: "chromium", use: { ...devices["Desktop Chrome"] } },
16
+ ],
17
+ webServer: {
18
+ command: "npm run dev",
19
+ url: "http://localhost:3000",
20
+ reuseExistingServer: !process.env["CI"],
21
+ },
22
+ });
@@ -0,0 +1,12 @@
1
+ import { LoginForm } from "@/features/auth/components/login-form";
2
+
3
+ export default function LoginPage() {
4
+ return (
5
+ <main className="flex min-h-screen items-center justify-center">
6
+ <div className="w-full max-w-md p-8">
7
+ <h1 className="mb-8 text-2xl font-bold">Sign in</h1>
8
+ <LoginForm />
9
+ </div>
10
+ </main>
11
+ );
12
+ }
@@ -0,0 +1,19 @@
1
+ import { redirect } from "next/navigation";
2
+ import { createClient } from "@/shared/lib/supabase/server";
3
+
4
+ export default async function ProtectedLayout({
5
+ children,
6
+ }: {
7
+ children: React.ReactNode;
8
+ }) {
9
+ const supabase = await createClient();
10
+ const {
11
+ data: { user },
12
+ } = await supabase.auth.getUser();
13
+
14
+ if (!user) {
15
+ redirect("/login");
16
+ }
17
+
18
+ return <>{children}</>;
19
+ }
@@ -0,0 +1,16 @@
1
+ import { createClient } from "@/shared/lib/supabase/server";
2
+ import { ChatUi } from "@/features/chat/components/chat-ui";
3
+
4
+ export default async function HomePage() {
5
+ const supabase = await createClient();
6
+ const {
7
+ data: { user },
8
+ } = await supabase.auth.getUser();
9
+
10
+ return (
11
+ <main className="container mx-auto p-8">
12
+ <h1 className="mb-4 text-2xl font-bold">Welcome, {user?.email}</h1>
13
+ <ChatUi />
14
+ </main>
15
+ );
16
+ }