feat(matters): people on a matter, and who wrote which thread - #128
Open
sergiomaldo wants to merge 2 commits into
Open
feat(matters): people on a matter, and who wrote which thread#128sergiomaldo wants to merge 2 commits into
sergiomaldo wants to merge 2 commits into
Conversation
…he legacy project_id filter GET /api/v1/knowledge-bases?project_id= filters on the legacy knowledge_bases.project_id column, while attach/detach (Wave D.1 T3) write the project_knowledge_bases junction table — so a freshly linked KB never appeared in the matter's Knowledge section. Resolve linked KBs from the project's attached_knowledge_base_ids against the full KB list instead. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Backend counterpart: matter membership + `share_scope` over `projects`
(`project_members`, migration 0067) and `GET /api/v1/users/directory`.
Adds a People section to the matter page: the roster, a role picker per
person, a people-picker for adding one, and the matter's share scope. A
lead manages all of it; everyone else sees it read-only.
Screened people (`role='blocked'`) are listed **apart** from the working
team, under their own heading, with a "Lift screen" control. They are not
members with a lesser role — they are the record of an ethical wall, and
mixing them into the roster makes the wall easy to miss. The UI calls
them *Screened* throughout; `blocked` is only ever the wire value.
Chats in a shared matter now carry their author's name. An unattributed
thread is exactly what privilege work cannot afford, and once three
people work one matter, "who ran this" stops being obvious from context.
Names resolve from the roster and fall back to the email.
The matter list gains a chip distinguishing a matter somebody put you on
("Shared") from one nobody had to ("Firm-wide") — different facts, and a
lawyer will want to tell them apart. Keyed on `caller_access_basis`
rather than `owner_id`, so it stays right for a lead who is not the
owner.
Archive is hidden for non-leads, matching the backend, rather than
offering a button that 403s.
Degrades cleanly against an API that predates all of this: the People
section is gated on the roster fetch succeeding, every new matter field
is optional, and the directory round-trip is skipped for anyone who
cannot staff the matter anyway. `activeMatters` is now generic so callers
reading the sharing fields do not lose them to a widening return type.
The new types are declared in `$lib/matters/types` rather than read from
`backend.d.ts`, since those are generated from the pinned `vendor/lq-ai`
sketch; they fold in at the next pin bump.
Test note: the `load` path's positional mocks in `page.server.test.ts`
now document the fetch order at the top of the file, because adding one
request to `load` silently shifts every mock below it — which is how the
three pre-existing KB tests broke while this was being written.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
sergiomaldo
force-pushed
the
feat/matter-team-ui
branch
from
August 21, 2026 14:24
ca224de to
3691792
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Frontend for matter membership. Backend counterpart: LegalQuants/lq-ai#536
(
project_members+share_scope, migration 0067, andGET /api/v1/users/directory).Two commits. The first is a standalone fix —
GET /knowledge-bases?project_id=filters thelegacy
knowledge_bases.project_idcolumn, so junction-attached KBs never appear in a matter'slinked list; it reads them from
attached_knowledge_base_idsinstead. It is here because thePeople work builds on the same
+page.server.tsload path and does not apply without it. Happy tosplit it into its own PR if you'd prefer to review them separately.
Safe to merge ahead of the backend. The People section is gated on the roster fetch succeeding,
every new matter field is optional, and the directory round-trip is skipped for anyone who cannot
staff the matter. Against an API that predates all of this, the page renders exactly as it does
today — there's a test for that.
What it adds
A People section on the matter page: the roster, a role picker per person, a people-picker for
adding one, and the matter's share scope. A lead manages all of it; everyone else sees it read-only.
Screened people are listed apart from the working team, under their own heading, with a "Lift
screen" control. They aren't members with a lesser role — they're the record of an ethical wall, and
folding them into the roster makes the wall easy to miss. The UI calls them Screened throughout;
blockedis only ever the wire value.Chats in a shared matter now carry their author's name. An unattributed thread is exactly what
privilege work cannot afford, and once several people work one matter, "who ran this" stops being
obvious from context. Names resolve from the roster and fall back to the email.
The matter list gains a chip distinguishing a matter somebody put you on ("Shared") from one
nobody had to ("Firm-wide") — different facts, and a lawyer will want to tell them apart. Keyed on
caller_access_basisrather thanowner_id, so it stays right for a lead who isn't the owner.Archive is hidden for non-leads, matching the backend, rather than offering a button that 403s.
Notes for review
$lib/matters/typesrather thanbackend.d.ts, since those are generatedfrom the pinned
vendor/lq-aiOpenAPI sketch; they fold in at the next pin bump.activeMattersis now generic so callers reading the sharing fields don't lose them to a wideningreturn type.
loadpath's positional mocks inpage.server.test.tsnow document the fetch order at thetop of the file. Adding one request to
loadsilently shifts every mock below it — which is howthree pre-existing KB tests broke while this was being written.
Docs
docs/GUIDE.md— a practitioner-facing "People on a matter" section: the four roles, thatfirm-wide means reading, that a screen overrides administrator rights, and the one thing you
can't do (post into a colleague's thread) with the reason.
README.md— "Adding your colleagues", placed where an installer hits it after first login:creating users, the one-time password, roles, and the share-scope default.
Testing
npm run test:unit— 1655 passed / 293 files.npm run lintandsvelte-checkclean. New:TeamSection.svelte.test.ts,SharedChip.svelte.test.ts, and roster/attribution cases inmatters/[id]/page.server.test.ts— including one asserting the page still renders against an APIwithout the membership endpoints.
Also verified by hand against a running deployment: three real logins, a matter shared and then a
colleague screened off it through the UI, with the screen confirmed to deny at the API.
🤖 Generated with Claude Code