feat: user linking, chat persistence, SID resolution, investment roadmap fixes, CI fix #21
No reviewers
Labels
No labels
prio_critical
prio_low
type_bug
type_contact
type_issue
type_lead
type_question
type_story
type_task
No milestone
No project
No assignees
2 participants
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
lhumina_code/hero_biz!21
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "development_casper"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Summary
This branch consolidates several weeks of work across hero_biz_ui: a new contact→user linking feature, a fully persisted chat system with file/voice uploads, end-to-end SID-to-name resolution across list/detail views, a batch of investment roadmap display fixes, CI build repairs, UI description improvements, and documentation cleanup.
What changed
Features
Business overview page descriptions (
feat(ui): add area descriptions and HR section to overview dashboard)Each section card on the overview dashboard now displays a short description of what that area is for (Contacts, Companies, Interactions, Deals, Contracts, Finance, HR, Tasks/Projects). An HR section card has also been added — it was present in the sidebar but missing from the dashboard body. Closes #35.
Contact–user linking (
feat: link contacts to users via user_sid)ContactRecordgains auser_sidfield. The store now wires upIdentityClient(fromhero_osis_sdk) so the link selector can search/load hero_osis identity users. Contacts can be attributed to the user who logged them.Link selector rewrite (
fix: rewrite get_link_selector,fix: remove redundant fields)get_link_selectorwas returning the wrong JSON shape for the frontend JS; rewritten to match.SaveLinksRequesthad stale redundant fields removed.Chat persistence + file/voice uploads (
fix: implement chat persistence and file uploads)Messages are now stored as NDJSON files per
(context_type, context_id)underdata/chats/. File uploads land indata/uploads/. Voice files are auto-transcribed via the AI client when configured.assistant_chatloads the last 10 persisted messages as conversation history so sessions are stateful across page reloads.Fixes
SID-to-name resolution in list/detail views (
fix: resolve entity SIDs to names in list/detail views; preserve link fields on update)Instruments, contracts, transactions, and comments now resolve their foreign-key SIDs (company, person, contract, etc.) into human-readable names at render time. Link fields are no longer clobbered on entity update.
Investment roadmap display bugs (
fix: investment roadmap shows transaction name, currency, and invested companies+fix(hero_biz_ui): fix investment roadmap display and data bugs)Timeline entries now show transaction name, currency, and company names instead of raw IDs. Broken company link fixed. Unused
instrumentsfield removed from the roadmap handler. Template variable references corrected.Form action base_path (
fix: prepend base_path to all form action URLs)All HTML form
action=attributes now prependstate.base_path, fixing broken form submissions when the service is mounted at a non-root prefix through hero_router.HERO_OSIS_URL default (
fix: default HERO_OSIS_URL to hero_router on port 9988)Default shifted from
:9080(direct hero_osis) to:9988(hero_router). Means a vanillahero_biz_uiinstance works without extra config when hero_router is running.CI tag-build fix (
fix(ci): clear stale ALL_FEATURES and guard --features when empty)buildenv.shno longer leavesALL_FEATURESstale across runs.build_lib.shguards the--featuresflag so an empty feature list does not produce a malformed cargo invocation. Fixes issue #14.Cleanup / docs
coding_instructions.mdandcoding_instructions_ai.mdcontent de-duplicated (both were identical).Blockers — what we are waiting on
1.
hero_aibroker_sdkneeds a non-streaming completion method (biggest blocker)hero_biz_uicurrently embeds its ownAiClient(crates/hero_biz_ui/src/ai/client.rs) that makes directreqwestcalls to any OpenAI-compatible endpoint. This bypasseshero_aibrokerentirely — no billing tracking, no model routing, no credit deduction.The correct architecture is for
hero_bizto call through the broker. Thehero_aibroker_sdkcurrently only exposes:StreamingClientthat connects torest.sockand does SSE streamingWhat we need is a non-streaming
/v1/chat/completionswrapper in the SDK sohero_bizcan make simple request/response AI calls through the broker without consuming a stream. Until that lands,hero_bizcalls the upstream AI provider directly and cannot benefit from the broker's model routing or multi-provider fallback.Workaround already in the codebase:
AIBrokerRawClient.call()exists as an escape hatch but requires hand-rolling payloads and is not ergonomic.2. Auth middleware disabled
// TODO: Re-enable auth once backend is complete(handlers/mod.rs:44). The Axum-layer global auth middleware is commented out. Auth is enforced per-handler viaget_session(). The middleware approach would give a blanket guarantee but is blocked on the backend being stable.3.
hero_bizbackend crate is a placeholdercrates/hero_biz/src/main.rslogs"hero_biz backend — placeholder (not yet implemented)". All business logic lives inhero_biz_ui. The backend crate will eventually host the OpenRPC service surface.4. Generic
Store::save()is a no-opservices/mod.rs— the genericStore::save<T>()returnsOk(())without writing (// TODO: Implement save via hero_osis). Entity persistence goes through specific typed methods; the generic path is a stub for a future unified OSIS save layer.Test plan
make build)make test)Every form template was submitting to a bare /c/{context}/... path, so hero_router would try to route the POST to a web_{context} socket instead of the hero_biz/ui.sock. Adding bp (BASE_PATH) prefix to all 12 form actions plus the search form, admin user list/edit, and the admin index link fixes this for all entity types. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>The handler was returning raw LinkSelectorData (flat type→[(sid,name)] map) but the JS expected { entity_name, linkable_types, targets, current_links }. This caused "linkableTypes is undefined" and "entity_name = undefined" in the link selector modal. New response: - entity_name: loaded from the actual entity - linkable_types: per-entity list of which types can be linked - targets: { type: [{id, name}] } populated from real store calls - current_links: { type: [sids] } read from the entity's current fields Covers all 9 linkable entity types (Contact, Deal, Contract, Opportunity, Project, Task, Milestone, Instrument, Transaction) plus Person/Company which show entity_name but have no outgoing links. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>JS sends { links: {...} } but the struct required entity_type and entity_id too — both already available from the URL path params. Axum returned a 422 plain-text error which the JS couldn't parse as JSON, showing "JSON.parse: unexpected character". Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>buildenv.sh listed hero_osis-business/projects/identity as ALL_FEATURES, but none of the workspace crates define those features. The hero_osis_sdk features are already hardcoded as always-on dep features in each crate's Cargo.toml, so no --features flag is needed at build time. - Set ALL_FEATURES="" in buildenv.sh - Remove hard-fail guard on empty ALL_FEATURES in build_lib.sh - Guard --features in build() so the flag is omitted when empty - Guard --features in ci_check() using ${var:+word} expansion #14Person/CRM records are now served at /c/{context}/contacts/* Activity touchpoint records are now served at /c/{context}/interactions/* Rust identifiers, struct names, function names, and field names are unchanged. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>- Fix 10 clippy errors blocking -D warnings: ptr_arg, too_many_arguments, field_reassign_with_default (4x), never_loop, empty_line_after_doc_comment - Convert mut Default::default() + field reassignment to struct initializer syntax for Project, Milestone, Task, and Story saves - Change while-let to if-let in file upload handler (loop never iterated) - Fix PersonDetailTemplate passing "persons" instead of "contacts" to render_source_footer_with_links, causing edit button to link to /persons/{id}/edit - Fix ContactDetailTemplate passing "contacts" instead of "interactions", causing edit button to link to /contacts/{id}/edit on interaction detail pages - Update no_links guard in components.rs to match renamed "contacts" entity type Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>a1c9bb3logging rewrite- axum 0.7 → 0.8 (route syntax :param → {param}, default-features off) - tower 0.4 → 0.5, tower-http 0.5 → 0.6 - axum-extra 0.9 → 0.10 - askama 0.12 + askama_axum 0.4 → askama 0.16 with-axum feature - reqwest 0.12 → 0.13 with rustls-tls - gloo-net 0.6 → 0.7, gloo-timers 0.3 → 0.4 - add rust-version = "1.95.0" to workspace.package - remove buildenv.sh Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>Pull request closed