Skip to content

Show tenant logo in header/sidebar when uploaded#92

Merged
zinkh merged 4 commits into
mainfrom
claude/tenant-logo-header-181tbv
Jul 19, 2026
Merged

Show tenant logo in header/sidebar when uploaded#92
zinkh merged 4 commits into
mainfrom
claude/tenant-logo-header-181tbv

Conversation

@zinkh

@zinkh zinkh commented Jul 19, 2026

Copy link
Copy Markdown
Owner

Adds a BrandLogo component that swaps in the tenant's uploaded
logo (settings.logoUrl), resized to the same height as the default
mark, and falls back to the ArchiOffice SVG mark otherwise.

claude added 4 commits July 19, 2026 07:23
Adds a BrandLogo component that swaps in the tenant's uploaded
logo (settings.logoUrl), resized to the same height as the default
mark, and falls back to the ArchiOffice SVG mark otherwise.
Agents were read-only: buildAgentContext only ever fetched data, and
the chat handler made a single sendMessage call with no tools, so an
agent literally could not write anything back to the cabinet even
when asked to (e.g. adding a new client and drafting their devis).

Adds a new agents.action_scopes column (contacts_write, proposals_write),
separate from the existing read-only context_scopes, that the architect
toggles per agent in AgentConfig. When granted, the chat route registers
matching Gemini function declarations (create_contact, create_proposal)
and loops sendMessage calls to execute chained tool calls — e.g. create
the contact first, then the proposal against the returned client_id —
before returning the final reply, with a confirmation summary of what
was actually created.
…roposals

The previous action_scopes design ('contacts_write', 'proposals_write')
hand-wrote a bespoke Supabase insert per resource in tools.ts — not
scalable to "give agents every action a human has", and already
drifting from server.ts (e.g. it skipped proposals' specialties_list
handling).

Replaces it with a generic, registry-driven system: AGENT_RESOURCES in
types.ts lists every core business resource (projects, tasks,
tenders, invoices, specifications, meetings, contrats_moe, ordres de
service, visas, receptions, reserves, marches_entreprises, notes
d'honoraires, plus contacts/proposals) with its REST path and which of
create/update/delete it supports. Three generic Gemini tools
(create_record/update_record/delete_record) execute by calling the
app's own /api/** routes over an internal loopback, forwarding the
caller's own auth token — so an agent action always runs through the
exact same validation, numbering, and side effects as a human
submitting the same form, with zero duplicated business logic.

AgentConfig now lists all resources as one checkbox each (full CRUD
per resource, mirroring a human's access to that section) with a
"Tout activer" shortcut, and the system prompt lists the authorized
resources and expected fields for the model instead of two hardcoded
capability flags.

Deliberately left out: admin endpoints, billing/checkout, third-party
integration connect/sync (Zoho/Odoo/Ragic/SuperPDP/Chorus Pro), auth,
profile/CV, messaging/feed, file uploads, and the more calculation-heavy
DPGF/situations flows — those stay human-only for now.
Root cause: getUserName() and three notification endpoints filtered
team_members by a `user_id` column that no committed migration ever
created — the live column is `auth_user_id`. Every call failed with
"column team_members.user_id does not exist", which is why POST
/api/contacts (and any other create that logs activity) returned a
500 even though the row had already been inserted successfully.
getUserName() now reads from profiles instead, since team_members is
no longer written to anywhere (POST/PUT /api/team both write to
profiles) — the other three endpoints keep using team_members but
with the corrected column name.

Also hardens the two contact-creation modals (ContactModal.tsx, and
Contacts.tsx's own inline modal + bulk-import mapping modal): they
called raw fetch() instead of apiFetch(), and only surfaced errors via
alert(), which is easy to miss or gets blocked outright in some
embedded/iframe contexts — explaining "no error shown in modal" even
though a request had in fact failed. They now use apiFetch (proper
auth + parsed error messages) and show failures inline in the modal /
via the existing toast, matching the rest of the app.
@zinkh
zinkh merged commit 8971ab3 into main Jul 19, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants