Skip to content

P1 Team-Scoped Projects Migration Guide

Overview

SkillMeat Phase 1 (P1) ships team-scoped project ownership, per-user project ACLs, and six new project:* RBAC scopes for enterprise deployments. This upgrade enables least-privilege access control at the project level, allowing operators to:

  • Scope project visibility to specific teams
  • Grant or revoke project access to individual users
  • Differentiate project roles (project_admin, project_editor, project_viewer)
  • Rotate legacy artifact:write PATs to new scopes on a 90-day deprecation timeline

This guide walks you through the migration choices, PAT rotation, and key changes to expect. For architectural details, see the ADR: Project Team Ownership Shape and the P1 implementation plan.


Terminology

Term Definition
Team-Scoped A project is owned by and visible to members of a specific team
Creator-Private A project with no team owner; only the creator and system admins see it
Explicit Member A user with a direct ACL row on a project (overrides team default)
Project Role One of project_admin, project_editor, project_viewer (distinct from team roles)
PAT Personal Access Token; used for API clients and CI/CD automation

Migration Strategy: Choose One

P1 includes an Alembic migration (ent_062_project_team_ownership) that backfills existing projects with team ownership. You must choose a strategy at migration time. This choice is not reversible without manual SQL intervention.

Command:

alembic upgrade ent_062 --x-strategy=creator-private

Behavior: - All existing projects without an explicit team assignment remain creator-private (owner_team_id IS NULL) - Only the original creator (created_by user) and system admins see the project in their my scope - Projects do not automatically appear in team project lists - Safe default: Existing behavior is preserved; no surprise sharing

When to use: - Upgrading multi-team tenants where users have mixed access expectations - Conservative deployments preferring manual review before bulk-sharing - Teams that will add members explicitly via the new skillmeat project member add CLI command

Post-Migration Admin Actions: Use the new admin bulk-share tool (backlog item DEF-P1-02) or the API endpoint POST /api/v1/projects/{id}/members to explicitly add teams or users to creator-private projects once you've reviewed access policies.

Strategy 2: first-team (Day-1 Sharing)

Command:

alembic upgrade ent_062 --x-strategy=first-team

Behavior: - All existing projects are assigned to each creator's first team membership (by creation date) - Projects automatically appear in all members' team project lists - Access is shared from day 1; no manual review needed - Caution: Assumes all team members have equal project access expectations

When to use: - Single-team deployments (most common) - Tenants where teams are coarse-grained and project sharing aligns with team membership - Streamlined onboarding where backward-compatibility is less critical

Risk: If a creator belongs to multiple teams with different access controls, all their projects become visible to all their team members. Review team membership structure before choosing this strategy.


OQ-21: Which Strategy Should I Choose?

Recommendation: Start with creator-private (default). It is safer, requires zero assumptions about your team structure, and allows manual review and approval before sharing projects with teams. You can always bulk-share creator-private projects later using admin tools.

If you operate a single-team deployment, first-team accelerates day-1 adoption with no additional manual steps.


PAT Scope Rotation (90-Day Deprecation Window)

Timeline

Date Milestone
2026-05-20 P1 ships; artifact:write on project mutation endpoints is deprecated. Existing PATs continue to work.
2026-05-20 → 2026-08-18 90-day window. Rotate PATs to include new project:* scopes.
2026-08-18 Sunset target. artifact:write removed from project mutation endpoints; PATs without project:* scopes receive 403 Forbidden on project mutations.

New Project Scopes

Six new scopes control project access:

Scope Purpose Minimum Grant Typical Grant
project:read Read project metadata, list members project_viewer All roles
project:write Create/update project properties project_editor project_editor, project_admin
project:branch Create/merge branches project_editor project_editor, project_admin
project:deploy Trigger deployments from project project_editor project_editor, project_admin
project:share Add/remove/modify project members project_admin project_admin only
project:admin Full project administration project_admin project_admin only

For details on role-to-scope mapping, see Auth Architecture: P1 project:* scopes.

How to Rotate a PAT

Step 1: Create a new PAT with project:* scopes

Via the SkillMeat web dashboard: 1. Navigate to Settings → Personal Access Tokens (or Admin → API Tokens for workspace tokens) 2. Click Create New Token 3. Name: [old-token-name]-v2 (for tracking) 4. Scopes: Check the project:read, project:write, project:branch, project:deploy boxes for your use case (and project:share, project:admin if you manage project membership) 5. Expiration: Match the old token's expiration policy 6. Click Generate 7. Copy the new token immediately (it is shown only once)

Step 2: Update your CI/CD or API client

Replace the old SKILLMEAT_PAT or equivalent environment variable with the new token:

# .env, CI/CD secrets, or deployment config
export SKILLMEAT_PAT="skillmeat-pat-xxx"  # New token

Step 3: Verify

Test a project mutation endpoint (e.g., POST /api/v1/projects/{id}/members) with the new PAT:

curl -X POST https://your-skillmeat-host/api/v1/projects/<project-uuid>/members \
  -H "Authorization: Bearer $SKILLMEAT_PAT" \
  -H "Content-Type: application/json" \
  -d '{
    "user_id": "user-uuid",
    "role": "project_viewer"
  }'

