Skip to content

Demo Bootstrap & Client Onboarding Tooling Specification

Demo Bootstrap & Client Onboarding Tooling Specification

Section titled “Demo Bootstrap & Client Onboarding Tooling Specification”

ARCHIVED / SUPERSEDED (15/06/2026, ID-95.16 — PI-17). This spec (31/03/2026) pre-dates the ID-95 per-client topology, the tenant_config branding model, and the signup_policy config-table sign-up design. Its bootstrap/onboarding flow (manual SQL snippets, GUC-era assumptions, single-instance seed model) is NOT the current process and MUST NOT be followed. It is retained here as a historical record only — for demo-seed mining of the platform dev/demo instance, mine from THIS archived copy. Current model: specs/id-95-per-client-topology/ (PRODUCT.md + TECH.md) and the operational runbook runbooks/client-app-deploy.md.

This file lives under specs/_archive/, which is excluded from the rendered docs (underscore-prefixed path; see src/content.config.ts glob). A pointer stub remains at the former live path specs/demo-bootstrap-spec.md.

Status: ARCHIVED — superseded by ID-95 (was: Draft) Created: 31/03/2026 Author: Liam + Claude Code


Knowledge Hub needs repeatable tooling to stand up new instances from scratch. Two use cases:

  1. Demo instance — pre-populated with seed data for demonstrations (prospect meetings, trade shows, internal training)
  2. Fresh client onboarding — empty DB populated with client-specific content

Today, standing up a new instance requires manually following docs/operations/production-setup-guide.md, running SQL snippets by hand, and executing multiple scripts in the correct order. This spec defines five phases of work to automate the entire flow into two scripts: bootstrap-instance.sh (demo) and onboard-client.sh (client).


  1. Repeatable demos — The first client is live. Prospect demos currently run against production data, which is unprofessional and risks exposing client information. A dedicated demo instance with curated seed data is needed.

  2. Client onboarding friction — Setting up the first client took multiple sessions of manual work. The second client should take under an hour, not days.

  3. Confidence in schema reproducibility — The migration chain (1 squashed baseline + 20 incremental, 21 total recorded in schema_migrations, plus 1 new migration for entity_aliases) has never been replayed against a fresh Supabase project. This spec forces that validation.

  4. Prerequisite data is undocumented — Taxonomy (15 domains, 57 subtopics), layer vocabulary (4 rows), entity aliases (22 rows), and guide definitions (8 guides) must all be seeded before the application is functional. This knowledge is scattered across migration files, seed scripts, and the production DB.


  • Supabase Pro plan — Per-org pricing model at ~$25/month base + ~$10/month per additional project. A second project is required for demo/client instances.
  • Supabase CLI installed (/opt/homebrew/bin/supabase)
  • API keys — Anthropic (classification/summaries), OpenAI (embeddings)
  • Python 3 with requirements.txt dependencies installed (requirements.txt exists at project root)
  • bun package manager with node_modules installed

AssetLocationNotes
Production setup guidedocs/operations/production-setup-guide.mdManual, step-by-step. Some counts outdated (says 92 migrations, actually 21).
Bid test data seedscripts/seed-bid-test-data.tsCreates 1 bid workspace, 10 questions, 3 responses. Idempotent, supports --dry-run and --clean.
Guide definitions seedscripts/seed-phew-guides.tsCreates 8 guides (4 sector, 3 product, 1 company) with sections. Idempotent, supports --apply and --clear.
Migration filessupabase/migrations/ (21 files, will become 22)1 squashed baseline (S118) + 20 incremental. Never replayed on a fresh project. Missing entity_aliases table (BLOCKER).
Client documentationdocs/client-documentation/9 .docx files (7 Q&A library + 2 non-Q&A: Product_KB_Dev_Brief.docx, Sector-Intelligence-Brief-Liam-Final.docx), 12 .md files (9 in markdown/ subdir + 3 at root: Knowledge Hub -- Claude Integration Guide.md, Knowledge Hub -- Platform Overview.md, sector-intelligence-analysis.md), 1 PDF. Covers audits, LMS, security, FAQs.
Python ingestion scriptsscripts/ingest.py, scripts/ingest_markdown.py, scripts/import_bid_library.pyThree entry points for different content types.
Entity aliases (DB)entity_aliases table22 rows: 14 generic (ISO, WordPress, etc.) + 8 client-specific (Phew products). BLOCKER: This table is NOT present in any of the 21 migration files — it exists only in production. A prerequisite migration is required before seed.sql can work.
Taxonomy (DB)taxonomy_domains + taxonomy_subtopics15 domains, 57 subtopics. 10 domains have key signals (security, compliance, implementation, support, corporate, product-feature, methodology, legislation-policy, market-intelligence, sector-news), 5 are sector intelligence domains without key signals (safeguarding-child-protection, safeguarding-adults, multi-academy-trusts, education, products-services).
Layer vocabulary (DB)layer_vocabulary table4 rows: sales_brief, bid_detail, company_reference, research. Note: production setup guide says 5 (fact/evidence/method/policy/narrative) but the actual DB has 4 different values.
Coverage targetscoverage_targets tableEmpty — no defaults exist.
Content templatescontent_templates tableEmpty — no defaults exist.
Governance configgovernance_config tableEmpty — no defaults exist. Schema: per-domain rows with posture/reviewer_id/timeout_days/thresholds, NOT key/value.
  1. No supabase/seed.sql — All reference data lives only in the production DB or hardcoded in seed scripts
  2. No orchestration script — Each step must be run manually in the correct order
  3. No demo data pack — No curated content set designed to showcase all features
  4. No post-setup validation — No automated check that a new instance is functional
  5. No client onboarding script — No way to set up a new client without deep platform knowledge

Goal: Create supabase/seed.sql containing all reference data needed for a functional Knowledge Hub instance.

PREREQUISITE: Before seed.sql can be applied, the entity_aliases table must exist. This table is NOT present in any of the 21 migration files — it exists only in production (likely created via MCP execute_sql during S118 or earlier). A new migration must be created first:

-- Migration: create_entity_aliases_table
CREATE TABLE IF NOT EXISTS public.entity_aliases (
id uuid DEFAULT gen_random_uuid() PRIMARY KEY,
alias text NOT NULL,
canonical text NOT NULL,
is_active boolean DEFAULT true,
created_at timestamptz DEFAULT now()
);
CREATE INDEX IF NOT EXISTS idx_entity_aliases_alias ON public.entity_aliases (alias);
CREATE UNIQUE INDEX IF NOT EXISTS idx_entity_aliases_alias_canonical ON public.entity_aliases (alias, canonical);
ALTER TABLE public.entity_aliases ENABLE ROW LEVEL SECURITY;
-- RLS: same pattern as other reference tables
CREATE POLICY entity_aliases_select ON public.entity_aliases
FOR SELECT TO authenticated USING (true);
CREATE POLICY entity_aliases_insert ON public.entity_aliases
FOR INSERT TO authenticated WITH CHECK (public.get_user_role() = 'admin');
CREATE POLICY entity_aliases_update ON public.entity_aliases
FOR UPDATE TO authenticated USING (public.get_user_role() = 'admin');
CREATE POLICY entity_aliases_delete ON public.entity_aliases
FOR DELETE TO authenticated USING (public.get_user_role() = 'admin');

This migration must be created via supabase migration new create_entity_aliases and pushed via supabase db push BEFORE Phase 2 bootstrap can succeed.

Create a single idempotent SQL file that seeds all prerequisite data. Each section uses INSERT ... ON CONFLICT DO NOTHING or equivalent guards.

Extracted from production DB. All values must be seeded:

INSERT INTO taxonomy_domains (id, name, description, colour, display_order, key_signal)
VALUES
('17d9f23f-1c4f-4d6d-b9c3-f37c178a547e', 'security',
'Information security, data protection, cyber security, and access control policies and practices.',
'security', 1,
'**Key signal:** Content about protecting information, systems, and data — controls, policies, and security practices.'),
('8d6c0b63-f77c-4021-a54b-15c07fa04420', 'compliance',
'Regulatory compliance, industry standards, certifications, and audit processes.',
'compliance', 2,
'**Key signal:** Content about proving adherence to external requirements — standards bodies, regulators, auditors.'),
('7ea9e1ca-0a99-48e4-8a38-0aff9b910e7b', 'implementation',
'Solution deployment, system migration, client onboarding, and third-party integration.',
'implementation', 3,
'**Key signal:** Content about concrete delivery activities — what happens, when it happens, and how the transition is managed.'),
('d234988f-f548-4ea6-afbd-3aa7969674bd', 'support',
'Service level agreements, helpdesk operations, maintenance, and incident management.',
'support', 4,
'**Key signal:** Content about keeping a live service running — BAU operations, response commitments, and what happens when things go wrong.'),
('2cf9db4f-fa8d-4c7b-97ce-c3ce6f966f1b', 'corporate',
'Company information, financial standing, insurance, references, and staffing.',
'corporate', 5,
'**Key signal:** Content about the organisation itself — who you are, your track record, your people, and your financial health.'),
('609bbcc4-ea14-4d74-b53d-d074ddce19a4', 'product-feature',
'Product functionality, technical capabilities, reporting, and usability.',
'product', 6,
'**Key signal:** Content about what the product or platform CAN do — its capabilities, architecture, and user experience.'),
('047b2b0f-59a1-4242-bbc8-b912c57d29aa', 'methodology',
'Project delivery approach, project management, quality assurance, and delivery frameworks.',
'methodology', 7,
'**Key signal:** Content about HOW you work — your processes, governance, and quality practices.'),
('52eb10ea-eaa6-433d-9c56-d573240b5cf8', 'safeguarding-child-protection',
'Safeguarding children and young people — KCSIE, DBS, SCR, DSL roles, safer recruitment, and child protection policies.',
'security', 8, NULL),
('7ced99c1-cc93-4074-a4fb-d3c6f30b817b', 'safeguarding-adults',
'Adult safeguarding — SAB statutory duties, Making Safeguarding Personal, Care Act compliance, and vulnerable adult protection.',
'compliance', 9, NULL),
('9da13d3a-5ccb-4363-adc0-ce32dc442423', 'multi-academy-trusts',
'MAT governance, central services, school improvement, trust-wide compliance, and multi-site safeguarding.',
'implementation', 10, NULL),
('e6be270b-5ee4-4b5a-ab51-3627fbed2372', 'education',
'Education sector — schools, colleges, universities, Ofsted, DfE requirements, and education technology.',
'methodology', 11, NULL),
('406054e3-8e00-46e2-9bff-038b9daff1b9', 'products-services',
'Phew Design product portfolio — LMS, Websites, Advanced Audits, and associated services.',
'product', 12, NULL),
('5e792735-8ce9-4b45-901b-44aaeb79bd9e', 'legislation-policy',
NULL, NULL, 13,
'**Key signal:** Content about laws, statutory guidance, regulatory policy updates, and legislative instruments.'),
('dee601a0-7c43-4470-acea-da0cbfc1601c', 'market-intelligence',
NULL, NULL, 14,
'**Key signal:** Content about competitors, market trends, procurement activity, and commercial landscape.'),
('43326cbe-bbe3-47f5-a70e-df314bfa966d', 'sector-news',
NULL, NULL, 15,
'**Key signal:** Content about sector events, leadership changes, inspections, audits, and organisational restructuring in target sectors.')
ON CONFLICT (id) DO NOTHING;

All 57 subtopics extracted from production, grouped by parent domain. The seed SQL will reference parent domain IDs using the hardcoded UUIDs above. Full list grouped by domain:

  • security (5): data-protection, cyber-security, encryption, access-control, iso-27001
  • compliance (9): standards, regulatory, audit, certification, health-and-safety, environmental, modern-slavery, equalities, safeguarding
  • implementation (4): deployment, migration, onboarding, integration
  • support (4): sla, helpdesk, maintenance, incident
  • corporate (8): company-info, financial, insurance, references, staffing, supply-chain, financial-standing, methodology
  • product-feature (4): functionality, technical, reporting, usability
  • methodology (4): approach, project-management, quality, delivery
  • legislation-policy (7): kcsie, education-act-dfe, health-social-care-legislation, gdpr-data-protection, funding-policy, safeguarding-guidance, cpd-requirements
  • market-intelligence (5): competitor-products, competitor-market-activity, competitor-leadership, market-trends, procurement-activity
  • sector-news (7): mat-leadership, mat-restructuring, mat-audits-ofsted, education-sector-audits, health-sector-audits, local-authority-inspections, safeguarding-practice

Each row includes the production UUID, name, description, display_order, and domain_id FK.

INSERT INTO layer_vocabulary (id, key, label, description, display_order, is_active)
VALUES
('d9fbcd98-f865-4229-8497-f82fae611973', 'sales_brief', 'Sales Brief',
'Positioning and messaging for internal sales', 10, true),
('01fe4de1-4f3c-433e-8f08-191f10ce54dd', 'bid_detail', 'Bid Detail',
'Factual content for tender responses', 20, true),
('3c2ce19c-e8f1-40a5-8c60-8912737b4572', 'company_reference', 'Company Reference',
'Controlled corporate documents', 30, true),
('4509e22e-defc-4dde-9a71-ee8e24e32f89', 'research', 'Research',
'Background material and market intelligence', 40, true)
ON CONFLICT (id) DO NOTHING;

Note: The production setup guide documents 5 layer vocabulary rows (fact, evidence, method, policy, narrative) but the actual production DB has 4 different rows (sales_brief, bid_detail, company_reference, research). The seed SQL must match production reality.

Two categories:

Generic aliases (14 rows) — technology/standard names, client-independent:

  • ISO Certification -> ISO 27001, Iso Certifications -> ISO 27001, ISO 27001 2013 -> ISO 27001, ISO 27000 -> ISO 27001
  • ISO 9001 2015 -> ISO 9001
  • wordpress -> WordPress, Wordpress -> WordPress
  • Csharp -> C#, csharp -> C#
  • Asp Net -> ASP.NET, Asp.net -> ASP.NET
  • Hcaptcha -> hCaptcha, Wcag 2 1 Aa -> WCAG 2.1 AA, agile -> Agile

Client-specific aliases (8 rows) — Phew Design product/company names:

  • Phew -> Phew Design Limited, Phew Design Ltd -> Phew Design Limited
  • Learning Management System -> Phew LMS, Phew Lms -> Phew LMS
  • Phew Audit -> Phew Audit System, Phew Audit Platform -> Phew Audit System
  • Phew Pdms -> Phew PDMS

Note: The exact split between generic and client-specific aliases should be verified by querying production: SELECT * FROM entity_aliases ORDER BY canonical;. The 22-row total is confirmed, but some aliases may have been recategorised since the last manual count.

The seed SQL will include all 22 with ON CONFLICT DO NOTHING. For client onboarding, a separate step will replace client-specific aliases with the new client’s product names.

Currently empty in production. The actual table schema (from baseline migration) is per-domain, not key/value:

-- governance_config schema (from migration):
-- id uuid PK
-- domain text NOT NULL UNIQUE
-- posture text NOT NULL DEFAULT 'open' CHECK (posture IN ('open', 'review_on_change'))
-- reviewer_id uuid FK -> auth.users
-- timeout_days integer DEFAULT 7
-- quality_score_threshold integer DEFAULT 40
-- auto_flag_on_quality_drop boolean DEFAULT true
-- auto_flag_on_freshness_transition boolean DEFAULT true
-- auto_flag_cooldown_days integer DEFAULT 7
-- created_by uuid FK -> auth.users
-- updated_by uuid FK -> auth.users
-- created_at timestamptz DEFAULT now()
-- updated_at timestamptz DEFAULT now()

Recommendation: Leave governance_config empty in seed.sql (matching production state). Governance posture should be configured per-client via the admin UI after setup, because reviewer_id requires a valid auth.users UUID which does not exist until after user creation. Add a comment in seed.sql:

-- governance_config: intentionally empty.
-- Configure per-domain governance posture via Admin > Settings after creating users.
-- Table columns: domain, posture (open|review_on_change), reviewer_id, timeout_days,
-- quality_score_threshold, auto_flag_on_quality_drop, auto_flag_on_freshness_transition,
-- auto_flag_cooldown_days.
FileAction
supabase/migrations/YYYYMMDDHHMMSS_create_entity_aliases.sqlCreate — prerequisite migration for entity_aliases table (BLOCKER)
supabase/seed.sqlCreate — all reference data in one idempotent SQL file
  • seed.sql can be applied to a fresh post-migration DB without errors
  • All 15 taxonomy domains present with correct key signals
  • All 57 taxonomy subtopics present with correct parent domain references
  • All 4 layer vocabulary rows present
  • All 22 entity aliases present
  • Re-running seed.sql on an already-seeded DB produces no errors (idempotent)
  • UUIDs in seed match production values (enables consistent cross-environment references)

3-4 hours — Primarily data extraction and SQL authoring. The taxonomy and subtopic data is the bulk of the work (57 individual INSERT statements with UUIDs and FKs).


Goal: Create scripts/bootstrap-instance.sh — a single script that takes a fresh Supabase project from empty to fully functional demo instance.

#!/usr/bin/env bash
set -euo pipefail
# Usage:
# ./scripts/bootstrap-instance.sh # interactive
# ./scripts/bootstrap-instance.sh --env .env.demo # use env file
# ./scripts/bootstrap-instance.sh --dry-run # preview only

The script accepts:

  • --env <path> — path to .env file with target Supabase credentials
  • --dry-run — print what would happen without executing
  • --skip-migrations — skip migration push (if already applied)
  • --skip-seed — skip seed.sql (if already applied)
  • --skip-guides — skip guide seeding
  • --skip-bid-data — skip bid test data seeding
  • --demo — include demo data pack (Phase 4)

