nextjs-hackathon-stack 0.1.24 → 0.1.25

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nextjs-hackathon-stack",
3
- "version": "0.1.24",
3
+ "version": "0.1.25",
4
4
  "description": "Scaffold a full-stack Next.js hackathon starter",
5
5
  "type": "module",
6
6
  "bin": {
@@ -12,7 +12,7 @@ readonly: true
12
12
  ### Authentication & Authorization
13
13
  - [ ] Supabase RLS enabled on all tables
14
14
  - [ ] Auth check in every protected API route
15
- - [ ] Session validation in middleware
15
+ - [ ] Session validation in proxy
16
16
  - [ ] No hardcoded credentials or API keys
17
17
 
18
18
  ### Input Validation
@@ -6,7 +6,7 @@ alwaysApply: true
6
6
  # Stack Overview
7
7
 
8
8
  ## Technology Stack
9
- - **Framework**: Next.js 15 (App Router)
9
+ - **Framework**: Next.js 16 (App Router)
10
10
  - **Database**: Supabase (PostgreSQL) with Drizzle ORM for schema/migrations
11
11
  - **Auth**: Supabase Auth via `@supabase/ssr`
12
12
  - **ORM**: Drizzle + `drizzle-zod` (schema + migrations ONLY — no runtime queries)
@@ -1,9 +1,9 @@
1
1
  ---
2
- description: Next.js 15 App Router patterns.
2
+ description: Next.js 16 App Router patterns.
3
3
  globs: ["src/app/**"]
4
4
  ---
5
5
 
6
- # Next.js 15 Rules
6
+ # Next.js 16 Rules
7
7
 
8
8
  ## App Router Conventions
9
9
  - `page.tsx` — public route page component
@@ -11,7 +11,7 @@ globs: ["src/app/**"]
11
11
  - `loading.tsx` — Suspense boundary UI
12
12
  - `error.tsx` — Error boundary UI
13
13
  - `route.ts` — API route handler
14
- - `middleware.ts` — Edge middleware (project root)
14
+ - `proxy.ts` — Request proxy (project root, Node.js runtime)
15
15
 
16
16
  ## Route Groups
17
17
  - `(auth)` — unauthenticated routes
@@ -34,3 +34,8 @@ const users = await db.select().from(usersTable); // WRONG — bypasses RLS
34
34
  - Enable RLS on ALL tables in Supabase dashboard
35
35
  - Every table must have explicit policies
36
36
  - Test RLS policies in migrations
37
+
38
+ ## Environment Variables
39
+ - `NEXT_PUBLIC_SUPABASE_URL` + `NEXT_PUBLIC_SUPABASE_ANON_KEY` — client-safe, used in browser + server
40
+ - `DATABASE_URL` — server-only, used by Drizzle for migrations (`drizzle.config.ts`)
41
+ - See `.env.example` for all required variables
@@ -29,7 +29,7 @@ For each table in `src/shared/db/schema.ts`:
29
29
  - Confirm explicit policies exist
30
30
 
31
31
  ### 4. Auth Coverage
32
- - Verify `middleware.ts` protects all non-public routes
32
+ - Verify `proxy.ts` protects all non-public routes
33
33
  - Check every `route.ts` in protected features has auth check
34
34
  - Verify `app/(protected)/layout.tsx` has server-side auth check
35
35
 
@@ -0,0 +1,21 @@
1
+ <!-- BEGIN:nextjs-agent-rules -->
2
+
3
+ # Next.js: ALWAYS read docs before coding
4
+
5
+ Before any Next.js work, find and read the relevant doc in `node_modules/next/dist/docs/`. Your training data is outdated — the docs are the source of truth.
6
+
7
+ <!-- END:nextjs-agent-rules -->
8
+
9
+ # Environment variables
10
+
11
+ Read `.env.example` for the full list. Key vars:
12
+
13
+ | Variable | Visibility | Where to get it |
14
+ |---|---|---|
15
+ | `NEXT_PUBLIC_SUPABASE_URL` | Client + Server | Supabase > Project Settings > API |
16
+ | `NEXT_PUBLIC_SUPABASE_ANON_KEY` | Client + Server | Supabase > Project Settings > API |
17
+ | `DATABASE_URL` | Server only | Supabase > Project Settings > Database > Connection string (Session mode) |
18
+
19
+ - `NEXT_PUBLIC_*` vars are safe to expose to the browser — they are public by design
20
+ - Never add `NEXT_PUBLIC_` prefix to secret keys (`DATABASE_URL`, `AI_API_KEY`)
21
+ - `.env.local` is gitignored — never commit real credentials
@@ -0,0 +1,15 @@
1
+ @AGENTS.md
2
+
3
+ # Architecture
4
+
5
+ Feature-based structure: `src/features/* → src/shared/*` (never reverse).
6
+
7
+ - **Drizzle** = schema + migrations ONLY. Never use Drizzle for runtime queries.
8
+ - **supabase-js** = all runtime queries. RLS is always active.
9
+ - **Zod schemas** for DB types: auto-generate via `drizzle-zod`, never write manually.
10
+
11
+ # Testing
12
+
13
+ - 100% coverage required — `pnpm test:coverage` must pass
14
+ - AAA pattern (Arrange / Act / Assert) in every test
15
+ - Mock only external boundaries (Supabase, HTTP, DB) — never mock internal code
@@ -1,12 +1,12 @@
1
1
  # {{projectName}}
2
2
 
3
- Full-stack Next.js 15 hackathon starter.
3
+ Full-stack Next.js 16 hackathon starter.
4
4
 
5
5
  ## Stack
6
6
 
7
7
  | Layer | Tool |
8
8
  |---|---|
9
- | Framework | Next.js 15 + App Router |
9
+ | Framework | Next.js 16 + App Router |
10
10
  | Database | Supabase (PostgreSQL) |
11
11
  | Auth | Supabase Auth |
12
12
  | ORM | Drizzle (schema + migrations) |
@@ -2,6 +2,9 @@ import type { NextConfig } from "next";
2
2
 
3
3
  const nextConfig: NextConfig = {
4
4
  typedRoutes: true,
5
+ logging: {
6
+ browserToTerminal: true,
7
+ },
5
8
  turbopack: {
6
9
  root: import.meta.dirname,
7
10
  },
@@ -3,7 +3,7 @@
3
3
  "version": "0.1.0",
4
4
  "private": true,
5
5
  "scripts": {
6
- "dev": "next dev --turbopack",
6
+ "dev": "next dev",
7
7
  "build": "next build",
8
8
  "start": "next start",
9
9
  "lint": "eslint . --max-warnings 0",
@@ -21,7 +21,7 @@
21
21
  "prepare": "husky"
22
22
  },
23
23
  "dependencies": {
24
- "next": "^15",
24
+ "next": "^16.2",
25
25
  "@supabase/supabase-js": "^2",
26
26
  "@supabase/ssr": "^0.6",
27
27
  "drizzle-orm": "^0.44",
@@ -45,6 +45,7 @@
45
45
  "@types/node": "^22",
46
46
  "@types/react": "^19",
47
47
  "@types/react-dom": "^19",
48
+ "@next/env": "^16",
48
49
  "drizzle-kit": "^0.30",
49
50
  "vitest": "^3",
50
51
  "@vitejs/plugin-react": "^4",
@@ -60,7 +61,7 @@
60
61
  "eslint": "^9",
61
62
  "@eslint/js": "^9",
62
63
  "typescript-eslint": "^8",
63
- "@next/eslint-plugin-next": "^15",
64
+ "@next/eslint-plugin-next": "^16",
64
65
  "eslint-plugin-react": "^7",
65
66
  "eslint-plugin-react-hooks": "^5",
66
67
  "eslint-plugin-import-x": "^4",
@@ -2,7 +2,7 @@ import type { NextRequest } from "next/server";
2
2
 
3
3
  import { updateSession } from "@/shared/lib/supabase/middleware";
4
4
 
5
- export async function middleware(request: NextRequest) {
5
+ export async function proxy(request: NextRequest) {
6
6
  return updateSession(request);
7
7
  }
8
8
 
@@ -7,16 +7,16 @@ vi.mock("@/shared/lib/supabase/middleware", () => ({
7
7
  updateSession: (...args: unknown[]): unknown => mockUpdateSession(...args),
8
8
  }));
9
9
 
10
- describe("middleware", () => {
10
+ describe("proxy", () => {
11
11
  it("delegates to updateSession", async () => {
12
12
  // Arrange
13
13
  const mockResponse = new Response(null, { status: 200 });
14
14
  mockUpdateSession.mockResolvedValue(mockResponse);
15
- const mod = await import("../../../middleware") as { middleware: (req: NextRequest) => Promise<Response> };
15
+ const mod = await import("../../../proxy") as { proxy: (req: NextRequest) => Promise<Response> };
16
16
  const req = new NextRequest("http://localhost/dashboard");
17
17
 
18
18
  // Act
19
- const response = await mod.middleware(req);
19
+ const response = await mod.proxy(req);
20
20
 
21
21
  // Assert
22
22
  expect(mockUpdateSession).toHaveBeenCalledWith(req);
@@ -25,7 +25,7 @@ describe("middleware", () => {
25
25
 
26
26
  it("exports a matcher config", async () => {
27
27
  // Arrange + Act
28
- const mod = await import("../../../middleware") as { config: { matcher: string[] } };
28
+ const mod = await import("../../../proxy") as { config: { matcher: string[] } };
29
29
 
30
30
  // Assert
31
31
  expect(mod.config.matcher).toBeDefined();