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:writePATs 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.
Strategy 1: creator-private (Default, Recommended)¶
Command:
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:
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:
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¶
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¶
Roles: project_admin, project_editor, project_viewer
Expected output: ✓ alice@example.dev added to <project-name> as project_editor
Change Member Role¶
Expected output: ✓ alice@example.dev role changed to project_admin
Remove a Member¶
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:
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:
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¶
- Choose your migration strategy (creator-private or first-team) before running the Alembic migration
- Run the migration on a staging environment first; test with one team
- Audit project access post-migration to ensure teams see the projects they expect
- Rotate PATs to include
project:*scopes during the 90-day window - Update CI/CD workflows to use the new PATs
- 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)