Feat v0.9.4 package adoption + roles
All checks were successful
CI/CD / detect-changes (pull_request) Successful in 21s
CI/CD / test-frontend (pull_request) Has been skipped
CI/CD / test-runners (pull_request) Has been skipped
CI/CD / e2e-smoke (pull_request) Has been skipped
CI/CD / test-sqlite (pull_request) Successful in 2m52s
CI/CD / test-go-pg (pull_request) Successful in 3m6s
CI/CD / build-and-deploy (pull_request) Successful in 1m41s

Packages can declare `adoptable: true` in their manifest. When a team
adopts an adoptable package, a team-scoped copy is created that references
the original via `adopted_from` (shared assets, no disk duplication).
The package's `requires_roles` auto-populate into a new `team_role_catalog`
table so team admins know which roles to assign.

Migration 017: adoptable/adopted_from columns on packages, team_role_catalog
table. 4 new endpoints (adopt, list adoptable, unadopt, role catalog).
AdoptTeamWorkflow deprecated. 11 new tests, all passing.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-04-03 16:17:53 +00:00
parent 0661e1d768
commit 166acce2e9
17 changed files with 959 additions and 24 deletions

View File

@@ -6,6 +6,7 @@ import (
"encoding/json"
"armature/models"
"armature/store"
)
type TeamStore struct{}
@@ -393,3 +394,40 @@ func (s *TeamStore) RemoveAllUserRoles(ctx context.Context, teamID, userID strin
teamID, userID)
return err
}
// ── v0.9.4 — Team Role Catalog ──
func (s *TeamStore) AddRoleToCatalog(ctx context.Context, teamID, role, sourcePkgID string) error {
_, err := DB.ExecContext(ctx, `
INSERT INTO team_role_catalog (id, team_id, role, source_package_id)
VALUES (gen_random_uuid(), $1, $2, $3)
ON CONFLICT (team_id, role) DO NOTHING`,
teamID, role, sourcePkgID)
return err
}
func (s *TeamStore) ListRoleCatalog(ctx context.Context, teamID string) ([]store.TeamRoleCatalogEntry, error) {
rows, err := DB.QueryContext(ctx, `
SELECT role, COALESCE(source_package_id, '') FROM team_role_catalog
WHERE team_id = $1 ORDER BY role`, teamID)
if err != nil {
return nil, err
}
defer rows.Close()
var result []store.TeamRoleCatalogEntry
for rows.Next() {
var e store.TeamRoleCatalogEntry
if err := rows.Scan(&e.Role, &e.SourcePackageID); err != nil {
return nil, err
}
result = append(result, e)
}
return result, rows.Err()
}
func (s *TeamStore) RemoveRoleCatalogBySource(ctx context.Context, teamID, sourcePkgID string) error {
_, err := DB.ExecContext(ctx, `
DELETE FROM team_role_catalog WHERE team_id = $1 AND source_package_id = $2`,
teamID, sourcePkgID)
return err
}