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

KnowledgeVault AI module-spec M-07

M-07 gives company-authenticated field technicians a semantic search interface over the published knowledge base. A POST /api/query endpoint embeds the natural-language query via text-embedding-3-small (1536d), runs pgvector cosine similarity against knowledge_chunks WHERE is_published=true, ranks results by a fixed formula (cosine_similarity×0.7 + ground_truth_verified::int×0.2 + novelty_score×0.1), and returns the top-5 chunks with expert attribution, chunk type, field-verified badge, and rele

Planning Surface

Use this to decide what happens next.

Status

approved

Phase

M-07

open questions
idownerblocksquestionresolvedresolution
OQ-M-07-01justinD-07-04 ranking SQL queryThe implementation scope blurb states ranking as cosine_similarity×0.7 + recency_weight×0.3 but the functional spec and approved blueprint both specify (cosine_similarity×0.7)+(ground_truth_verified::int×0.2)+(novelty_score×0.1). Which formula is authoritative?true3-factor formula is authoritative: (cosine_similarity×0.7 + ground_truth_verified::int×0.2 + novelty_score×0.1). 2-factor was a stale implementation scope note.
Agent Handoff
Start Here

M-07 gives company-authenticated field technicians a semantic search interface over the published knowledge base. A POST /api/query endpoint embeds the natural-language query via text-embedding-3-small (1536d), runs pgvector cosine similarity against knowledge_chunks WHERE is_published=true, ranks results by a fixed formula (cosine_similarity×0.7 + ground_truth_verified::int×0.2 + novelty_score×0.1), and returns the top-5 chunks with expert attribution, chunk type, field-verified badge, and rele

Completion Evidence

No explicit evidence field yet. Require tests, screenshots, linked PRs, or reviewed outputs before marking complete.

Open Questions
  • OQ-M-07-01: id: string, owner: string, blocks: string, question: string, resolved: boolean, resolution: string
Structured Payload

Machine-readable source fields

summary

M-07 gives company-authenticated field technicians a semantic search interface over the published knowledge base. A POST /api/query endpoint embeds the natural-language query via text-embedding-3-small (1536d), runs pgvector cosine similarity against knowledge_chunks WHERE is_published=true, ranks results by a fixed formula (cosine_similarity×0.7 + ground_truth_verified::int×0.2 + novelty_score×0.1), and returns the top-5 chunks with expert attribution, chunk type, field-verified badge, and relevance score. Every query is logged to the new field_queries table for downstream use by M-09. This module also establishes the company JWT middleware (Supabase Auth role=company + company_id claim) and a demo company-login endpoint; both are reused by M-08 and M-09 without modification.

module id

M-07