Expected: 201 Created (or 409 Conflict if the user is already a member).

Step 4: Revoke the old PAT

In Settings → Personal Access Tokens, click the old token and select Revoke. Update your CI/CD or client configs to use only the new token.


Access Before & After

Scenario 1: Single Team, Single User

Aspect Before P1 After P1 (creator-private) After P1 (first-team)
User sees all projects ✅ (tenant-wide) ✅ (creator-private projects) ✅ (auto-added to team)
Teammates see your projects ✅ (tenant-wide) ❌ (unless explicitly added) ✅ (team-owned)
Explicit member removal N/A ✅ (per-user granularity) ✅ (per-user granularity)

Scenario 2: Multi-Team User, Different Access Per Team

Aspect Before P1 After P1 (creator-private) After P1 (first-team)
Alice (TeamA editor, TeamB viewer) creates a project Visible to all tenants ✅ Creator-private; only Alice sees ⚠️ Caution: Visible to all members of Alice's first team (whether TeamA or TeamB depends on join order)
Admin manually adds project to TeamB N/A ✅ TeamB members see it; role defaults to project_editor ✅ Already visible via first-team assignment
Admin grants Alice project_admin on TeamA's projects N/A ✅ Alice gets explicit project_admin row; overrides team project_editor default ✅ Same; explicit rows override team defaults

Scenario 3: Admin Bulk-Share Existing Projects

Aspect Before P1 After P1 (creator-private) After P1 (first-team)
Admin wants all Marketing projects visible to the Marketing team Tenant-wide access only ✅ Use admin bulk-share tool (DEF-P1-02) or POST /api/v1/projects/{id}/members to add each project to Marketing team ✅ Already shared if project creator is in Marketing; manual override if not

CLI Member Management Quick-Start

P1 ships four new CLI commands under skillmeat project member for managing project access:

List Project Members

skillmeat project member list <project-uuid>

Output:

Project Members: <project-name>

  User                          Role             Joined
  ────────────────────────────  ───────────────  ──────────────
  alice@example.dev             project_admin    2026-05-20
  bob@example.dev               project_editor   2026-05-20
  carol@example.dev             project_viewer   2026-05-21

Add a Member

skillmeat project member add <project-uuid> --user alice@example.dev --role project_editor

Roles: project_admin, project_editor, project_viewer

Expected output: ✓ alice@example.dev added to <project-name> as project_editor

Change Member Role

skillmeat project member role <project-uuid> --user alice@example.dev --role project_admin

Expected output: ✓ alice@example.dev role changed to project_admin

Remove a Member

skillmeat project member remove <project-uuid> --user alice@example.dev --yes

The --yes flag skips the confirmation prompt.

Expected output: ✓ alice@example.dev removed from <project-name>


Known Limitations & Follow-On Work

The following features are not included in P1 and are planned for later phases:

Feature Target Phase Status
Project Branching P2 Projects gain main + N-branches semantics; branch protection rules
User Overlays P4 Per-user variant pinning (artifact versions, env vars) without affecting teammates
Audit Logging P3 Project membership changes, role changes, and project edits logged to audit tables
Admin Bulk-Share Tool Post-P1 Backlog UI/CLI tool for bulk-adding teams/users to creator-private projects (DEF-P1-02)

For full feature roadmap, see the PRD: Multi-User Projects, Team Scoping, User Overlays, and Project Branching.


Troubleshooting

Q: After migration, users report "project not found"

A: You selected creator-private strategy. Creator-private projects are visible only to the original creator. Either: 1. Use the new skillmeat project member add CLI command to explicitly add users, or 2. Use the admin bulk-share tool (coming in DEF-P1-02) to assign the project to a team

Q: A user is a team member but cannot see the project

A: Check the project's owner_team_id:

skillmeat admin project show <project-uuid>

If owner_team_id is NULL, the project is creator-private. Add the user explicitly via skillmeat project member add.

If owner_team_id is set, check the user's team membership:

skillmeat admin user show <user-id>

If the user is not in the team, add them via skillmeat team member add.

Q: PAT no longer works for project mutations (403 Forbidden)

A: You are past the 90-day deprecation window (after 2026-08-18) and the old artifact:write scope is no longer accepted. Rotate to a new PAT with project:* scopes per the PAT Scope Rotation section above.

Q: Which scopes should I grant my CI/CD PAT?

A: Depends on what your CI/CD does: - Read-only (artifact discovery): project:read, artifact:read - Artifact mutations + deployments: project:read, project:write, project:deploy, artifact:write - Project member management (rare for CI/CD): Add project:share

Avoid granting project:admin unless absolutely necessary; it grants team-wide project administration.


Next Steps

  1. Choose your migration strategy (creator-private or first-team) before running the Alembic migration
  2. Run the migration on a staging environment first; test with one team
  3. Audit project access post-migration to ensure teams see the projects they expect
  4. Rotate PATs to include project:* scopes during the 90-day window
  5. Update CI/CD workflows to use the new PATs
  6. Monitor logs for 403 errors on project endpoints (indicates scope issues)

For additional help, see: - ADR: Project Team Ownership Shape - Auth Architecture Key Context - SkillMeat API Documentation (project endpoints + scopes)