Required env vars (from file or environment):

  • SUPABASE_URL / NEXT_PUBLIC_SUPABASE_URL
  • SUPABASE_ANON_KEY / NEXT_PUBLIC_SUPABASE_ANON_KEY
  • SUPABASE_SECRET_KEY
  • SUPABASE_PROJECT_REF — project ID for CLI commands
  • SUPABASE_DB_PASSWORD — required for supabase db push
  • ANTHROPIC_API_KEY — for classification during content ingestion
  • OPENAI_API_KEY — for embedding generation
  1. Verify connection — Query SELECT 1 via Supabase JS client to confirm credentials work
  2. Check DB state — Count tables in public schema. If > 0, warn and require --force to proceed
  3. Link projectsupabase link --project-ref $SUPABASE_PROJECT_REF
  4. Push migrationssupabase db push (applies all 22 migration files: 21 existing + 1 new entity_aliases)
  5. Verify migrationssupabase migration list and confirm count matches local files
  6. Apply seed.sql — Execute via psql or Supabase REST API
  7. Verify seed — Count taxonomy_domains (expect 15), taxonomy_subtopics (expect 57), layer_vocabulary (expect 4), entity_aliases (expect 22)
  8. Seed guidesbun run scripts/seed-phew-guides.ts --apply
  9. Verify guides — Count guides (expect 8) and guide_sections (expect >= 70)
  10. Seed bid test databun run scripts/seed-bid-test-data.ts
  11. Verify bid data — Count workspaces (expect 1), bid_questions (expect 10), bid_responses (expect 3)
  12. Print summary — Table of all verification results

Each step checks whether it has already been completed:

  • Migrations: supabase migration list shows applied count
  • Seed data: Count queries before inserting (seed.sql uses ON CONFLICT DO NOTHING)
  • Guides: seed-phew-guides.ts already has idempotent slug-check
  • Bid data: seed-bid-test-data.ts already checks for existing test bid
  • Each step exits with a clear error message on failure
  • --dry-run prints each step without executing
  • Failed steps do not prevent subsequent steps from being attempted (with --continue-on-error flag)
  • Final summary marks each step as PASS/FAIL/SKIP
FileAction
scripts/bootstrap-instance.shCreate — orchestration script
scripts/lib/bootstrap-utils.shCreate — shared functions (verify_connection, count_rows, print_summary)
  • Script runs end-to-end against a fresh Supabase project without manual intervention
  • --dry-run mode prints all steps without executing any
  • Idempotent — safe to re-run on an already-bootstrapped instance
  • Each step has a verification check that confirms success
  • Script exits with non-zero code if any critical step fails
  • Works with both .env file and environment variables

4-5 hours — Shell scripting, Supabase CLI integration, verification logic.


Goal: Create scripts/onboard-client.sh — automates setting up a new client instance with their specific content.

#!/usr/bin/env bash
set -euo pipefail
# Usage:
# ./scripts/onboard-client.sh \
# --client "Acme Corp" \
# --env .env.acme \
# --docs ./acme-documents/ \
# --taxonomy ./acme-taxonomy.json # optional

Required:

  • --client <name> — client name (used in logging and metadata)
  • --env <path> — path to .env file for the client’s Supabase project
  • --docs <dir> — directory containing client documents for ingestion

Optional:

  • --taxonomy <path> — JSON file with client-specific taxonomy overrides
  • --aliases <path> — JSON file with client-specific entity aliases
  • --urls <path> — text file with URLs to ingest (one per line)
  • --skip-bootstrap — skip migrations and seed (if already done)
  • --dry-run — preview mode
  • --batch-tag <tag> — tag for the import batch (defaults to initial-import-{date})
  1. Bootstrap — Run bootstrap-instance.sh --env $ENV --skip-bid-data (clients don’t need test bid data)
  2. Customise taxonomy — If --taxonomy provided, apply overrides:
    • Add client-specific domains
    • Modify descriptions or key signals
    • Remove irrelevant domains (mark inactive, don’t delete)
  3. Seed client aliases — If --aliases provided, insert client-specific entity aliases
  4. Create admin user — Print instructions for manual user creation (cannot be automated — Supabase Auth requires email verification)
  5. Ingest .docx files — Scan --docs dir for .docx files, run python3 scripts/import_bid_library.py <dir> --batch-tag $TAG
  6. Ingest .md files — Scan --docs dir for .md files/subdirs, run python3 scripts/ingest_markdown.py <dir> --tag $TAG --author "$CLIENT"
  7. Ingest URLs — If --urls provided, run python3 scripts/ingest.py --file $URLS
  8. Generate summariesbun run scripts/batch-generate-summaries.ts for items missing AI summaries
  9. Seed guides — Run scripts/seed-phew-guides.ts --apply (or client-specific guide definitions if provided)
  10. Post-onboarding verification:
    • Count content_items by content_type
    • Count content_items by primary_domain
    • Count items with embeddings vs without
    • Count items with classifications vs without
    • Count Q&A library entries
    • Verify semantic search returns results
    • Print summary report
{
"add_domains": [
{
"name": "client-specific-domain",
"description": "Description of the domain",
"colour": "security",
"display_order": 20,
"key_signal": "Key signal text"
}
],
"modify_domains": [
{
"name": "corporate",
"description": "Updated description for this client"
}
],
"deactivate_domains": ["sector-news", "market-intelligence"]
}
{
"aliases": [
{
"alias": "Acme",
"canonical": "Acme Corporation Ltd",
"category": "client"
},
{
"alias": "Acme Corp",
"canonical": "Acme Corporation Ltd",
"category": "client"
},
{
"alias": "Widget Pro",
"canonical": "Acme Widget Pro Platform",
"category": "client"
}
],
"remove_aliases": ["Phew", "Phew Design Ltd", "Phew Lms"]
}

