This commit is contained in:
j3d1 2026-08-20 05:04:30 +02:00
parent c345372382
commit 395a9b156a
9 changed files with 1434 additions and 0 deletions

View file

@ -0,0 +1,113 @@
# Groups MVP (Design in Progress)
Status: not implemented. [groups.md](groups.md) works out the underlying model (what a group is,
how "acting as a group" is authenticated across federation). This document doesn't re-derive any
of that; it takes that design as given and asks a narrower question: what is the smallest set of
screens and actions that makes groups usable, reusing the UI patterns Toolshed already has for
friends and inventory rather than inventing new ones.
## Goals
- Ship something a user can actually click through: create a group, add/remove members, and have
the group own items, end to end.
- Reuse existing screens and interaction patterns wherever the shape already matches, instead of
designing new ones (see below).
- Leave every deferred piece as an explicit non-goal rather than a silent gap, so it's clear what
MVP does and doesn't cover.
## Non-goals (for now)
- **Group-to-group friending, and letting outside users friend a group.** groups.md's model
supports both, but the only audience for a group's items in MVP is the group's own members;
"private" already covers that (see "Availability policy for group items" below). Extending
visibility to non-members via the group's own friends list is real, valuable, and deferred as a
fast-follow, not designed here.
- **Transferring an existing personally-owned item's ownership to a group.** MVP only supports
creating a *new* item directly owned by a group. Moving an already-existing item across owners is
a separate piece of work (ownership transfer isn't something Toolshed supports for user-to-user
either today).
- **Deleting a group.** MVP has no explicit "delete this group" action. A group's lifecycle is just
"created, membership changes over time"; the orphaning guard (a group can't be left with zero
members, see groups.md's Known Gaps) means a group that's no longer wanted just sits unused rather
than needing a teardown flow.
- **Any governance, roles, or per-item permissions.** Same non-goal as groups.md: every member has
equal, full privileges over the group and everything it owns.
## User-facing features
### Creating a group
A new "Groups" section, entry point styled like Inventory's "Add" button. The form is just a name;
the handle (`#name@yourdomain`) is derived from it the same way a username becomes part of a user's
handle. The creator becomes the group's first member automatically — there's no empty-group state
to design for.
### My Groups list
A "Groups" nav entry/page, modeled directly on `Friends.vue`: a table of groups the current user is
a member of (name/handle, member count), each row linking into that group's detail page. No
separate "discover groups you're not in" browsing for MVP — you land in a group by being added to
it, the same way you become friends with someone by request/accept, not by browsing a directory of
all users.
Known limitation: this list only ever queries the member's own home backend, so it only shows
groups actually hosted there (groups you created, or joined on your own domain). Membership itself
works regardless of which backend hosts the group — a remote member can still be invited, accept,
and fully edit/delete the group's items (see "Owning items as a group" below) — but a group hosted
on someone else's backend won't show up in your own "My Groups" list, because unlike friendship
(which both sides record), group membership is only ever recorded on the group's own home backend,
and there's no index anywhere of "which other backends has this identity been added to." Making a
remote membership discoverable would need a small personal pointer index (written by the client at
join time) plus a handle-based group lookup on the group's own backend; deferred as a fast-follow
alongside group-friending.
### Group detail page
One page per group, with two sections, each reusing an existing pattern wholesale:
- **Members** — the add/remove-row pattern from `Friends.vue`'s friend list: an inline "add member"
field (enter a handle, `user@domain`), and a remove (trash icon) action per row. Any member can
add or remove any other member — flat privilege, no confirmation step beyond the orphaning guard
(removing the group's last member is blocked, with an error explaining why, rather than silently
emptying the group).
- **Group inventory** — the exact table/grid pattern from `Inventory.vue` (Name, Availability
Policy, Amount, Edit/Delete), scoped to items owned by this group, with the same "Add" button
leading into the existing item-creation form (see below).
A "Leave group" action removes the current user from Members; if they're the last member, it's
blocked by the same orphaning guard.
### Owning items as a group
The existing item create/edit form (`InventoryNew.vue` / `InventoryEdit.vue`) gets one new field:
an "Owner" selector, defaulting to "Myself," with the groups you belong to as the other options.
Every other field on that form (tags, properties, availability policy, storage location, quantity)
is unchanged, and a group-owned item behaves exactly like a personally-owned one everywhere else in
the app (edit, delete, detail view) — any member can edit or delete it, the same way the owner can
today.
### Where group-owned items show up
The main "Inventory" page stays scoped to items you personally own, unchanged from today. A group's
items are visible and managed in exactly one place: that group's detail page. This keeps "my
inventory" meaning one thing (what I personally own) and avoids merging two different item lists
with different edit semantics into one view for MVP.
### Availability policy for group items
The item form's existing Availability Policy field (private/share/lend/rent/sell) is unchanged and
applies to group-owned items the same way it does today. Since group-friending is out of scope for
MVP (see Non-goals), "share/lend/rent/sell" have no wider audience to expand to yet, only "private"
is fully meaningful right now — a private group item is visible to and editable by every group
member, which is already the core value the Problem statement in groups.md is after (a shared
workshop's members all having a say over shared equipment). The field stays as-is rather than being
trimmed down to just "private," so nothing needs to change on it once group-friending ships.
## Open scoping call
Deferring group-friending is the one judgment call in this document worth flagging explicitly:
it means an MVP group can't yet share an item with anyone outside its own membership, which is a
real limitation, not just a simplification. It was scoped out because it pulls in a second piece of
UI (a group's own Friends tab, and "who can accept a friend request on the group's behalf") that
isn't needed for the core "shared ownership among members" use case to work end to end. Worth
confirming this is the right line before building against it.