---
phase: 05-project-user-management
plan: 03
type: execute
---

<objective>
Implement member management API methods and CLI commands to add, remove, and list project members with role support.

Purpose: Complete the project/user/member management suite, enabling full control of project membership from the terminal.
Output: Member management methods in ProjectsResource and complete `n8n member` command group.
</objective>

<execution_context>
~/.claude/get-shit-done/workflows/execute-phase.md
./summary.md
~/.claude/get-shit-done/references/tdd.md
</execution_context>

<context>
@.planning/PROJECT.md
@.planning/ROADMAP.md
@.planning/STATE.md
@.planning/phases/05-project-user-management/05-01-SUMMARY.md
@.planning/phases/05-project-user-management/05-02-SUMMARY.md
@REQUIREMENTS.md
@src/n8n_cli/client/resources/projects.py
@src/n8n_cli/client/resources/users.py
@src/n8n_cli/commands/project.py
@src/n8n_cli/commands/user.py
@tests/test_projects_resource.py
@tests/commands/test_project.py
</context>

<tasks>

<task type="auto" tdd="true">
  <name>Add member management methods to ProjectsResource</name>
  <files>src/n8n_cli/client/resources/projects.py, tests/test_projects_resource.py</files>
  <test-first>
    Test: ProjectsResource.list_project_members(project_id) returns list of member dicts with userId, email, role
    Test: ProjectsResource.add_project_member(project_id, user_id, role) succeeds
    Test: ProjectsResource.remove_project_member(project_id, user_id) succeeds
    Cases:
    - list_project_members extracts from project.relations
    - add_project_member with valid role (editor, admin)
    - remove_project_member with valid user_id
    - Error handling: NotFoundError, ValidationError
    - Retry behavior on transient errors
  </test-first>
  <action>
    Add three methods to ProjectsResource class:

    **list_project_members(project_id: str) -> list[dict]:**
    - Call self.get(project_id) to fetch project
    - Extract members from project relations: project.relations.projectRelations if present
    - Each relation has: userId, role, email (may need to map from relations structure)
    - Return list of dicts: [{"userId": "...", "email": "...", "role": "..."}]
    - If no relations or empty: return empty list []
    - Note: REQUIREMENTS.md says "extracted from project relations" - the n8n API returns project members as part of project.relations

    **add_project_member(project_id: str, user_id: str, role: str) -> None:**
    - POST /api/v1/projects/{project_id}/members with {"userId": user_id, "role": role}
    - Use @retry decorator with exponential backoff
    - Retry on httpx.HTTPError, ConnectionError, ServerError
    - Use handle_response() for error mapping
    - Return None on success

    **remove_project_member(project_id: str, user_id: str) -> None:**
    - DELETE /api/v1/projects/{project_id}/members/{user_id}
    - Use @retry decorator with exponential backoff
    - Use handle_response() for error mapping
    - Return None on success

    Add comprehensive tests (new test class TestProjectMembers):
    - test_list_project_members_success (with members)
    - test_list_project_members_empty (no relations)
    - test_add_project_member_success
    - test_add_project_member_invalid_role (ValidationError)
    - test_remove_project_member_success
    - test_remove_project_member_not_found (NotFoundError)
    - test_retry_behavior for add/remove methods
  </action>
  <verify>pytest tests/test_projects_resource.py -v passes, mypy passes</verify>
  <done>ProjectsResource has list_project_members, add_project_member, remove_project_member methods with 100% test coverage</done>
</task>

<task type="auto">
  <name>Implement member list, member add, and member remove commands</name>
  <files>src/n8n_cli/commands/member.py, tests/commands/test_member.py, src/n8n_cli/cli.py</files>
  <action>
    Create src/n8n_cli/commands/member.py following user.py pattern:

    **member list command:**
    - `n8n member list <project> [-v]`
    - Resolve project name to ID using client.projects.find_by_name(project)
    - Call client.projects.list_project_members(project_id)
    - Output: Email and role in columns
    - Format: "user@example.com    editor" or "other@example.com    admin"
    - With -v: Add user ID column
    - If no members: "No members found for project: {project_name}"

    **member add command:**
    - `n8n member add <project> <email> [--role editor|admin] [-v]`
    - Default role: editor
    - Resolve project name to ID using client.projects.find_by_name(project)
    - Resolve email to user ID using client.users.find_by_email(email)
    - If user not found: "User not found: {email}. Invite user first with: n8n user invite {email}", exit 1
    - Call client.projects.add_project_member(project_id, user_id, role)
    - Output: "Added {email} to {project_name} as {role}"
    - With -v: Show user ID and project ID

    **member remove command:**
    - `n8n member remove <project> <email> [-v]`
    - Resolve project name to ID
    - Resolve email to user ID
    - Call client.projects.remove_project_member(project_id, user_id)
    - Output: "Removed {email} from {project_name}"
    - No confirmation prompt (unlike user remove) - members can be re-added easily

    **Error handling:**
    - Use `from None` for clean CLI errors
    - Handle NotFoundError for project/user not found
    - Friendly messages: "Project not found: {name}", "User not found: {email}"
    - Validate config before API calls

    **CLI registration:**
    - Update src/n8n_cli/cli.py to add member_group command group

    Write comprehensive tests:
    - test_member_list_success (with members)
    - test_member_list_empty
    - test_member_list_project_not_found
    - test_member_add_success (default role)
    - test_member_add_with_role_admin
    - test_member_add_user_not_found (helpful error message)
    - test_member_add_project_not_found
    - test_member_remove_success
    - test_member_remove_user_not_found
    - test_member_remove_project_not_found
  </action>
  <verify>pytest tests/commands/test_member.py -v passes, all member commands work locally, ruff check passes</verify>
  <done>member list, member add, member remove commands working with proper error handling and role support</done>