The script provides progress output at each stage:

[1/10] Bootstrap: applying migrations... DONE (21 migrations)
[2/10] Bootstrap: applying seed data... DONE (15 domains, 57 subtopics)
[3/10] Customising taxonomy... SKIP (no --taxonomy provided)
[4/10] Seeding client aliases... DONE (12 aliases)
[5/10] Admin user setup... MANUAL (see instructions below)
[6/10] Ingesting .docx files... DONE (7 Q&A files, 142 Q&A pairs + 2 narrative docs)
[7/10] Ingesting .md files... DONE (12 files, 12 content items)
[8/10] Ingesting URLs... SKIP (no --urls provided)
[9/10] Generating AI summaries... DONE (16 summaries)
[10/10] Verification... PASS
=== Onboarding Summary ===
Client: Acme Corp
Content items: 151
- Q&A pairs: 142
- Articles: 9
Classified: 151/151 (100%)
Embedded: 151/151 (100%)
Domains covered: 7/15
FileAction
scripts/onboard-client.shCreate — client onboarding orchestration
scripts/lib/onboard-utils.shCreate — shared functions for onboarding
docs/templates/client-taxonomy.example.jsonCreate — taxonomy override template
docs/templates/client-aliases.example.jsonCreate — alias override template
  • Script sets up a functional client instance from scratch with one command (plus manual admin user step)
  • Supports mixed content types (.docx, .md, URLs)
  • Taxonomy customisation works for adding, modifying, and deactivating domains
  • Client-specific aliases replace Phew-specific ones
  • Post-onboarding verification catches missing classifications or embeddings
  • --dry-run shows what would happen without writing data
  • Progress reporting is clear and informative

6-8 hours — More complex than bootstrap due to taxonomy customisation, multi-format ingestion, and verification logic.


Goal: Define and implement a curated demo dataset that showcases all Knowledge Hub features.

A compelling demo must cover these features:

FeatureMinimum data needed
Browse page15+ content items across 4+ domains, mix of content types (article, blog, guidance, Q&A)
SearchSufficient content density for meaningful semantic search results (at least 3 results per common query)
Bid workspace1 active bid with 10 questions, 3 draft responses, KB matches visible
Q&A Library20+ Q&A pairs across multiple domains for copy-to-bid demonstration
Coverage matrixItems in at least 5 domains, visible gaps in 2-3 domains
DashboardMix of fresh/ageing content, quality scores distributed across range, recent activity
Review queue3-5 items pending review (low quality score or governance flags)
Guides8 guides with some sections populated, some empty (shows value of filling gaps)
Change reportsAt least 1 digest covering recent content changes
Entity graphMultiple entities with relationships (e.g. ISO 27001 mentioned across 5+ items)

