KnowledgeVault AI plan-module M-01
internal prototype · canonical JSON + Dreamborn Forge HTML
internal generated
plan-module · supabase_json

KnowledgeVault AI plan-module M-01

plan-module artifact · for KnowledgeVault AI · phase M-01 · status draft

Planning Surface

Use this to decide what happens next.

Status

draft

Phase

M-01

tasks
idrolebrieftitlecompletiondepends on
1developerCreate 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 timesCreate 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
2developerCreate 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 cImplement 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
3developerCreate 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
4developerCreate 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, PipefitterImplement 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
5developerCreate 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
idrolebrieftitlecompletiondepends on
1developerCreate 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 timesCreate 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
2developerCreate 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 cImplement 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
3developerCreate 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
4developerCreate 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, PipefitterImplement 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
5developerCreate 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
idrolebrieftitlecompletiondepends on
1developerCreate 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 timesCreate 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
2developerCreate 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 cImplement 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
3developerCreate 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
4developerCreate 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, PipefitterImplement 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
5developerCreate 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