Skip to content

Product-Guide Workspaces — TECH

Status: [CURRENT-CANONICAL] — NEW-S244 Wave 0. Companion to PRODUCT.md. Phase 1 reserved-seat scope only; per-app columns deferred to product-guide feature build.

This file carries implementation references for the Phase 1 reserved seat. Each T-N entry inherits the corresponding S-N invariant from ./PRODUCT.md + the parent docs/specs/reserved-workspace-seats/PRODUCT.md S-1..S-8. T-N entries below cover only what’s specific to the product_guide_workspaces seat — they do not re-state the generic reserved-seat DDL pattern (cross-ref to RWS TECH T-1..T-8 for that).

Each T-N entry contains:

  • Current state: code / migration file:line that today implements the invariant, or “greenfield” if no code exists.
  • Target state: what the platform must do after the Phase 1 migration applies.
  • Gate: any STILL-OPEN dependency.
  • Validation: how the invariant is verified.
  • ./PRODUCT.md — Phase 1 reserved-seat invariants (cross-refs to RWS S-1..S-8).
  • docs/specs/reserved-workspace-seats/{PRODUCT,TECH}.md — parent spec for the reserved-seat pattern; S-1..S-8 invariants + T-1..T-8 implementation references.
  • docs/specs/id-38-rls-pattern/{PRODUCT,TECH}.md — RLS auto-enable + grants-helper pattern.
  • docs/specs/id-31-canonical-pipeline-implementation-plan/PLAN.md §4.2 T2 sub-task 7 — combined-PR migration scope landing the 5 reserved satellite seats.
  • docs/plans/phase-0-investigation/architecture/04-workspace-types.md §3.2 + §4.2 — application_types instance table + per-application-type satellite pattern.
  • docs/ontology/25-application-type.mdproduct_guide as baseline core-provenance application type.

Engineers writing the Phase 1 reserved-seats migration (T2 sub-task 7) for the product_guide_workspaces row of that migration; future product-guide feature-spec authors planning the per-app ALTER TABLE pattern.


T-1 — Satellite shape (reserved seat only) (implements S-1, S-2, S-3 via PRODUCT.md invariants 1, 3, 4)

Section titled “T-1 — Satellite shape (reserved seat only) (implements S-1, S-2, S-3 via PRODUCT.md invariants 1, 3, 4)”

Current state: Greenfield. The table product_guide_workspaces does not exist in either staging (turayklvaunphgbgscat) or production (rovrymhhffssilaftdwd) schemas as of S243. Confirmed by absence from supabase/types/database.types.ts (auto-generated; never hand-edited per CLAUDE.md “Supabase & Schema”).

Target state: The migration landing the 5 reserved seats (PLAN.md §4.2 T2 sub-task 7) creates product_guide_workspaces in the same transaction as the other 4 reserved seats per docs/specs/reserved-workspace-seats/TECH.md T-1 BEGIN/COMMIT envelope. Shape:

CREATE TABLE public.product_guide_workspaces (
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
workspace_id uuid NOT NULL UNIQUE REFERENCES workspaces(id) ON DELETE CASCADE,
created_at timestamptz NOT NULL DEFAULT now(),
updated_at timestamptz NOT NULL DEFAULT now()
);

Identical shape to the other 4 reserved seats per docs/specs/reserved-workspace-seats/TECH.md T-1 (lines 41-62 of that doc — intelligence_workspaces, sales_proposal_workspaces, product_guide_workspaces, competitor_research_workspaces, training_onboarding_workspaces all share the shell shape).

Lands in: Same migration as the other 4 reserved seats (Q-OQR1-16 combined PR per PLAN.md §4.2 T2 sub-task 7) — filename per Supabase migration timestamp convention. Single migration creates all 5 in one transaction.

Gate: RLS-PATTERN combined migration (supabase/migrations/20260514150238_enable_rls_auto_event_trigger_and_grants_pattern.sql) MUST apply first so the rls_auto_enable() event trigger + grant_standard_public_table_access(regclass) helper exist when this migration runs. Per PLAN.md §8 Wave 1, this is already DONE-S239 (verified S243 — docs/specs/phase-1-kickoff-scoping-s243.md §3).

