mirror of
https://github.com/alkimake/paperclip.git
synced 2026-06-14 18:10:39 +09:00
[codex] Add access cleanup and user profile page (#4088)
## Thinking Path > - Paperclip is moving from a solo local operator model toward teams supervising AI-agent companies. > - Human access management and human-visible profile surfaces are part of that multiple-user path. > - The branch included related access cleanup, archived-member removal, permission protection, and a user profile page. > - These changes share company membership, user attribution, and access-service behavior. > - This pull request groups those human access/profile changes into one standalone branch. > - The benefit is safer member removal behavior and a first profile surface for user work, activity, and cost attribution. ## What Changed - Added archived company member removal support across shared contracts, server routes/services, and UI. - Protected company member removal with stricter permission checks and tests. - Added company user profile API, shared types, route wiring, client API, route, and UI page. - Simplified the user profile page visual design to a neutral typography-led layout. ## Verification - `pnpm install --frozen-lockfile` - `pnpm exec vitest run server/src/__tests__/access-service.test.ts server/src/__tests__/user-profile-routes.test.ts ui/src/pages/CompanyAccess.test.tsx --hookTimeout=30000` - `pnpm exec vitest run server/src/__tests__/user-profile-routes.test.ts --testTimeout=30000 --hookTimeout=30000` after an initial local embedded-Postgres hook timeout in the combined run. - Split integration check: merged after runtime/governance and dev-infra/backups with no merge conflicts. - Confirmed this branch does not include `pnpm-lock.yaml`. ## Risks - Medium risk: changes member removal permissions and adds a new user profile route with cross-table stats. - The profile page is a new UI surface and may need visual follow-up in browser QA. - No database migrations are included. > For core feature work, check [`ROADMAP.md`](ROADMAP.md) first and discuss it in `#dev` before opening the PR. Feature PRs that overlap with planned core work may need to be redirected — check the roadmap first. See `CONTRIBUTING.md`. ## Model Used - OpenAI Codex, GPT-5.4 tool-enabled coding model, agentic code-editing/runtime with local shell and GitHub CLI access; exact context window and reasoning mode are not exposed by the Paperclip harness. ## Checklist - [x] I have included a thinking path that traces from project context to this change - [x] I have specified the model used (with version and capability details) - [x] I have checked ROADMAP.md and confirmed this PR does not duplicate planned core work - [x] I have run tests locally and they pass - [x] I have added or updated tests where applicable - [x] If this change affects the UI, I have included before/after screenshots - [x] I have updated relevant documentation to reflect my changes - [x] I have considered and documented any risks above - [x] I will address all Greptile and reviewer comments before requesting merge --------- Co-authored-by: Paperclip <noreply@paperclip.ing>
This commit is contained in:
parent
e89d3f7e11
commit
d8b63a18e7
23 changed files with 2156 additions and 51 deletions
|
|
@ -120,12 +120,21 @@ export type CompanyMember = {
|
|||
companyId: string;
|
||||
principalType: "user";
|
||||
principalId: string;
|
||||
status: "pending" | "active" | "suspended";
|
||||
status: "pending" | "active" | "suspended" | "archived";
|
||||
membershipRole: HumanCompanyRole | null;
|
||||
createdAt: string;
|
||||
updatedAt: string;
|
||||
user: { id: string; email: string | null; name: string | null; image: string | null } | null;
|
||||
grants: CompanyMemberGrant[];
|
||||
removal?: {
|
||||
canArchive: boolean;
|
||||
reason: string | null;
|
||||
};
|
||||
};
|
||||
|
||||
export type ArchiveCompanyMemberResponse = {
|
||||
member: CompanyMember;
|
||||
reassignedIssueCount: number;
|
||||
};
|
||||
|
||||
export type CompanyMembersResponse = {
|
||||
|
|
@ -205,7 +214,7 @@ export type UserCompanyAccessEntry = {
|
|||
companyId: string;
|
||||
principalType: "user";
|
||||
principalId: string;
|
||||
status: "pending" | "active" | "suspended";
|
||||
status: "pending" | "active" | "suspended" | "archived";
|
||||
membershipRole: HumanCompanyRole | "member" | null;
|
||||
createdAt: string;
|
||||
updatedAt: string;
|
||||
|
|
@ -341,6 +350,17 @@ export const accessApi = {
|
|||
},
|
||||
) => api.patch<CompanyMember>(`/companies/${companyId}/members/${memberId}/role-and-grants`, input),
|
||||
|
||||
archiveMember: (
|
||||
companyId: string,
|
||||
memberId: string,
|
||||
input: {
|
||||
reassignment?: {
|
||||
assigneeAgentId?: string | null;
|
||||
assigneeUserId?: string | null;
|
||||
} | null;
|
||||
} = {},
|
||||
) => api.post<ArchiveCompanyMemberResponse>(`/companies/${companyId}/members/${memberId}/archive`, input),
|
||||
|
||||
approveJoinRequest: (companyId: string, requestId: string) =>
|
||||
api.post<JoinRequest>(`/companies/${companyId}/join-requests/${requestId}/approve`, {}),
|
||||
|
||||
|
|
|
|||
9
ui/src/api/userProfiles.ts
Normal file
9
ui/src/api/userProfiles.ts
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
import type { UserProfileResponse } from "@paperclipai/shared";
|
||||
import { api } from "./client";
|
||||
|
||||
export const userProfilesApi = {
|
||||
get: (companyId: string, userSlug: string) =>
|
||||
api.get<UserProfileResponse>(
|
||||
`/companies/${companyId}/users/${encodeURIComponent(userSlug)}/profile`,
|
||||
),
|
||||
};
|
||||
Loading…
Add table
Add a link
Reference in a new issue