The demo data pack ingests from three sources:

  1. Client documentation (markdown) — 12 .md files total:

    • docs/client-documentation/markdown/ — 9 .md files (converted from .docx Q&A templates)
    • docs/client-documentation/ (root) — 3 .md files: Knowledge Hub -- Claude Integration Guide.md, Knowledge Hub -- Platform Overview.md, sector-intelligence-analysis.md These get classified and embedded automatically via ingest_markdown.py.
  2. Client .docx Q&A files (docs/client-documentation/*.docx) — 9 .docx files total, but requiring different ingestion paths:

    • Q&A library files (7): The “Tender and Bid Library Template” and “DRAFT” .docx files. Ingest via import_bid_library.py.
    • Non-Q&A .docx files (2): Product_KB_Dev_Brief.docx and Sector-Intelligence-Brief-Liam-Final.docx. These are narrative documents, not Q&A pairs. Ingest via ingest_markdown.py after converting to markdown (mammoth or manual), or via ingest.py if a URL-based approach is preferred.
  3. Synthetic demo content — A small set of purpose-built content items that fill specific demo gaps (e.g. items in domains not covered by real client docs, items with varying quality scores, items with known expiry dates for freshness demonstration).

Create scripts/demo-content.json containing 10-15 synthetic content items designed to:

  • Fill domain coverage gaps (ensure at least 5 domains have content)
  • Provide varying quality scores (some high, some low for review queue)
  • Include items with expiry dates (for freshness demonstration)
  • Include items with different content types (article, blog, guidance, policy)
  • Include items created at different dates (for dashboard time distribution)

The bootstrap-instance.sh --demo flag triggers additional steps after base bootstrap:

  1. Ingest docs/client-documentation/markdown/ via ingest_markdown.py (9 files)
  2. Ingest docs/client-documentation/*.md (3 root-level .md files) via ingest_markdown.py
  3. Import Q&A .docx files (7) via import_bid_library.py
  4. Ingest non-Q&A .docx files (2: Product_KB_Dev_Brief.docx, Sector-Intelligence-Brief-Liam-Final.docx) via ingest_markdown.py after mammoth conversion
  5. Insert synthetic demo content from scripts/demo-content.json
  6. Run batch-generate-summaries.ts for AI summaries
  7. Backfill reader HTML via backfill-reader-html.ts
  8. Verify demo coverage:
    • Content spans 5+ domains
    • Browse page shows 15+ items
    • Q&A library has 20+ entries
    • At least 1 bid workspace exists with matched content
    • Coverage matrix shows both coverage and gaps
FileAction
scripts/demo-content.jsonCreate — synthetic demo content definitions
scripts/seed-demo-content.tsCreate — inserts synthetic demo items with classification + embedding
scripts/bootstrap-instance.shModify — add --demo flag handling
  • bootstrap-instance.sh --demo produces a fully populated demo instance
  • Browse page shows 15+ items across multiple domains and content types
  • Semantic search returns relevant results for common bid queries (e.g. “data protection”, “quality management”, “case studies”)
  • Bid workspace shows matched KB content for test questions
  • Coverage matrix shows meaningful coverage with visible gaps
  • Dashboard displays distributed quality scores and freshness states
  • Demo can be reset and rebuilt from scratch in under 30 minutes (including AI processing)

5-6 hours — Synthetic content authoring, ingestion script, verification checks.


Goal: Update operational documentation to reference new tooling and create guides for demo and client onboarding flows.

Modify docs/operations/production-setup-guide.md:

  • Fix outdated migration count (says 92, should say 21)
  • Fix outdated table count (says 30, should say 39 tables + 1 view: quality_issues_pending)
  • Fix layer vocabulary description (says 5 rows with fact/evidence/method/policy/narrative, should say 4 rows with sales_brief/bid_detail/company_reference/research)
  • Add reference to supabase/seed.sql for step 4 (Configure Taxonomy)
  • Add reference to bootstrap-instance.sh as alternative to manual setup
  • Add reference to onboard-client.sh for client setup

Create docs/operations/demo-setup-guide.md:

  • Prerequisites (Supabase project, API keys, local environment)
  • Quick start: ./scripts/bootstrap-instance.sh --env .env.demo --demo
  • What the demo includes (content, bids, guides)
  • How to reset the demo (delete project, recreate, re-run)
  • Demo walkthrough script (suggested flow for prospect meetings)
  • Troubleshooting common issues

Create docs/operations/client-onboarding-guide.md:

  • Prerequisites checklist
  • Preparing client documents (accepted formats, directory structure)
  • Creating the Supabase project
  • Running the onboarding script
  • Post-onboarding manual steps (create admin user, invite team)
  • Customising taxonomy for the client
  • Verifying the setup
  • Ongoing maintenance (cron jobs, monitoring)
FileAction
docs/operations/production-setup-guide.mdModify — fix counts, add tooling references
docs/operations/demo-setup-guide.mdCreate — demo-specific instructions
docs/operations/client-onboarding-guide.mdCreate — client onboarding flow
  • Production setup guide has accurate counts and references new tooling
  • Demo setup guide enables a new team member to stand up a demo instance without prior knowledge
  • Client onboarding guide covers the full flow from project creation to verification
  • All guides use UK English, DD/MM/YYYY date format

2-3 hours — Documentation writing and cross-referencing.


After all phases are complete, the following end-to-end verification must pass:

  1. Fresh project test — Create a new Supabase project, run bootstrap-instance.sh --demo, verify all acceptance criteria from Phases 1-4
  2. Idempotency test — Re-run bootstrap-instance.sh on the same project, verify no errors and no duplicate data
  3. Client onboarding test — Create another new project, run onboard-client.sh with the existing client documentation, verify content is ingested and classified
  4. Migration replay validation — Confirm all 22 migrations (21 existing + 1 new entity_aliases) apply cleanly to a fresh project (this is the first time the squashed baseline has been replayed)

PhaseDescriptionEffortDependencies
1Seed SQL (supabase/seed.sql) + entity_aliases migration3-4hNone (migration is a blocker for seed)
2Bootstrap Script (scripts/bootstrap-instance.sh)4-5hPhase 1
3Client Onboarding Script (scripts/onboard-client.sh)6-8hPhase 2
4Demo Data Pack5-6hPhase 2
5Documentation2-3hPhases 1-4
Total20-26h

Phases 3 and 4 can run in parallel after Phase 2 is complete. With two agents, the total wall-clock time could be reduced to 15-19 hours.


DependencyTypeNotes
Supabase Pro planInfrastructureSecond project needed. ~$10/month additional.
Supabase CLIToolingMust be installed at /opt/homebrew/bin/supabase
Migration chain integrityTechnicalThe 21-migration chain (+ 1 new entity_aliases migration) has never been replayed. Phase 2 is the first validation.
Python environmentToolingrequirements.txt exists at project root. Install via pip install -r requirements.txt.
API keysInfrastructureAnthropic + OpenAI keys needed for classification and embedding during content ingestion
Jina Reader (r.jina.ai)External serviceUsed by ingest.py for URL content extraction. Requires network access to r.jina.ai.
SentryExternal service (optional)Error tracking. Not required for bootstrap but recommended for production instances.
docs/client-documentation/DataMust remain in repo for demo data pack
entity_aliases migrationTechnical (BLOCKER)Must be created and pushed before seed.sql can be applied. See Phase 1 prerequisite.

RiskSeverityMitigation
Migration replay fails on fresh projectHighPhase 2 validates this explicitly. If it fails, fix migrations before proceeding.
entity_aliases table missing from migrationsHigh (BLOCKER)Must create migration before Phase 1 seed can work. See Phase 1 prerequisite section.
Seed SQL UUIDs conflict with auto-generated IDsMediumUse explicit UUIDs from production to avoid collisions. Test on fresh project.
Demo content insufficient for compelling demoMediumPhase 4 includes verification criteria. Iterate on synthetic content if coverage is thin.
Supabase CLI TLS errors during migration pushLowDocumented in production setup guide. Fallback: use MCP apply_migration tool.
Python ingestion scripts fail on client documentsMediumTest with existing client docs in Phase 4. Document supported formats in Phase 5.
Layer vocabulary values outdated in docsLowPhase 1 establishes canonical values from production DB. Phase 5 fixes documentation.
Key signal text abbreviated in seed SQLMediumSeed SQL should use full production text from the taxonomy migration, not hand-abbreviated versions. Script extraction from production DB recommended over manual enumeration.
Subtopic count fragilityMediumThe 57-subtopic list is fragile if manually maintained. Seed extraction should be scripted from production DB (SELECT * FROM taxonomy_subtopics ORDER BY domain_id, display_order;) rather than manually enumerated, to avoid counts drifting.

  1. Should the seed SQL include Phew-specific entity aliases? For a generic demo, yes. For a new client, the Phew aliases should be replaced. The current design includes all 22 in seed.sql and the client onboarding script removes/replaces client-specific ones.

  2. Should guide definitions be in seed.sql or remain in the TypeScript seed script? The current design keeps them in seed-phew-guides.ts because they contain complex nested section definitions that are cleaner in TypeScript. The bootstrap script calls the TS script after applying seed.sql.

  3. Should the bootstrap script handle Vercel deployment? No — deployment is a separate concern. The bootstrap script handles DB setup only. Vercel deployment follows the existing production setup guide.

  4. Coverage targets and content templates — should we seed defaults? Both tables are currently empty in production. If sensible defaults emerge during implementation, they should be added to seed.sql. Otherwise, they remain empty and are configured per-client after onboarding.