Validation:

  • Apply migration to staging; assert SELECT count(*) FROM information_schema.tables WHERE table_schema='public' AND table_name = 'product_guide_workspaces' returns 1.
  • Assert column shape: SELECT column_name, data_type, is_nullable, column_default FROM information_schema.columns WHERE table_name='product_guide_workspaces' ORDER BY ordinal_position returns the 4-row shape above (id + workspace_id + created_at + updated_at; no per-app columns).
  • Confirm FK + UNIQUE: SELECT constraint_name, constraint_type FROM information_schema.table_constraints WHERE table_name='product_guide_workspaces' returns the PK + the FK + the UNIQUE on workspace_id.
  • Cascade test: insert a workspace + matching satellite row; delete workspace; assert satellite row count drops to 0.

T-2 — Feature-build ALTER path (implements PRODUCT.md invariant 6 + S-7)

Section titled “T-2 — Feature-build ALTER path (implements PRODUCT.md invariant 6 + S-7)”

Current state: No lib/product_guide/, no app/product_guide/, no feature-spec directory. The product-guide-feature build cycle has not begun.

Target state: When the product-guide feature spec ships, its TECH.md owns a migration of the form:

ALTER TABLE public.product_guide_workspaces
ADD COLUMN <product_guide_specific_col_1> <type> [NULL | NOT NULL] [DEFAULT ...];
-- repeat per per-app column as the feature spec dictates.

This spec does not constrain the column list. The reserved-seat invariant is that the seat shell remains the FK target while column lists evolve per-application — never re-create the table, never DROP TABLE + CREATE TABLE per docs/specs/reserved-workspace-seats/TECH.md T-7 (line 199-201).

Gate: Product-guide feature spec drafting (out of scope for Phase 1). Per CLAUDE.md “Supabase & Schema”: new columns adding PL/pgSQL helper functions need SET search_path = public, extensions + per-function REVOKE EXECUTE ... FROM anon; blocks — feature spec must carry these patterns.

Validation:

  • Per-feature-spec; not validated at Phase 1.
  • v1.1 candidate CI guard per docs/specs/reserved-workspace-seats/TECH.md T-7: extend migration-revoke-guard.yml (or sibling workflow) to lint for CREATE TABLE public.product_guide_workspaces outside the v1 reserved-seats migration file.

T-3 — RLS auto-enable + grants helper (implements PRODUCT.md invariant 2 + S-4 + S-6)

Section titled “T-3 — RLS auto-enable + grants helper (implements PRODUCT.md invariant 2 + S-4 + S-6)”

Current state: Greenfield seat. The auto-RLS event trigger from RLS-PATTERN P-1/T-1 is applied per PLAN.md §8 Wave 1 (DONE-S239); the grants helper from RLS-PATTERN T-2 is available.

Target state: Two things must hold immediately after CREATE TABLE public.product_guide_workspaces returns:

  1. pg_class.relrowsecurity = true for the new table — set by the rls_auto_enable() event trigger firing on the CREATE TABLE command tag per RLS-PATTERN P-1.
  2. The standard 3-role grants (anon SELECT; authenticated full CRUD; service_role full CRUD) are applied via SELECT grant_standard_public_table_access('public.product_guide_workspaces'::regclass); per RWS S-6 + RLS-PATTERN P-2.

Migration order per docs/specs/reserved-workspace-seats/TECH.md T-6 line 180-185:

CREATE TABLE public.product_guide_workspaces (...);
ALTER TABLE public.product_guide_workspaces ENABLE ROW LEVEL SECURITY; -- belt-and-braces per RWS S-4
SELECT grant_standard_public_table_access('public.product_guide_workspaces'::regclass);
-- per-seat RLS policies follow per T-4 below

The explicit ALTER TABLE ... ENABLE ROW LEVEL SECURITY is idempotent against the event-trigger enable, but acts as a fall-back if migration order inverts — per RWS T-4 line 116-126.

Gate: RLS-PATTERN combined migration applied (DONE-S239 — supabase/migrations/20260514150238_enable_rls_auto_event_trigger_and_grants_pattern.sql). No further gate at Phase 1.

Validation:

  • Apply migration to staging; assert SELECT relrowsecurity FROM pg_class WHERE relname = 'product_guide_workspaces' returns true.
  • Assert grants per RWS TECH T-6: SELECT grantee, privilege_type FROM information_schema.role_table_grants WHERE table_name = 'product_guide_workspaces' returns the 3-role pattern (anon SELECT; authenticated SELECT/INSERT/UPDATE/DELETE; service_role SELECT/INSERT/UPDATE/DELETE).
  • Negative-case (per implementation-readiness audit P4 fix): an unprivileged tenant cannot SELECT from product_guide_workspaces for a workspace they do not own — Data API returns 42501 permission denied, not silent empty result.

