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

<objective>
Implement ProjectsResource and UsersResource API classes with list, get, and utility methods following the hub-and-spoke architecture established in Phases 3-4.

Purpose: Provide type-safe API methods for project and user management that CLI commands will use in Plan 2 and 3.
Output: Two complete resource classes (ProjectsResource, UsersResource) with retry logic, Pydantic validation, and 100% test coverage.
</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
@REQUIREMENTS.md
@src/n8n_cli/client/core.py
@src/n8n_cli/client/resources/workflows.py
@src/n8n_cli/client/resources/executions.py
@src/n8n_cli/client/resources/__init__.py
@src/n8n_cli/client/models/project.py
@src/n8n_cli/client/models/user.py
@src/n8n_cli/client/models/__init__.py
@tests/test_workflows_resource.py
@tests/test_executions_resource.py
</context>

<tasks>

<task type="auto" tdd="true">
  <name>Create ProjectsResource with list/get/find_by_name methods</name>
  <files>src/n8n_cli/client/resources/projects.py, tests/test_projects_resource.py</files>
  <test-first>
    Test: ProjectsResource.list() returns list[Project], .get(id) returns single Project, .find_by_name(name) returns Project or None
    Cases:
    - list() with empty/multiple projects
    - get() with valid ID, invalid ID (NotFoundError)
    - find_by_name() with exact match, no match, multiple matches (ValueError)
    - All methods retry on HTTPError, ConnectionError, ServerError
  </test-first>
  <action>
    Create ProjectsResource class following WorkflowsResource pattern from Phase 3:
    - Hub-and-spoke architecture: __init__(self, client: httpx.Client)
    - list() method: GET /api/v1/projects, return list[Project] from data["data"]
    - get(project_id) method: GET /api/v1/projects/{id}, return Project.model_validate()
    - find_by_name(name) method: Call list(), filter by exact name match (case-sensitive), raise ValueError if multiple matches
    - All methods use @retry decorator with exponential backoff (2s/4s/8s, max 10s, 3 attempts)
    - Retry on httpx.HTTPError, ConnectionError, ServerError
    - Use handle_response() for proper error mapping (NotFoundError on 404)
    - Return type-safe Pydantic Project models

    Write comprehensive tests covering:
    - list() success with multiple projects
    - get() success and NotFoundError
    - find_by_name() exact match, no match (None), multiple matches (ValueError)
    - Retry behavior on transient errors (3 test classes: TestList, TestGet, TestFindByName)
  </action>
  <verify>pytest tests/test_projects_resource.py -v passes, mypy src/n8n_cli/client/resources/projects.py passes</verify>
  <done>ProjectsResource implemented with all methods, 100% test coverage, type-safe returns</done>
</task>

<task type="auto" tdd="true">
  <name>Create UsersResource with list/invite/delete/find_by_email methods</name>
  <files>src/n8n_cli/client/resources/users.py, tests/test_users_resource.py, src/n8n_cli/client/resources/__init__.py, src/n8n_cli/client/core.py</files>
  <test-first>
    Test: UsersResource.list() returns list[User], .invite(email) returns User, .delete(user_id) returns None, .find_by_email(email) returns User or None
    Cases:
    - list() with empty/multiple users
    - invite() with valid email, duplicate email (ValidationError)
    - delete() with valid ID, invalid ID (NotFoundError)
    - find_by_email() with exact match, no match (None)
    - All methods retry on appropriate errors
  </test-first>
  <action>
    Create UsersResource class following ProjectsResource pattern:
    - Hub-and-spoke architecture: __init__(self, client: httpx.Client)
    - list() method: GET /api/v1/users, return list[User] from data["data"]
    - invite(email) method: POST /api/v1/users with {"email": email}, return User.model_validate()
    - delete(user_id) method: DELETE /api/v1/users/{id}, return None
    - find_by_email(email) method: Call list(), filter by exact email match (case-insensitive), return User or None
    - All methods use @retry decorator with exponential backoff
    - Retry on httpx.HTTPError, ConnectionError, ServerError
    - Use handle_response() for error mapping

    Update src/n8n_cli/client/resources/__init__.py:
    - Export ProjectsResource and UsersResource

    Update src/n8n_cli/client/core.py:
    - Import ProjectsResource and UsersResource
    - Add to __init__: self.projects = ProjectsResource(self._client), self.users = UsersResource(self._client)
    - Update docstring example to show client.projects and client.users

    Write comprehensive tests covering all methods and error cases (4 test classes: TestList, TestInvite, TestDelete, TestFindByEmail).
  </action>
  <verify>pytest tests/test_users_resource.py tests/test_projects_resource.py -v passes, mypy passes, ruff check passes</verify>
  <done>UsersResource implemented, both resources integrated into APIClient hub, 100% test coverage for both resources</done>
</task>

</tasks>

<verification>
Before declaring plan complete:
- [ ] pytest tests/test_projects_resource.py tests/test_users_resource.py passes (all tests green)
- [ ] mypy src/n8n_cli/client/ passes (no type errors)
- [ ] ruff check passes (no linting errors)
- [ ] Both resources available via APIClient: client.projects and client.users
- [ ] All methods return type-safe Pydantic models (Project, User)
- [ ] 100% test coverage for both resource files
</verification>

<success_criteria>

- All tasks completed
- All verification checks pass
- No errors or warnings introduced
- ProjectsResource has list(), get(), find_by_name() methods
- UsersResource has list(), invite(), delete(), find_by_email() methods
- Both resources integrated into APIClient hub-and-spoke architecture
- All methods use @retry decorator with exponential backoff
- All methods return type-safe Pydantic models
- Comprehensive test suite with retry behavior verification
- Ready for Plan 2 (CLI commands can use these resources)
</success_criteria>

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

# Phase 5 Plan 1: ProjectsResource and UsersResource API Methods Summary

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

## Performance

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

## Accomplishments

- ProjectsResource class with list(), get(), find_by_name() methods
- UsersResource class with list(), invite(), delete(), find_by_email() methods
- Hub-and-spoke integration into APIClient
- Type-safe Pydantic model returns (Project, User)
- Exponential backoff retry logic on all methods
- Comprehensive test suite with [X] test methods
- 100% test coverage verified

## Files Created/Modified

- `src/n8n_cli/client/resources/projects.py` - ProjectsResource implementation
- `src/n8n_cli/client/resources/users.py` - UsersResource implementation
- `tests/test_projects_resource.py` - Comprehensive ProjectsResource tests
- `tests/test_users_resource.py` - Comprehensive UsersResource tests
- `src/n8n_cli/client/resources/__init__.py` - Export new resources
- `src/n8n_cli/client/core.py` - Integrate resources into APIClient hub

## 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 Plan 1 complete. Ready for **05-02-PLAN.md (Project and User CLI Commands)**.

**API foundation established:**
- ✅ ProjectsResource with all methods (list, get, find_by_name)
- ✅ UsersResource with all methods (list, invite, delete, find_by_email)
- ✅ Both integrated into APIClient hub
- ✅ All methods type-safe with Pydantic validation
- ✅ Production-ready retry logic
- ✅ 100% test coverage
- ✅ All quality gates passing

**Next up:**
Phase 5 Plan 2 will implement project and user CLI commands using the complete API foundation established in this plan.

## TDD Commit Hashes

**Task 1: ProjectsResource**
- RED: [hash] - test: add failing tests for ProjectsResource
- GREEN: [hash] - feat: implement ProjectsResource with retry logic

**Task 2: UsersResource**
- RED: [hash] - test: add failing tests for UsersResource
- GREEN: [hash] - feat: implement UsersResource and integrate into APIClient

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