plan-module · supabase_json
KnowledgeVault AI plan-module M-01
plan-module artifact · for KnowledgeVault AI · phase M-01 · status draft
tasks
| id | role | brief | title | completion | depends on |
|---|---|---|---|---|---|
| 1 | developer | Create apps/knowledgevault/supabase/migrations/001_experts_table.sql.
Table: Create experts in the public schema with these columns:
- id uuid NOT NULL DEFAULT gen_random_uuid() PRIMARY KEY
- name text NOT NULL
- email text UNIQUE NOT NULL
- phone text NULL -- nullable: optional contact info
- role_type text NOT NULL
- specialties text[] NOT NULL DEFAULT '{}'
- years_experience integer NULL -- nullable: optional, 0-60
- bio text NULL -- nullable: optional profile text
- stripe_account_id text NULL -- nullable: null means Stripe onboarding deferred
- `created_at times | Create experts table migration | - type: file - evaluate: SQL file creates experts table with all 10 specified columns and correct types/constraints, enables RLS with experts_self_rw policy (SELECT/UPDATE self only, INSERT BYPASSRLS, no DELETE), installs auth.expert_id() function returning (auth.jwt()->'app_metadata'->>'expert_id')::uuid, UNIQUE constraint on email, file is idempotent — satisfies POL-SEC-001 (RLS enabled on all user tables), POL-ARCH-001 (sequential migration naming, no modifications to existing files), POL-DATA-002 (all nullable columns have -- nullable: comment). - min length: 300 | |
| 2 | developer | Create apps/knowledgevault/src/app/api/experts/signup/route.ts — Next.js App Router API route for expert registration. This is a public endpoint — no prior JWT required.
Request body (JSON): { name: string (required), email: string (required, valid email format), phone?: string, role_type: string (required, one of: Plumber | Electrician | HVAC Tech | Pipefitter | Millwright | Other), specialties: string[] (required, may be empty), years_experience?: integer (0-60) }
Success 201: { expert_id: string (uuid), stripe_onboarding_url: string | null, deferred: boolean }
**Error c | Implement POST /api/experts/signup route | - type: file - evaluate: Route handles all 5 error cases with exact status codes and error body shapes specified, calls sanitizeInput() on all user-supplied strings before any DB write or Stripe call (POL-SEC-003), Stripe failure path returns 201 with deferred=true and experts row committed (stripe_account_id=null), Auth createUser failure returns 500 with no experts row written, SUPABASE_SERVICE_KEY used only in server-side module (POL-ARCH-003), TypeScript strict mode with no bare any (POL-STYLE-001). - min length: 400 | - 1 |
| 3 | developer | Create apps/knowledgevault/src/lib/auth/expertAuthMiddleware.ts — reusable server-only middleware that validates Supabase Auth JWTs for all expert-authenticated routes in M-02 (sessions, product queue) and M-04 (payments).
Export: A single async function:
``typescript
export async function expertAuthMiddleware(
req: NextRequest
): Promise<{ expert: { id: string } } | NextResponse>
`
If JWT is valid and role is correct → return { expert: { id: string } } (caller uses this to access expert ID). If invalid → return a NextResponse` error directly (caller must check and return it).
| Implement expertAuthMiddleware service | - type: file - evaluate: File exports a single async expertAuthMiddleware function, reads role from app_metadata (not user_metadata) with code comment explaining why, returns correct 401/403 response shapes for each failure case, calls supabase.auth.getUser() for JWT validation per POL-SEC-002, marked 'use server', no bare any (POL-STYLE-001), no import paths that could reach client bundle (POL-ARCH-003). - min length: 100 | - 1 |
| 4 | developer | Create apps/knowledgevault/src/components/experts/ExpertSignupFlow.tsx — three-screen mobile signup flow. Export named components ExpertSignupForm, StripeRedirect, OnboardingConfirmation plus a default ExpertSignupFlow that orchestrates state.
S-01-a — ExpertSignupForm:
- Full-screen single-column scroll with sticky submit button
- Fields: name (aria-label='Full name', required, autocomplete='name'), email (type='email', required, autocomplete='email'), phone (type='tel', optional, autocomplete='tel'), role_type selector (bottom-sheet: Plumber, Electrician, HVAC Tech, Pipefitter | Implement ExpertSignupFlow UI components | - type: file - evaluate: File exports ExpertSignupForm, StripeRedirect, OnboardingConfirmation as named exports plus default ExpertSignupFlow; S-01-b fires redirect within 500ms of mount; submit button is disabled during API call; 409 shows inline email field error without page reload; S-01-c renders both default and deferred_bank headline/body states correctly; trade selector options are bundled in JS (no network fetch); all ARIA labels, input types, and autocomplete attributes match spec; no bare any (POL-STYLE-001); no SUPABASE_SERVICE_KEY or server-only imports. - min length: 400 | - 2 |
| 5 | developer | Create apps/knowledgevault/src/__tests__/auth/jwtClaims.test.ts — test suite validating the Supabase Auth JWT claim structure and expertAuthMiddleware correctness.
Test group 1 — JWT structure (integration):
After POST /api/experts/signup with a unique email, decode the issued Supabase JWT and assert:
- user.app_metadata.role === 'expert'
- user.app_metadata.expert_id equals the UUID from the 201 response
- expert_id does NOT appear in user.user_metadata (not user-editable)
Test group 2 — auth.expert_id() SQL function:
Using a test DB connection with a seeded expert JWT, | JWT claim validation test suite | - type: file - evaluate: Test file contains all 4 test groups; group 3 includes all 5 middleware scenarios including the critical app_metadata vs user_metadata test (confirming middleware reads from app_metadata per POL-SEC-002); all tests pass with test runner; no bare any (POL-STYLE-001). - min length: 300 | - 2 - 3 |
Agent Handoff
Start Here
| id | role | brief | title | completion | depends on |
|---|---|---|---|---|---|
| 1 | developer | Create apps/knowledgevault/supabase/migrations/001_experts_table.sql.
Table: Create experts in the public schema with these columns:
- id uuid NOT NULL DEFAULT gen_random_uuid() PRIMARY KEY
- name text NOT NULL
- email text UNIQUE NOT NULL
- phone text NULL -- nullable: optional contact info
- role_type text NOT NULL
- specialties text[] NOT NULL DEFAULT '{}'
- years_experience integer NULL -- nullable: optional, 0-60
- bio text NULL -- nullable: optional profile text
- stripe_account_id text NULL -- nullable: null means Stripe onboarding deferred
- `created_at times | Create experts table migration | - type: file - evaluate: SQL file creates experts table with all 10 specified columns and correct types/constraints, enables RLS with experts_self_rw policy (SELECT/UPDATE self only, INSERT BYPASSRLS, no DELETE), installs auth.expert_id() function returning (auth.jwt()->'app_metadata'->>'expert_id')::uuid, UNIQUE constraint on email, file is idempotent — satisfies POL-SEC-001 (RLS enabled on all user tables), POL-ARCH-001 (sequential migration naming, no modifications to existing files), POL-DATA-002 (all nullable columns have -- nullable: comment). - min length: 300 | |
| 2 | developer | Create apps/knowledgevault/src/app/api/experts/signup/route.ts — Next.js App Router API route for expert registration. This is a public endpoint — no prior JWT required.
Request body (JSON): { name: string (required), email: string (required, valid email format), phone?: string, role_type: string (required, one of: Plumber | Electrician | HVAC Tech | Pipefitter | Millwright | Other), specialties: string[] (required, may be empty), years_experience?: integer (0-60) }
Success 201: { expert_id: string (uuid), stripe_onboarding_url: string | null, deferred: boolean }
**Error c | Implement POST /api/experts/signup route | - type: file - evaluate: Route handles all 5 error cases with exact status codes and error body shapes specified, calls sanitizeInput() on all user-supplied strings before any DB write or Stripe call (POL-SEC-003), Stripe failure path returns 201 with deferred=true and experts row committed (stripe_account_id=null), Auth createUser failure returns 500 with no experts row written, SUPABASE_SERVICE_KEY used only in server-side module (POL-ARCH-003), TypeScript strict mode with no bare any (POL-STYLE-001). - min length: 400 | - 1 |
| 3 | developer | Create apps/knowledgevault/src/lib/auth/expertAuthMiddleware.ts — reusable server-only middleware that validates Supabase Auth JWTs for all expert-authenticated routes in M-02 (sessions, product queue) and M-04 (payments).
Export: A single async function:
``typescript
export async function expertAuthMiddleware(
req: NextRequest
): Promise<{ expert: { id: string } } | NextResponse>
`
If JWT is valid and role is correct → return { expert: { id: string } } (caller uses this to access expert ID). If invalid → return a NextResponse` error directly (caller must check and return it).
| Implement expertAuthMiddleware service | - type: file - evaluate: File exports a single async expertAuthMiddleware function, reads role from app_metadata (not user_metadata) with code comment explaining why, returns correct 401/403 response shapes for each failure case, calls supabase.auth.getUser() for JWT validation per POL-SEC-002, marked 'use server', no bare any (POL-STYLE-001), no import paths that could reach client bundle (POL-ARCH-003). - min length: 100 | - 1 |
| 4 | developer | Create apps/knowledgevault/src/components/experts/ExpertSignupFlow.tsx — three-screen mobile signup flow. Export named components ExpertSignupForm, StripeRedirect, OnboardingConfirmation plus a default ExpertSignupFlow that orchestrates state.
S-01-a — ExpertSignupForm:
- Full-screen single-column scroll with sticky submit button
- Fields: name (aria-label='Full name', required, autocomplete='name'), email (type='email', required, autocomplete='email'), phone (type='tel', optional, autocomplete='tel'), role_type selector (bottom-sheet: Plumber, Electrician, HVAC Tech, Pipefitter | Implement ExpertSignupFlow UI components | - type: file - evaluate: File exports ExpertSignupForm, StripeRedirect, OnboardingConfirmation as named exports plus default ExpertSignupFlow; S-01-b fires redirect within 500ms of mount; submit button is disabled during API call; 409 shows inline email field error without page reload; S-01-c renders both default and deferred_bank headline/body states correctly; trade selector options are bundled in JS (no network fetch); all ARIA labels, input types, and autocomplete attributes match spec; no bare any (POL-STYLE-001); no SUPABASE_SERVICE_KEY or server-only imports. - min length: 400 | - 2 |
| 5 | developer | Create apps/knowledgevault/src/__tests__/auth/jwtClaims.test.ts — test suite validating the Supabase Auth JWT claim structure and expertAuthMiddleware correctness.
Test group 1 — JWT structure (integration):
After POST /api/experts/signup with a unique email, decode the issued Supabase JWT and assert:
- user.app_metadata.role === 'expert'
- user.app_metadata.expert_id equals the UUID from the 201 response
- expert_id does NOT appear in user.user_metadata (not user-editable)
Test group 2 — auth.expert_id() SQL function:
Using a test DB connection with a seeded expert JWT, | JWT claim validation test suite | - type: file - evaluate: Test file contains all 4 test groups; group 3 includes all 5 middleware scenarios including the critical app_metadata vs user_metadata test (confirming middleware reads from app_metadata per POL-SEC-002); all tests pass with test runner; no bare any (POL-STYLE-001). - min length: 300 | - 2 - 3 |
Completion Evidence
No explicit evidence field yet. Require tests, screenshots, linked PRs, or reviewed outputs before marking complete.
Artifact Shape
- tasks: 5 items
- module id: M-01
- module name: Auth & Expert Onboarding
- schema version: 1.0
- depends on modules: 1 item
Structured Payload
Machine-readable source fields
tasks
| id | role | brief | title | completion | depends on |
|---|---|---|---|---|---|
| 1 | developer | Create apps/knowledgevault/supabase/migrations/001_experts_table.sql.
Table: Create experts in the public schema with these columns:
- id uuid NOT NULL DEFAULT gen_random_uuid() PRIMARY KEY
- name text NOT NULL
- email text UNIQUE NOT NULL
- phone text NULL -- nullable: optional contact info
- role_type text NOT NULL
- specialties text[] NOT NULL DEFAULT '{}'
- years_experience integer NULL -- nullable: optional, 0-60
- bio text NULL -- nullable: optional profile text
- stripe_account_id text NULL -- nullable: null means Stripe onboarding deferred
- `created_at times | Create experts table migration | - type: file - evaluate: SQL file creates experts table with all 10 specified columns and correct types/constraints, enables RLS with experts_self_rw policy (SELECT/UPDATE self only, INSERT BYPASSRLS, no DELETE), installs auth.expert_id() function returning (auth.jwt()->'app_metadata'->>'expert_id')::uuid, UNIQUE constraint on email, file is idempotent — satisfies POL-SEC-001 (RLS enabled on all user tables), POL-ARCH-001 (sequential migration naming, no modifications to existing files), POL-DATA-002 (all nullable columns have -- nullable: comment). - min length: 300 | |
| 2 | developer | Create apps/knowledgevault/src/app/api/experts/signup/route.ts — Next.js App Router API route for expert registration. This is a public endpoint — no prior JWT required.
Request body (JSON): { name: string (required), email: string (required, valid email format), phone?: string, role_type: string (required, one of: Plumber | Electrician | HVAC Tech | Pipefitter | Millwright | Other), specialties: string[] (required, may be empty), years_experience?: integer (0-60) }
Success 201: { expert_id: string (uuid), stripe_onboarding_url: string | null, deferred: boolean }
**Error c | Implement POST /api/experts/signup route | - type: file - evaluate: Route handles all 5 error cases with exact status codes and error body shapes specified, calls sanitizeInput() on all user-supplied strings before any DB write or Stripe call (POL-SEC-003), Stripe failure path returns 201 with deferred=true and experts row committed (stripe_account_id=null), Auth createUser failure returns 500 with no experts row written, SUPABASE_SERVICE_KEY used only in server-side module (POL-ARCH-003), TypeScript strict mode with no bare any (POL-STYLE-001). - min length: 400 | - 1 |
| 3 | developer | Create apps/knowledgevault/src/lib/auth/expertAuthMiddleware.ts — reusable server-only middleware that validates Supabase Auth JWTs for all expert-authenticated routes in M-02 (sessions, product queue) and M-04 (payments).
Export: A single async function:
``typescript
export async function expertAuthMiddleware(
req: NextRequest
): Promise<{ expert: { id: string } } | NextResponse>
`
If JWT is valid and role is correct → return { expert: { id: string } } (caller uses this to access expert ID). If invalid → return a NextResponse` error directly (caller must check and return it).
| Implement expertAuthMiddleware service | - type: file - evaluate: File exports a single async expertAuthMiddleware function, reads role from app_metadata (not user_metadata) with code comment explaining why, returns correct 401/403 response shapes for each failure case, calls supabase.auth.getUser() for JWT validation per POL-SEC-002, marked 'use server', no bare any (POL-STYLE-001), no import paths that could reach client bundle (POL-ARCH-003). - min length: 100 | - 1 |
| 4 | developer | Create apps/knowledgevault/src/components/experts/ExpertSignupFlow.tsx — three-screen mobile signup flow. Export named components ExpertSignupForm, StripeRedirect, OnboardingConfirmation plus a default ExpertSignupFlow that orchestrates state.
S-01-a — ExpertSignupForm:
- Full-screen single-column scroll with sticky submit button
- Fields: name (aria-label='Full name', required, autocomplete='name'), email (type='email', required, autocomplete='email'), phone (type='tel', optional, autocomplete='tel'), role_type selector (bottom-sheet: Plumber, Electrician, HVAC Tech, Pipefitter | Implement ExpertSignupFlow UI components | - type: file - evaluate: File exports ExpertSignupForm, StripeRedirect, OnboardingConfirmation as named exports plus default ExpertSignupFlow; S-01-b fires redirect within 500ms of mount; submit button is disabled during API call; 409 shows inline email field error without page reload; S-01-c renders both default and deferred_bank headline/body states correctly; trade selector options are bundled in JS (no network fetch); all ARIA labels, input types, and autocomplete attributes match spec; no bare any (POL-STYLE-001); no SUPABASE_SERVICE_KEY or server-only imports. - min length: 400 | - 2 |
| 5 | developer | Create apps/knowledgevault/src/__tests__/auth/jwtClaims.test.ts — test suite validating the Supabase Auth JWT claim structure and expertAuthMiddleware correctness.
Test group 1 — JWT structure (integration):
After POST /api/experts/signup with a unique email, decode the issued Supabase JWT and assert:
- user.app_metadata.role === 'expert'
- user.app_metadata.expert_id equals the UUID from the 201 response
- expert_id does NOT appear in user.user_metadata (not user-editable)
Test group 2 — auth.expert_id() SQL function:
Using a test DB connection with a seeded expert JWT, | JWT claim validation test suite | - type: file - evaluate: Test file contains all 4 test groups; group 3 includes all 5 middleware scenarios including the critical app_metadata vs user_metadata test (confirming middleware reads from app_metadata per POL-SEC-002); all tests pass with test runner; no bare any (POL-STYLE-001). - min length: 300 | - 2 - 3 |
module id
M-01
module name
Auth & Expert Onboarding
schema version
1.0
depends on modules
- M-00