Adds the load-bearing structural feature of the FlowPilot migration: a
"What we know" panel that holds confirmed facts for a session, fed by AI
[PROMOTE] markers and engineer-added notes. Facts feed the resolution
note preview (Phase 3) and survive across turns via stable UUIDs assigned
to pending_task_lane items.
Backend:
- FactSynthesisService: create/update/soft-delete facts with atomic
state_version bumps; LLM-backed synthesize_from_question/check on the
fact_synthesis (Haiku) action tier per Section 6.6.
- /api/v1/ai-sessions/{id}/facts CRUD + /facts/promote (proposed_text or
via synthesis). PATCH returns 403 for question/diagnostic_check facts
(edit the source item instead, Section 7.3).
- unified_chat_service: [PROMOTE] marker parser (JSON-block per Section
8.1 spec drift note), stable-UUID assignment for pending_task_lane
questions/actions preserved by exact text/label match across turns.
- ASSISTANT_SYSTEM_PROMPT: documents [PROMOTE] format, when to/not to
emit, hallucination guardrails, source_ref handling.
- 17 tests covering parser, stable IDs, service validation, CRUD,
editability rule, both promote modes, 422 null-synthesis path,
state_version invariant.
Frontend:
- src/components/pilot/sections/{WhatWeKnow,WhatWeKnowItem,AddNoteButton}
— green-gradient section above Questions, dashed-circle check, inline
edit/delete gated by the server's editable flag.
- TaskLane gains a whatWeKnowSlot prop (existing assistant/ folder kept
per the doc's "rename is opportunistic" guidance).
- AssistantChatPage fetches facts on selectChat and refetches after each
chat send (so [PROMOTE]-synthesized facts appear immediately); auto-
opens the lane when facts exist.
Verification: end-to-end smoke against the local docker stack confirms
all five endpoints (list/create/patch/delete/promote) plus the 403
editability rule. pytest suite verifies the same with mocked LLM. Live
[PROMOTE] flow remains untested until used in the UI — the marker shape
is covered by parser tests.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
152 lines
6.7 KiB
Python
152 lines
6.7 KiB
Python
from fastapi import APIRouter, Depends
|
|
|
|
from app.api.deps import require_tenant_context
|
|
from app.api.endpoints import (
|
|
admin,
|
|
admin_audit,
|
|
admin_categories,
|
|
admin_dashboard,
|
|
admin_feature_flags,
|
|
admin_gallery,
|
|
admin_plan_limits,
|
|
admin_settings,
|
|
admin_survey,
|
|
ai_builder,
|
|
ai_chat,
|
|
ai_fix,
|
|
ai_sessions,
|
|
ai_suggestions,
|
|
analytics,
|
|
assistant_chat,
|
|
auth,
|
|
beta_feedback,
|
|
beta_signup,
|
|
branding,
|
|
categories,
|
|
copilot,
|
|
device_types,
|
|
feedback,
|
|
flow_proposals,
|
|
flowpilot_analytics,
|
|
folders,
|
|
integrations,
|
|
invite,
|
|
kb_accelerator,
|
|
maintenance_schedules,
|
|
network_diagrams,
|
|
notifications,
|
|
onboarding,
|
|
public_templates,
|
|
ratings,
|
|
scripts,
|
|
script_builder,
|
|
session_branches,
|
|
session_facts,
|
|
session_handoffs,
|
|
session_resolutions,
|
|
sessions,
|
|
shared,
|
|
shares,
|
|
sidebar,
|
|
step_categories,
|
|
steps,
|
|
supporting_data,
|
|
survey,
|
|
tags,
|
|
target_lists,
|
|
tree_markdown,
|
|
tree_transfer,
|
|
trees,
|
|
uploads,
|
|
webhooks,
|
|
accounts,
|
|
)
|
|
|
|
api_router = APIRouter()
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Public / unauthenticated endpoints — no tenant context
|
|
#
|
|
# Note: auth.router contains both public endpoints (register, login,
|
|
# forgot-password, reset-password, email/verify) and authenticated endpoints
|
|
# (GET/PATCH /me, logout, change-password, email/send-verification).
|
|
# The authenticated auth endpoints only query the `users` table, which is
|
|
# excluded from Phase 1 RLS. They work correctly without tenant context
|
|
# in Phase 1. This will need revisiting in Phase 2 when `users` gets RLS.
|
|
# ---------------------------------------------------------------------------
|
|
api_router.include_router(auth.router)
|
|
api_router.include_router(shared.router) # Public share links (no auth)
|
|
api_router.include_router(beta_signup.router)
|
|
api_router.include_router(webhooks.router) # Stripe webhook receiver
|
|
api_router.include_router(public_templates.router) # Public gallery (no auth, rate-limited)
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Admin endpoints — super_admin only
|
|
# admin_categories, admin_gallery, admin_dashboard, admin query Phase 1 RLS
|
|
# tables and MUST use get_admin_db (migrated in Task 8). The remaining admin
|
|
# endpoints (admin_audit, admin_plan_limits, admin_feature_flags,
|
|
# admin_settings, admin_survey) are safe until Phase 2 extends RLS.
|
|
# ---------------------------------------------------------------------------
|
|
api_router.include_router(admin.router)
|
|
api_router.include_router(admin_dashboard.router)
|
|
api_router.include_router(admin_audit.router)
|
|
api_router.include_router(admin_plan_limits.router)
|
|
api_router.include_router(admin_feature_flags.router)
|
|
api_router.include_router(admin_settings.router)
|
|
api_router.include_router(admin_categories.router)
|
|
api_router.include_router(admin_survey.router)
|
|
api_router.include_router(admin_gallery.router)
|
|
# ---------------------------------------------------------------------------
|
|
# User-facing endpoints — tenant context required
|
|
# ---------------------------------------------------------------------------
|
|
_tenant_deps = [Depends(require_tenant_context)]
|
|
|
|
api_router.include_router(trees.router, dependencies=_tenant_deps)
|
|
api_router.include_router(sidebar.router, dependencies=_tenant_deps)
|
|
api_router.include_router(sessions.router, dependencies=_tenant_deps)
|
|
api_router.include_router(invite.router, dependencies=_tenant_deps)
|
|
api_router.include_router(categories.router, dependencies=_tenant_deps)
|
|
api_router.include_router(tags.router, dependencies=_tenant_deps)
|
|
api_router.include_router(folders.router, dependencies=_tenant_deps)
|
|
api_router.include_router(step_categories.router, dependencies=_tenant_deps)
|
|
api_router.include_router(steps.router, dependencies=_tenant_deps)
|
|
api_router.include_router(accounts.router, dependencies=_tenant_deps)
|
|
api_router.include_router(shares.router, dependencies=_tenant_deps)
|
|
api_router.include_router(tree_markdown.router, dependencies=_tenant_deps)
|
|
api_router.include_router(ratings.router, dependencies=_tenant_deps)
|
|
api_router.include_router(analytics.router, dependencies=_tenant_deps)
|
|
api_router.include_router(target_lists.router, dependencies=_tenant_deps)
|
|
api_router.include_router(maintenance_schedules.router, dependencies=_tenant_deps)
|
|
api_router.include_router(feedback.router, dependencies=_tenant_deps)
|
|
api_router.include_router(ai_builder.router, dependencies=_tenant_deps)
|
|
api_router.include_router(ai_fix.router, dependencies=_tenant_deps)
|
|
api_router.include_router(ai_chat.router, dependencies=_tenant_deps)
|
|
api_router.include_router(copilot.router, dependencies=_tenant_deps)
|
|
api_router.include_router(assistant_chat.router, dependencies=_tenant_deps)
|
|
api_router.include_router(survey.router, dependencies=_tenant_deps)
|
|
api_router.include_router(tree_transfer.router, dependencies=_tenant_deps)
|
|
api_router.include_router(ai_suggestions.router, dependencies=_tenant_deps)
|
|
api_router.include_router(kb_accelerator.router, dependencies=_tenant_deps)
|
|
api_router.include_router(scripts.router, dependencies=_tenant_deps)
|
|
api_router.include_router(integrations.router, dependencies=_tenant_deps)
|
|
api_router.include_router(onboarding.router, dependencies=_tenant_deps)
|
|
api_router.include_router(branding.router, dependencies=_tenant_deps)
|
|
api_router.include_router(supporting_data.router, dependencies=_tenant_deps)
|
|
api_router.include_router(network_diagrams.router, dependencies=_tenant_deps)
|
|
# session_handoffs queue router must come before ai_sessions to avoid conflict
|
|
api_router.include_router(session_handoffs.queue_router, dependencies=_tenant_deps)
|
|
api_router.include_router(session_resolutions.router, dependencies=_tenant_deps)
|
|
# session_facts mounts under /ai-sessions/{id}/facts — register before ai_sessions
|
|
# so the {session_id}/facts subpaths take precedence over any future generic catchalls.
|
|
api_router.include_router(session_facts.router, dependencies=_tenant_deps)
|
|
api_router.include_router(ai_sessions.router, dependencies=_tenant_deps)
|
|
api_router.include_router(flow_proposals.router, dependencies=_tenant_deps)
|
|
api_router.include_router(flowpilot_analytics.router, dependencies=_tenant_deps)
|
|
api_router.include_router(notifications.router, dependencies=_tenant_deps)
|
|
api_router.include_router(uploads.router, dependencies=_tenant_deps)
|
|
api_router.include_router(script_builder.router, dependencies=_tenant_deps)
|
|
api_router.include_router(beta_feedback.router, dependencies=_tenant_deps)
|
|
api_router.include_router(session_branches.router, dependencies=_tenant_deps)
|
|
api_router.include_router(session_handoffs.router, dependencies=_tenant_deps)
|
|
api_router.include_router(device_types.router, dependencies=_tenant_deps)
|