T-4 — Per-tenant RLS policies (implements S-5)

Section titled “T-4 — Per-tenant RLS policies (implements S-5)”

Current state: Greenfield. Pattern precedent will land on the post-rename procurement_workspaces (per PLAN.md §4.2 T2 sub-task 4) — JOIN-or-EXISTS delegation through workspace_id to the parent workspaces row’s tenant scope.

Target state: The seat carries 4 RLS policies (select, insert, update, delete) delegating to the parent workspaces row per RWS TECH T-5 (lines 141-160). Policy shape (SELECT example):

CREATE POLICY product_guide_workspaces_select
ON public.product_guide_workspaces
FOR SELECT
USING (
EXISTS (
SELECT 1
FROM workspaces w
WHERE w.id = product_guide_workspaces.workspace_id
AND (
-- delegated to workspaces' own RLS USING clause (role-based via get_user_role()
-- per CLAUDE.md "Supabase & Schema"); exact predicate matches workspaces-level pattern
)
)
);

Identical pattern across all 5 reserved seats — 20 policy statements total (5 seats × 4 policies) per RWS TECH T-5 line 163.

Gate: None — workspaces table RLS policies are stable in current production schema.

Validation:

  • Per-seat: connect as authenticated role with tenant A; insert workspace + matching satellite for tenant A; assert satellite visible. Switch to tenant B; assert satellite not visible.
  • Test fixture from procurement seat post-rename will provide the migration test scaffold — copy across the 5 reserved seats per RWS TECH T-5 line 168.

T-5 — Existing-code integration anchor (no Phase 1 binding)

Section titled “T-5 — Existing-code integration anchor (no Phase 1 binding)”

Current state: The repo carries product-guide-adjacent code distinct from this satellite. Integration shape is feature-build scope; this T-5 names the anchors so feature-build planning has the inventory.

File / artefactLine refsWhat it doesIntegration shape
supabase/migrations/20260416102457_pre_squash_reconciliation.sql3804-3813Defines public.guides table with guide_type CHECK column allowing 'product' value (5-value CV: sector, product, company, research, custom)Feature spec resolves whether guide_type CV retires/aliases vs application_types.key discrimination. Content-side vs application-type-side disambiguation.
supabase/migrations/20260422174420_wire_product_guide_sections.sql(S189 WP4)Wires 19 sections per product guide row; populates subtopic_filterOut of Phase 1 scope; section-shape governed by docs/specs/p0-product-guide-section-alignment-spec.md.
supabase/migrations/20260422174117_add_research_feed_to_product_guides.sql(S189 WP5)Adds 20th “Research Feed” section to product guidesSame — content-side; orthogonal to satellite seat.
lib/mcp/tools/guides.ts52-105, 237-283, 356-548, 680MCP tools list_guides, get_guide, create_guide, update_guide; guide_type is a filter parameterFeature spec decides whether product_guide_workspaces rows surface as a separate MCP tool (list_product_guide_workspaces etc.) or whether existing guides.ts tools extend to join through the satellite.
lib/intelligence/guide-generator.ts33-150Auto-generates guide_type='research' guides for intelligence workspaces; sets guide_id on intelligence_workspaces (via workspaces.domain_metadata JSONB per S243 audit)Direct precedent for how a workspace satellite may reference a guides row at feature-build time. The Shape B promotion guide_id is one of two fields the intelligence-workspaces spec ratifies as typed columns (per PLAN.md §4.2 T2 sub-task 8 + S243 Item 12). Product-guide feature spec may follow the same pattern (or differ — feature-spec call).
lib/guide-section-mapping.ts82-139Domain-filtered guide-section lookup; reads guides.domain_filter + guides.is_publishedOut of Phase 1 scope; will integrate at feature-build only if section-aware UX surfaces for product-guide workspaces.
scripts/seed-phew-guides.ts388-390Seeds the live Phew product guide rows (“Advanced Audits Product Guide” etc.)Existing-state evidence — three live guide_type='product' rows exist (Advanced Audits, LMS, Websites) per docs/specs/p0-product-guide-section-alignment-spec.md line 121. Confirms guides content-side coexists with the empty Phase 1 satellite.
docs/ontology/25-application-type.md20-22, 50Names product_guide (label “Product Guide”) as baseline core-provenance application typeDirect cross-reference — the application_types seed row key='product_guide' is what workspaces.application_type_id FKs to; this satellite is its sibling.
docs/specs/p0-product-guide-section-alignment-spec.md(full doc)Pre-launch spec governing content shape of guides/guide_sections rows where guide_type='product'Orthogonal — content-model spec for the guides table; this PRODUCT.md/TECH.md is the workspace-satellite seat. The two integrate at feature-build time but are independent at Phase 1.