</task>

</tasks>

<verification>
Before declaring plan complete:
- [ ] pytest tests/test_projects_resource.py tests/commands/test_member.py passes
- [ ] mypy src/n8n_cli/ passes
- [ ] ruff check passes
- [ ] Manual verification: Run `n8n member list`, `n8n member add`, `n8n member remove` locally
- [ ] member add supports --role flag with editor/admin
- [ ] All member commands registered in src/n8n_cli/cli.py
- [ ] Phase 5 complete: All project, user, and member commands working
</verification>

<success_criteria>

- All tasks completed
- All verification checks pass
- No errors or warnings introduced
- ProjectsResource has list_project_members, add_project_member, remove_project_member methods
- member list shows project members with roles
- member add adds user to project with role (default: editor)
- member remove removes user from project
- All commands follow established CLI patterns
- Comprehensive test coverage for API methods and commands
- **Phase 5 complete**: Full project/user/member management suite operational
</success_criteria>

<output>
After completion, create `.planning/phases/05-project-user-management/05-03-SUMMARY.md`:

# Phase 5 Plan 3: Member Management API and Commands Summary

**[Substantive one-liner - what shipped]**

## Performance

- **Duration:** [time]
- **Started:** [timestamp]
- **Completed:** [timestamp]
- **Tasks:** 2
- **Files modified:** [count]

## Accomplishments

- list_project_members(), add_project_member(), remove_project_member() methods in ProjectsResource
- member list command showing project members with roles
- member add command with role support (--role editor|admin, default: editor)
- member remove command for removing members from projects
- Email to user ID resolution for seamless UX
- Project name to ID resolution throughout
- Comprehensive test suite with [X] test methods
- 100% test coverage for member management methods
- **Phase 5 complete**: Full project, user, and member management suite

## Files Created/Modified

- `src/n8n_cli/client/resources/projects.py` - Added member management methods
- `src/n8n_cli/commands/member.py` - member list, add, remove commands
- `tests/test_projects_resource.py` - Member management tests
- `tests/commands/test_member.py` - Comprehensive member command tests
- `src/n8n_cli/cli.py` - Register member_group

## Decisions Made

[Key decisions and rationale, or "None - followed plan exactly"]

## Deviations from Plan

[Any auto-fixes or deferred issues, or "None"]

## Issues Encountered

[Problems and resolutions, or "None"]

## Next Phase Readiness

**Phase 5 complete!** Ready for **Phase 6: Developer Experience**.

**Phase 5 deliverables:**
- ✅ ProjectsResource with all methods (list, get, find_by_name, list_project_members, add_project_member, remove_project_member)
- ✅ UsersResource with all methods (list, invite, delete, find_by_email)
- ✅ project list and project view commands
- ✅ user list, user invite, user remove commands
- ✅ member list, member add, member remove commands
- ✅ Role support (editor, admin)
- ✅ Name/email resolution for intuitive CLI UX
- ✅ All commands follow established patterns
- ✅ Comprehensive test coverage across all resources and commands
- ✅ All quality gates passing (pytest, mypy, ruff)

**Next up:**
Phase 6 will enhance developer experience with shell completion, progressive verbosity, and utility functions.

## TDD Commit Hashes

**Task 1: Member management methods**
- RED: [hash] - test: add failing tests for member management methods
- GREEN: [hash] - feat: implement member management in ProjectsResource

**Task 2: Member commands**
- [hash] - feat: implement member list, add, remove commands

---
*Phase: 05-project-user-management*
*Completed: [date]*
</output>