api routes
authpatherrorsmethodrequestresponse
public — no JWT required/api/auth/company-login- Missing company_id => 422 {error: "company_id required", code: "VALIDATION_ERROR", status: 422} - Invalid demo_secret => 401 {error: "Invalid credentials", code: "INVALID_CREDENTIALS", status: 401} - company_id not in companies table => 404 {error: "Company not found", code: "COMPANY_NOT_FOUND", status: 404} - COMPANY_DEMO_SECRET env var not set => 500 {error: "Service misconfigured", code: "SERVER_ERROR", status: 500}POST{company_id: string (uuid), demo_secret: string}{access_token: string, token_type: "bearer", expires_in: 3600, company_id: string}
company JWT required — Authorization: Bearer <token> with role=company, company_id claim/api/query- Missing Authorization header => 401 {error: "Authentication required", code: "MISSING_AUTH", status: 401} - Expired/invalid JWT => 401 {error: "Invalid token", code: "INVALID_TOKEN", status: 401} - company_id not in companies table => 403 {error: "Company not found", code: "COMPANY_NOT_FOUND", status: 403} - Missing query field => 422 {error: "query is required", code: "VALIDATION_ERROR", status: 422} - query > 500 chars => 422 {error: "query must be 500 characters or fewer", code: "VALIDATION_ERROR", status: 422} - OpenAI embedding failure => 503 {error: "Embedding service unavailable", codPOST{query: string (required, max 500 chars), sku_filter?: string, chunk_type_filter?: string, verified_only?: boolean}{results: [{chunk_id: string, content: string, chunk_type: string, sku: string, expert_name: string, ground_truth_verified: boolean, captured_at: string (ISO8601), relevance_score: number, field_verified_badge: boolean}], query_id: string}
company JWT required/api/query/recent- Unauthenticated => 401 (from companyAuth middleware) - No queries exist for company => 200 []GETNo body. Optional query param: limit (integer, default 5, max 10)[{query_id: string, query_text: string, created_at: string}] ordered by created_at DESC
data model
notes

knowledge_chunks table is read-only in this module — no mutations. field_queries.results stores the full top-5 response as JSONB for M-09 replay without re-embedding. query_embedding nullable: if OpenAI fails, query_text row still persisted with null embedding.

tables
rlsnameindexespurposekey columns
RLS enabled. Service-role key: full access. Company JWT: SELECT and INSERT WHERE company_id = (auth.jwt()->>'company_id')::uuid. No UPDATE or DELETE for company role.field_queries- idx_field_queries_company_id ON field_queries(company_id) - idx_field_queries_created_at ON field_queries(created_at DESC)Logs every company search query for analytics and M-09 coverage dashboard (top_queries, slang_cloud).- id uuid PK DEFAULT gen_random_uuid() - company_id uuid NOT NULL REFERENCES companies(id) - query_text text NOT NULL - query_embedding vector(1536) nullable - results jsonb nullable - created_at timestamptz NOT NULL DEFAULT now()
module name

Knowledge Retrieval

deliverables
idnametypeinputsoutputsdescription
D-07-010007_field_queries.sqlmigration- companies table must exist (FK reference)- field_queries table created in public schema - idx_field_queries_company_id index created - idx_field_queries_created_at index createdCreates the field_queries table to persist every search query submitted via POST /api/query. Consumed by M-09 (top_queries, slang_cloud analytics). Includes indexes on company_id and created_at.
D-07-02lib/companyAuth.jsservice- HTTP request with Authorization: Bearer <jwt> header - SUPABASE_URL and SUPABASE_SERVICE_ROLE_KEY environment variables - companies table with id uuid column- req.companyId set to UUID string on success - next() called on success - JSON error response on failureExpress/Next.js middleware that validates a company JWT on every request to /api/query, /api/virtual-experts/*, and /api/dashboard/*. Extracts Supabase Auth JWT from Authorization: Bearer header, verifies signature, checks role=company claim, reads company_id claim, queries companies table to confirm company exists. Attaches req.companyId to request context. Returns 401 on missing/invalid/expired JWT. Returns 403 if company_id is not found in companies table. Authored once here and imported without duplication by M-08 and M-09.
D-07-03POST /api/auth/company-loginapi_route- Request body: {company_id: string (uuid), demo_secret: string}- 200: {access_token: string, token_type: "bearer", expires_in: 3600, company_id: string} - 401 on invalid demo_secret - 404 if company_id not in companies table - 422 on missing/malformed bodyDemo login endpoint that mints a Supabase Auth session for a company user. Accepts company_id and shared demo_secret env var. Uses Supabase Admin API to create/retrieve a Supabase Auth user keyed to the company (email: company-<company_id>@demo.knowledgevault.internal), then issues a JWT with custom claims {role: "company", company_id: <company_id>}. Intended for demo flows and internal testing only. Does not require existing JWT.
D-07-04POST /api/queryapi_route- Authorization: Bearer <company_jwt> header - Request body: {query: string (required, 1-500 chars), sku_filter?: string, chunk_type_filter?: string, verified_only?: boolean}- 200: {results: [{chunk_id, content, chunk_type, sku, expert_name, ground_truth_verified, captured_at, relevance_score, field_verified_badge}], query_id: string} - 200: {results: [], query_id: string} when no published chunks match - 401 on missing/invalid JWT (from middleware) - 403 if company_id not in companies table (from middleware) - 422 on missing query field or query > 500 chars - 503 on OpenAI embedding failure with Retry-After: 10 headerCore semantic search endpoint. Protected by companyAuth middleware. Embeds query_text via OpenAI text-embedding-3-small (1536d). Queries knowledge_chunks using pgvector cosine similarity (1 - (embedding <=> query_embedding)) WHERE is_published=true. Optional filters: sku_filter (WHERE sku = ), chunk_type_filter (WHERE chunk_type = ), verified_only (WHERE ground_truth_verified = true). Ranking formula: relevance_score = (cosine_similarity * 0.7) + (ground_truth_verified::int * 0.2) + (COALESCE(novelty_score, 0) * 0.1). Returns top-5 ordered by relevance_score DESC. field_verified_badge=true whe
D-07-05Knowledge Search UI (S-06-a + S-06-b)component- company JWT stored in session/cookie - POST /api/query endpoint (D-07-04) - GET /api/query/recent endpoint (returns [{query_id, query_text, created_at}] for this company, limit 5)- S-06-a and S-06-b screens rendered and routed at /search and /search/results - GET /api/query/recent API route returning recent queries for the authenticated companyTwo-screen search UI for company-authenticated field technicians. S-06-a (KnowledgeSearchScreen): Full-screen, prominent centered search bar (placeholder: "Ask anything about a product or process…"), optional SKU filter input below, recent queries list (last 5 from GET /api/query/recent), Powered by KnowledgeVault badge at bottom. Submitting calls POST /api/query. Skeleton shown during request. S-06-b (SearchResultsScreen): Sticky search bar at top (pre-filled), scrollable results list of up to 5 result cards, Powered by badge at bottom. Each card shows: content, chunk type badge (Failure Mode
integrations
callspurposeservice
- POST https://api.openai.com/v1/embeddings — model: text-embedding-3-small, input: query string, dimensions: 1536. Called once per POST /api/query. 10s timeout. On error => 503 response, query_text still logged to field_queries with null query_embedding.Embed the field technician natural-language query as a 1536-dimension vector for pgvector cosine similarity searchOpenAI
- supabaseAdmin.auth.admin.createUser — create demo company auth user (email: company-<company_id>@demo.knowledgevault.internal) if not exists - supabaseAdmin.auth.admin.generateLink or signInWithPassword — mint access token with custom claims {role: "company", company_id: <uuid>} - supabase.auth.getUser(token) — verify JWT signature and extract claims in companyAuth middlewareIssue and verify company JWTs with custom claims (role=company, company_id). Mint demo sessions via Admin API for POST /api/auth/company-login.Supabase Auth
prerequisites
  • experts table exists with columns: id uuid, name text, role_type text, years_experience integer
  • knowledge_chunks table exists with columns: id uuid, session_id uuid, expert_id uuid, product_id uuid, sku text, chunk_type text, content text, embedding vector(1536), ground_truth_verified boolean, novelty_score float, is_published boolean, created_at timestamptz
  • companies table exists with columns: id uuid, name text, plan text
  • pgvector extension enabled on the Supabase database (CREATE EXTENSION IF NOT EXISTS vector already applied)
  • Supabase Auth configured and capable of issuing JWTs with custom claims (role, company_id)
  • M-05 Evaluation & Knowledge Publication is complete — knowledge_chunks.is_published can be set to true and knowledge_chunks.embedding is populated post-evaluation
  • OPENAI_API_KEY environment variable set with access to text-embedding-3-small
open questions
idownerblocksquestionresolvedresolution
OQ-M-07-01justinD-07-04 ranking SQL queryThe implementation scope blurb states ranking as cosine_similarity×0.7 + recency_weight×0.3 but the functional spec and approved blueprint both specify (cosine_similarity×0.7)+(ground_truth_verified::int×0.2)+(novelty_score×0.1). Which formula is authoritative?true3-factor formula is authoritative: (cosine_similarity×0.7 + ground_truth_verified::int×0.2 + novelty_score×0.1). 2-factor was a stale implementation scope note.
schema version

1.0

authoring notes
middleware reuse

lib/companyAuth.js exported as single middleware function. M-08 and M-09 import it directly — no duplication per constraint.

demo login security

POST /api/auth/company-login gated by COMPANY_DEMO_SECRET env var. Not for production multi-user auth. Production company auth is out of scope.

ranking formula used

(cosine_similarity * 0.7) + (ground_truth_verified::int * 0.2) + (COALESCE(novelty_score, 0) * 0.1) — matches functional spec and approved blueprint. Proceeding with this; flagged as OQ-M-07-01.

company knowledge access

Not used as a search filter in M-07 per out_of_scope. Query searches all is_published=true chunks globally for authenticated company.

field verified badge definition

field_verified_badge=true when knowledge_chunks.created_at > NOW() - INTERVAL 60 minutes — uses chunk own created_at. Consistent with done_when criteria.