Target state: No Phase 1 binding. Per docs/specs/reserved-workspace-seats/TECH.md T-7 line 198, the reserved seat exists as a stable FK target while the feature-build cycle adds typed columns. If the feature-build cycle decides to expose primary_guide_id uuid REFERENCES guides(id) on the satellite (one plausible shape — mirroring intelligence_workspaces.guide_id per S243 Item 12 Shape B promotion), that ALTER lands in the feature TECH.md, not here.

Gate: Feature-spec drafting — owns the integration shape. This anchor table is a roadmap, not a constraint.

Validation:

  • Phase 1 only validates the seat shell (T-1, T-3, T-4). Integration shape validation lands at feature-build.

T-6 — Naming convention frozen (implements S-8)

Section titled “T-6 — Naming convention frozen (implements S-8)”

Current state: Name documented at architecture/04-workspace-types.md §3.2 line 77, docs/ontology/25-application-type.md line 50, and docs/specs/reserved-workspace-seats/PRODUCT.md S-1 + S-8.

Target state: Migration creates the table verbatim as public.product_guide_workspaces — underscore-separated, singular product_guide matching application_types.key='product_guide' per Q-OQR1-113-A.

Gate: None — name is settled. Rename requires separate ratification cycle.

Validation:

  • Migration file diff vs architecture/04-workspace-types.md §3.2 line 77 + PRODUCT.md S-1 name list.

  • Gap flag GF-1 — guides.guide_type='product' vs application_types.key='product_guide' collapse decision (DEFERRED to feature build). The existing 5-value guide_type CV (sector, product, company, research, custom) overlaps in intent with application_types.key for at least two values (productproduct_guide; researchintelligence Phase-1-only research-flow generation; arguably sectorintelligence if sector guides are an intelligence-flow surface). Phase 1 does not resolve this — both CVs coexist. The product-guide feature spec at build time must rule on whether guide_type retires (similar to workspaces.type → workspaces.application_type_id per Q-OQR1-01) or stays as a content-side discriminator. Category (construction-guide §5.2): Ratification needed (product-owner judgement call: collapse vs coexist). Sources checked: supabase/migrations/20260416102457_pre_squash_reconciliation.sql:3804-3813 (5-value CV), docs/ontology/25-application-type.md (product_guide baseline), 0.9-decision-graph.md §11.3 row 1 (Q-OQR1-01 precedent). Prerequisite work: product-guide feature PRODUCT spec ratification on the collapse vs coexist decision. Construction-guide §5.3 format: [STILL-OPEN — gates on product-guide feature spec ratification].

  • Gap flag GF-2 — Backfill for any pre-existing workspaces.application_type_id='product_guide' rows. As of S243, 0 prod workspaces rows carry a product-guide application type (only 4 intelligence rows verified S234 per architecture/04-workspace-types.md §2.2 line 40). If feature-build cycle precedes any product-guide workspace creation, backfill is null; if feature-build cycle happens after some workspaces are created with application_type='product_guide' (e.g. via admin UI v1.1 or migration), the feature TECH.md must include a INSERT INTO product_guide_workspaces (workspace_id) SELECT id FROM workspaces WHERE application_type_id = (SELECT id FROM application_types WHERE key='product_guide') backfill step. Phase 1 does not pre-empt this — feature spec owns. Category (construction-guide §5.2): Tech spec needed (the backfill SQL is a feature-spec implementation detail conditional on sequencing). Sources checked: architecture/04-workspace-types.md §2.2 (4-intel rows / 0-product-guide rows audit), pre-s244-project-feedback.md Item 15 (NEW Phase 1 specs), application_types seed list in T2 sub-task 1. Prerequisite work: product-guide feature TECH spec drafting at feature-build kickoff. Construction-guide §5.3 format: [STILL-OPEN — gates on feature-build sequencing relative to first product-guide workspace creation].

  • GF-3 — MCP tool integration shape for product_guide_workspaces. The existing lib/mcp/tools/guides.ts:52-105 MCP tools (list_guides etc.) operate on guides. Whether the feature build exposes the satellite via a separate list_product_guide_workspaces tool, or extends guides.ts to JOIN through, or surfaces a unified workspace-listing tool that includes satellite columns — open. Category (construction-guide §5.2): Tech spec needed (MCP surface decisions live in TECH territory; the feature TECH spec selects one of the three shapes). Sources checked: lib/mcp/tools/guides.ts:52-105, 237-283, 356-548, 680 (existing surface), 06-mcp-tooling.md (architecture sub-doc surface), product-guide feature spec (not yet drafted). Prerequisite work: product-guide feature TECH spec MCP-surface decision at feature-build kickoff. Construction-guide §5.3 format: [STILL-OPEN — gates on product-guide feature MCP scope decision].


