Skip to content

Feature/shared projects#449

Open
kaospr wants to merge 31 commits intomainfrom
feature/shared-projects
Open

Feature/shared projects#449
kaospr wants to merge 31 commits intomainfrom
feature/shared-projects

Conversation

@kaospr
Copy link
Copy Markdown
Collaborator

@kaospr kaospr commented Mar 17, 2026

No description provided.

kaospr and others added 30 commits March 13, 2026 12:29
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Address issues found during spec review:
- Rate resolution is now org-context-aware (used_rate_for method)
- TimeRegPolicy scope extended for shared project visibility
- ProjectPolicy uses subquery approach to avoid JOIN incompatibility
- Added ProjectSharePolicy and ProjectShareTaskRatePolicy
- Post-disconnection time_reg visibility rules defined
- AssignedTask rate-change archiving migrates ProjectShareTaskRate
- Workspace::ProjectPolicy changes for guest admin read access
- Task/Client scope adjustments documented
- Controller structure and routes defined
- API considerations noted
- Edge cases documented (multi-org users, promotions, soft deletes)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Add concrete TimeRegPolicy action methods for shared projects
  (create?, show?, edit? etc. now handle cross-org access)
- Add concrete TaskPolicy scope for shared projects
  (guest org users can see owning org's tasks via assigned_tasks)
- Add export restriction note (no emails for cross-org users)
- Add Reports::Summary/Result refactoring note
- Fix route/controller inconsistency

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Create the foundational model for org-to-org project sharing.
ProjectShare links a project to a guest organization with an
optional rate override, enforcing uniqueness and preventing
sharing with the owning organization.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add per-task rate override model for shared projects. Includes
RateConvertible concern, uniqueness validation scoped to project_share,
and a unique composite index on (project_share_id, assigned_task_id).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
When accepting a project invitation into an organization different from
the project's owner, automatically create a ProjectShare linking the
project to the guest organization via find_or_create_by! to handle
duplicates gracefully.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
When an AssignedTask's rate changes, the existing record is archived and
a new one is created. This ensures any associated ProjectShareTaskRate
records are migrated to point to the new AssignedTask.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Authorize show/update/destroy actions on project shares with proper
multi-tenant scoping. Owner org admins can view and disconnect shares;
guest org admins can view, manage rates, and disconnect. Non-admin
users are denied all access. Scope returns shares visible to the
current organization (as guest or owner).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Update the Workspace::ProjectPolicy to support shared projects:
- Scope now returns both own org projects and projects shared via
  ProjectShare, with non-admin users filtered by ProjectAccess
- show? allows guest org admins to view shared projects (read-only)
- edit?/update?/destroy? remain restricted to owning org admin
- Add fixtures for cross-org test scenarios (org_two user, ProjectAccess)
- Update spectator controller test for new redirect path

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add used_rate_for(organization) and billed_amount_for(organization) methods
that resolve rates based on the viewing organization's context. Guest orgs
(with a ProjectShare) get their own rate hierarchy: task rate > project share
rate > 0. The project owner org falls back to existing used_rate behavior.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Reports::Summary and Reports::Result now accept an optional organization
parameter. When provided, they use billed_amount_for(organization) to
compute billable amounts using the guest org's ProjectShare rates instead
of the owning org's rates.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Implements controller for managing project shares with index, update_rates,
and destroy actions. Adds accepts_nested_attributes_for to ProjectShare model
to support bulk rate updates for project share task rates.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add shared project context variables to the show action:
- @shared_project and @project_share for guest org admins viewing shared projects
- @guest_organizations for owning org admins to see which orgs have access

Add tests verifying guest org admin can view but not edit/update/destroy
shared projects.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Update ProjectPolicy scopes to include shared projects via ProjectShare
- Add authorize! to export action (was missing)
- Move export? to class-based authorization in TimeRegPolicy
- Strip cross-org user emails in CSV export
- Add tests for org_two member creating time_regs on shared projects
- Add tests for task dropdown loading shared project tasks
- Add tests for admin export with email stripping

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Show "Shared by [org_name]" badge on projects shared with the current
organization. Hide edit/delete buttons for shared projects since guest
org admins cannot modify them. Add shared_with? helper to Project model
and preload project_shares in index to avoid N+1 queries.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Create _shared_organizations partial showing guest organizations with
disconnect buttons. Only visible to owning org admins when
@guest_organizations is present. Each org entry has a disconnect button
that triggers the ProjectSharesController#destroy action.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
When viewing a shared project (guest org): hide edit/delete buttons and
show disconnect action instead, display "Shared by [org]" badge, hide
client link and members tab (not relevant for guest org), and add a
hook for the rates form partial.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Create rates form partial allowing guest org admins to set project-level
and per-task override rates on their project share. The form submits to
the update_rates action which now redirects back to the project show
page. Eagerly load project_share_task_rates in the show action to avoid
N+1 queries.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Create index.html.erb for ProjectSharesController replacing the JSON
response. Lists shared organizations with disconnect buttons. Update
controller to eagerly load organizations and render the template.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Two issues fixed:
1. new_modal redirected away if guest org had no own projects — now
   also checks for shared_projects
2. create? policy denied guest org admins from logging their own time
   on shared projects — now allows it (still prevents creating on
   behalf of others)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The TimeRegPolicy :own scope filtered by organization ID, which
excluded time_regs on shared projects (where the project's org
differs from the user's current org). Now includes the user's own
entries on shared projects via ProjectShare subquery.

Also adds Playwright test verifying time_regs are visible on the
time_regs index for guest org users.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1. Fix missing locale key: use notice.project_share_rates_updated
2. Extract ProjectShare#rate_for_task and Project#project_share_for
   to reduce N+1 queries and improve message passing
3. Use model methods (shared_with?, project_share_for, owning_organization,
   has_accessible_projects?) instead of reaching into associations from
   controllers, policies, and views
4. Show guest org's rate on shared project info section
5. Rename update_rates to standard RESTful update action
6. Extract switch_org_context! to test_helper.rb (was duplicated in 9 files)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant