admin / Apex
publicBid Management and Orchestration Tool with AI Capability
Apex / Synapse-Apexv2 / DECISIONS.md
13349 B · main
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 | # Build decisions (v1) Where the blueprint left a judgement call, the simplest option consistent with the acceptance criteria was chosen. Notable decisions: - **Schema management:** v1 creates tables via `Base.metadata.create_all` on startup plus a seed routine, rather than Alembic migrations. This keeps `docker compose up` a one-command boot. **Follow-up:** add Alembic and generate an initial migration before any production use / schema change. - **Async work:** document parsing and all AI calls run on Celery (Redis broker), as specified. The UI dispatches jobs and polls by refreshing; a dedicated progress endpoint / SSE is a follow-up (blueprint §7 batching note). - **AI graceful degradation:** with no `ANTHROPIC_API_KEY`, extraction/generation return labelled placeholders so the full workflow is demoable offline (blueprint §10). - **AI model usage:** default `claude-opus-4-8`, adaptive thinking + `effort: high`, streaming for long-form generation, no `budget_tokens`/sampling params. Structured extraction currently uses a strict-JSON prompt + parse rather than `messages.parse()` with Pydantic tool schemas — a straightforward hardening follow-up. - **Document input to the model:** v1 extracts text server-side (pypdf/python-docx/ openpyxl) and passes text. Native PDF document blocks / Files API upload is a follow-up for higher-fidelity extraction on complex PDFs. - **Capability grounding in Module 2:** responses are grounded by passing approved capabilities into the prompt (first 12 by simple selection). A keyword/embedding retrieval step is a follow-up for large libraries. - **Cost-of-bid rate:** production cost on the dashboard uses a blended internal rate (£45/hr) for v1; wiring it to each allocated resource's cost rate is a follow-up. - **User deletion:** soft delete (deactivate); anonymisation-on-request is a follow-up. Audit entries are retained. - **Rate versioning:** rate changes are stored on the resource type; per-bid rate snapshots exist on cost lines (`rate_snapshot`) and team members. A full effective-dated `rate_versions` child table is a follow-up. - **Money:** all cost/pricing maths use `Decimal`; DB columns are `Numeric`. Unit tested in `backend/tests/test_costing.py`. - **Exports:** DOCX (main response), XLSX (cost + pricing), PDF (summary). The internal bid-production-cost page is intentionally excluded from the client-facing DOCX. ## v1.1 feature additions (2026-07-07) - **Opportunity fields:** `opportunity_value`, `contract_duration_months`, `web_link` added to the bid (create form + editable Overview; web link is click-through). - **Frameworks:** full add/amend/delete in the admin panel. - **Resources:** add/amend/delete plus an **hourly⇄daily rate basis toggle** — editing one basis rederives the other (×/÷8); both are stored so the cost engine and displays stay consistent. Delete is a soft-delete (hidden from selection; existing bid snapshots unaffected). - **Non-people resource costs:** user-entered cost lines (`group="non_people"`) held in `cost_sheet.inputs.non_people` and re-materialised on every recalculation, so engine rebuilds never wipe them. - **Gantt chart:** auto-rendered from plan tasks (inline SVG component), milestones as diamonds, tasks as bars, today marker, colour by status. Uses the product's indigo/gold design system rather than a generic charting palette for visual consistency. - **Response editing & word limits:** responses remain editable inline; a per-requirement `word_limit` shows a live word count that flags over-limit, and the limit is passed to the AI as a hard constraint during generation. - **Per-bid audit trail:** added `audit_log.bid_id`; bid-scoped actions now stamp it, and each bid's **Activity** tab shows exactly which login did what and when. - **Clickable workflow bar:** the lifecycle is rendered as coloured rounded boxes (completed=green, current=indigo, actionable=gold-outlined) that advance the bid on click, gated to Bid Manager/Approver; terminal outcomes (won/lost/withdrawn) appear at submission. - **Guides:** `docs/USER_GUIDE.md` and `docs/ADMIN_GUIDE.md` added. > **Schema note:** these additions introduce new columns (`bids.opportunity_value/…`, > `bid_requirements.word_limit`, `audit_log.bid_id`). Because v1 still uses > `create_all` rather than Alembic, an **existing** database won't gain the columns > automatically — run `docker compose down -v` (destroys data) then `up` on an already > deployed instance, or apply the columns manually. A fresh deployment is unaffected. > Alembic remains the planned follow-up. ## v1.2 feature additions (2026-07-07) - **Licence cost CRUD:** full add/amend/delete in the admin Resources panel (backend endpoints already existed; this wired the UI). Deletes are soft (hidden from selection). - **AI Integration (Assistant) toggle at admin level:** a `SystemSetting` (`ai_assistant`) gates a new **advisory** tool, kept entirely separate from the existing extraction/generation pipeline (which is unchanged and still gated only by the API key). Exposed to clients via `/api/config.assistant_admin_enabled`. - **Per-bid Assistant:** `bids.assistant_enabled` toggled from the workspace Assistant tab (Bid Manager). Turning it on requires the admin toggle to be on first (enforced server-side). The Assistant: - gives **bid-level advice** and **per-response enhancements**, grounded only in in-app data (approved capabilities, requirements, win themes, word limits); - runs a **hallucination self-check** — the model drafts, then audits its own draft against the supplied evidence and removes unsupported claims; the removed claims and a `guardrail` object (`checked`, `removed`, `clean`, `claims`) are surfaced as a guard-rail badge in the UI; - is **advisory only** — an enhancement is written to the response **exclusively via a human "Approve & apply"** action (`assistant_suggestion_applied`); suggestions can be dismissed; the whole lifecycle is persisted (`assistant_suggestions` table) and every step is written to the per-bid **audit trail** with the acting login. - **Graceful degradation:** with no API key the Assistant still creates suggestions but marks `guardrail.checked = false` and returns a labelled placeholder, so the flow is demoable offline (consistent with the rest of the app). > **Schema note:** adds `bids.assistant_enabled` and a new `assistant_suggestions` > table. As with earlier versions (no Alembic yet), an **existing** database needs > `docker compose down -v` then `up` to pick up the new column; the new table is created > automatically. Fresh deployments are unaffected. ## v1.3 feature additions (2026-07-07) - **Framework active toggle:** frameworks can be switched on/off (existing `active` column + PATCH). Inactive frameworks are hidden from bid selection and from the Assistant's alignment, without deletion. - **Assistant framework alignment:** a new `framework_align` assistant action that advises how to better map a response to the bid's *active* frameworks (control references, terminology, evidence), self-checked for hallucinations and applied only on human approval — same lifecycle as response enhancement. Rejected (400) when the bid has no active frameworks. - **Dynamic thought cloud:** the Assistant surfaces its latest proposed suggestion in a floating, animated thought-cloud (`components/AssistantCloud.tsx`) anchored to a ✦ floating button. It polls per-bid suggestions while the Assistant is active. - **Ping + mute:** a short two-tone ping (Web Audio oscillator — no asset file, avoids CSP/bundle concerns) plays when the cloud appears. A user-level mute toggle on the cloud persists to `localStorage` (`apex_assistant_sound`). - **Acknowledge / reappear / summon:** the cloud disappears when acknowledged (*Got it*), with acknowledged suggestion ids persisted per-bid in `localStorage` (`apex_ack_<bidId>`) so the same idea doesn't re-pop. It reappears only when a **new** proposed suggestion arrives or when the user **summons** it via the ✦ button (summoning an empty queue triggers fresh bid-level advice). - **Verified live in-browser** (Vite dev + uvicorn/SQLite): cloud auto-pops on entering a bid with a pending suggestion, guard-rail badge renders ("✓ Hallucination self-check — N removed"), acknowledge hides + persists, summon re-shows, mute toggles + persists, and Approve & apply writes the enhancement to the response and audits it — no console errors. ## v1.4 feature additions (2026-07-07) - **Effort rules — full CRUD UI + access:** effort-rule add/amend/delete is available to **Administrator, Bid Manager and Finance** (Bid Manager added this version; Finance retained). The admin Effort-rules panel, previously read-only, gained a full editor: add form (trigger / endpoint type / per-qty / resource / recurring & one-off hours), inline amend, and delete. The tab is shown to those three roles. All create/amend/delete actions are audited against the acting login. The CRUD + RBAC pattern was verified E2E (a non-admin role performs full CRUD, an excluded role gets 403, actions audited). ## v1.5 fixes (2026-07-08) - **Root-cause fix — AI SDK version:** `anthropic` was pinned to `0.42.0`, which predates adaptive thinking and `output_config`. With a real key, every AI call passed `thinking={"type":"adaptive"}` / `output_config={"effort":...}` that the old SDK rejected with `TypeError`, and the error was swallowed → "the Assistant does nothing." Bumped to **`anthropic==0.116.0`** (verified: it accepts the streaming + adaptive thinking + effort call shape; a fake key now yields an `AuthenticationError`, not a `TypeError`). **Requires an image rebuild:** `docker compose build backend worker && docker compose up -d`. - **Live AI status endpoint:** `GET /api/ai/status` performs a minimal real call (cached ~60s) and returns `connected` / `disabled` / `error` with a classified detail (invalid key, model not found, cannot reach API, rate limited, …). - **Obvious dashboard indicator:** a colour-coded pill in the dashboard header — green "AI connected & working", grey "AI not configured", red "AI error" — with the model name and detail on hover; click to re-check. - **No more silent failures:** the Assistant thought-cloud now shows a "Thinking…" state while working and surfaces errors (previously `catch {}` swallowed them); the Responses-tab ✦ actions show an immediate "working…" message and report errors. - **Snappier Assistant:** assistant advisory calls now run at `medium` effort (was `high`) for lower latency; extraction/generation stay at `high`. ## v2.0 — Answer Library MVP (2026-07-08, Synapse-Apexv2) New module: a searchable catalogue of tender questions & responses (blueprint: `docs/ANSWER_LIBRARY_BLUEPRINT.md`). Implemented the MVP: - **Model:** `answer_entries` (question/answer/summary/category/tags/frameworks, provenance source_type/source_bid_id/source_response_id, client, outcome, status, is_master, reuse_count, word_count) + `answer_reuse_log`. - **Fills itself:** `update_response` harvests on **approval** (upsert keyed by `source_response_id`); `change_state` propagates **won/lost** outcome onto that bid's entries. Admin/BM **Harvest approved** backfills existing approved responses (idempotent). - **Search (MVP):** DB-agnostic ILIKE + Python filter/rank (master → won → reuse → recency), filters by category/client/outcome/framework, `/facets` for dropdowns. **Deliberately not** Postgres FTS/pgvector yet — keeps it portable and testable on SQLite; semantic search is the documented Phase-2 step (Anthropic has no embeddings API). - **Curation:** manual add, edit, mark master, archive; reuse logging + full audit. - **Frontend:** left-nav **Answer Library** page (search/filters/Q&A cards/detail modal/ add/master/archive/copy) + **"Find in Answer Library"** on the Responses tab that inserts a proven answer into a draft and logs the reuse. - **RBAC:** all roles search/view/copy; Bid Manager + Contributor curate; Admin + Bid Manager backfill. - **Verified:** frontend build clean; E2E green (auto-harvest, keyword/framework search, won propagation, reuse+audit, master ranking, manual add, archive, idempotent backfill); unit tests 7/7. Guides updated + PDFs regenerated. > **Schema note:** new tables `answer_entries` + `answer_reuse_log` are created > automatically by `create_all`. A fresh v2 deployment needs nothing special. ## Build phase coverage vs blueprint §11 - Phase 1 (foundation, auth, RBAC, MFA, audit, shell): **complete** - Phase 2 (Module 5 + admin data, frameworks, effort rules, workflow view): **complete** - Phase 3 (Module 1 capability library): **complete** - Phase 4 (bids + Module 2, requirement gate, plan, responses): **complete** - Phase 5 (Modules 3 & 4, cost + pricing waterfall + AI justification): **complete** - Phase 6 (Module 6 package assembly, approve/request-changes, exports, state machine): **complete** - Phase 7 (polish: dashboard tiles/filters, seed demo data, AI usage reporting): **partial** — tiles and seed are in; richer AI-usage reporting and notifications are follow-ups. |