DocWhat it references
./PRODUCT.mdPhase 1 reserved-seat invariants (delegates S-1..S-8 to RWS PRODUCT.md).
docs/specs/reserved-workspace-seats/{PRODUCT,TECH}.mdParent reserved-seat spec; this seat is one of five it covers.
docs/specs/id-38-rls-pattern/{PRODUCT,TECH}.mdRLS auto-enable + grants-helper pattern this seat leverages.
docs/specs/id-31-canonical-pipeline-implementation-plan/PLAN.md §4.2 T2 sub-task 7 + §5 row “product-guide-workspaces” + §8 Wave 0 orderingImplementation sequencing — this spec lands Wave 0; migration lands Wave 2 T2.
docs/plans/phase-0-investigation/architecture/04-workspace-types.md §3.2 + §4.2Pattern substrate; names the satellite verbatim.
docs/ontology/25-application-type.md line 20-22 + 50application_types.key='product_guide' row binding.
docs/specs/p0-product-guide-section-alignment-spec.mdOrthogonal content-model spec for guides.guide_type='product' rows; integration deferred to feature build.
Future docs/specs/product-guide/{PRODUCT,TECH}.md (or equivalent feature-spec path)Owner of per-app column lists + integration shape with guides/guide_sections.
docs/reference/SCHEMA-QUICK-REFERENCE.md §workspacesPost-apply update — add the new satellite row alongside the other 4 reserved seats.

Not applicable — NEW spec. No predecessor.

DocDateStatusUseful for
docs/specs/reserved-workspace-seats/{PRODUCT,TECH}.md15/05/2026 (S240 NEW)[CURRENT-CANONICAL] for the reserved-seat pattern.S-1..S-8 invariants inherited verbatim; T-1..T-8 implementation patterns referenced inline.
docs/plans/phase-0-investigation/architecture/04-workspace-types.md §3.2 + §4.214-15/05/2026 (S239 + S240 ratifications)[CURRENT-CANONICAL] for the satellite pattern + S240 upfront-seats decision + the product_guide baseline application type row.Substrate for T-1 (seat shape) + T-6 (naming).
docs/specs/id-31-canonical-pipeline-implementation-plan/PLAN.md §4.2 + §5 + §818/05/2026 + 20/05/2026 S243 ratifications[CURRENT-CANONICAL] for the Wave 0 spec drafting requirement + Wave 2 migration sequencing.Substrate for the Wave 0 gate identification + T-2 deferral framing.
docs/plans/phase-0-investigation/pre-s244-project-feedback.md Item 1520/05/2026 (S243 interim)[CURRENT-CANONICAL] for the RATIFIED-S243 Item 15 ratification of this NEW spec.Source ratification — the only doc that mandates this spec’s existence.
docs/specs/rls-pattern/{PRODUCT,TECH}.md14/05/2026 (S239 NEW)[CURRENT-CANONICAL] for RLS auto-enable + grants pattern.T-3 leverage.
docs/ontology/25-application-type.md(S235 ratified)[CURRENT-CANONICAL] for product_guide baseline application type row.T-6 cross-ref + GF-1 collapse-decision substrate.
docs/specs/p0-product-guide-section-alignment-spec.md23/04/2026 (S190 draft)[CURRENT-CANONICAL] for guides.guide_type='product' content model — orthogonal to satellite seat.T-5 existing-code anchor; GF-1 substrate.
supabase/migrations/20260416102457_pre_squash_reconciliation.sql lines 3804-3813(live schema)[CURRENT-CANONICAL] for live guides table shape with guide_type CHECK.T-5 existing-code anchor; current-state evidence.
lib/intelligence/guide-generator.ts lines 33-150(live code)[CURRENT-CANONICAL] for the precedent pattern of workspace → guides binding (via intelligence_workspaces).T-5 integration anchor — direct precedent feature-spec may follow.

End of TECH spec. Numbered invariants and behaviour anchors in ./PRODUCT.md.