Team Management Agent Skill
Team/org data model, email invitations, role assignment, seat-based billing, org switcher, and ownership transfer.
The Skill
Full content, every format. Copy it, download it, or install with one command.
---
description: Team/org data model, email invitations, role assignment, seat-based billing, org switcher, and ownership transfer.
homepage: https://yepapi.com/skills/team-management
metadata:
tags: [teams, organizations, invitations, roles]
---
# Team Management
## Rules
- Data model: `Organization` → `Membership` (userId, orgId, role) → `User` — many-to-many through membership
- Roles: owner (1 per org), admin, member — permissions checked via middleware, not inline conditionals
- Invite by email: create `Invitation` with token, role, expiry (7 days) — send email with invite link
- Invite flow: click link → sign up or sign in → auto-accept → redirect to org dashboard
- Org switcher: store `currentOrgId` in session/cookie — all API calls scoped to current org
- Seat-based billing: sync member count with Stripe subscription `quantity` — update on member add/remove
- Transfer ownership: current owner selects new owner → confirm with password → swap roles
- Leave team: member can leave freely, admin must transfer admin to another first, owner must transfer ownership
## Patterns
\`\`\`ts
// Data model
// organizations: id, name, slug, createdAt
// memberships: id, orgId, userId, role (owner|admin|member), createdAt
// invitations: id, orgId, email, role, token, expiresAt, acceptedAt, invitedBy
// Invite flow
export async function inviteToOrg(orgId: string, email: string, role: string, invitedBy: string) {
const token = crypto.randomUUID();
const expiresAt = new Date(Date.now() + 7 * 24 * 60 * 60 * 1000);
await db.insert(invitations).values({ orgId, email, role, token, expiresAt, invitedBy });
await sendEmail({
to: email,
subject: `You're invited to join ${org.name}`,
html: `<a href="${baseUrl}/invite/${token}">Accept invitation</a>`,
});
}
// Accept invite
export async function acceptInvite(token: string, userId: string) {
const invite = await db.query.invitations.findFirst({
where: and(eq(invitations.token, token), gt(invitations.expiresAt, new Date()), isNull(invitations.acceptedAt)),
});
if (!invite) throw new Error("Invalid or expired invitation");
await db.transaction(async (tx) => {
await tx.insert(memberships).values({ orgId: invite.orgId, userId, role: invite.role });
await tx.update(invitations).set({ acceptedAt: new Date() }).where(eq(invitations.id, invite.id));
});
}
// Middleware: scope all queries to current org
function withOrg(handler: (req: Request, orgId: string) => Promise<Response>) {
return async (req: Request) => {
const orgId = req.headers.get("x-org-id") || session.currentOrgId;
const membership = await getMembership(session.userId, orgId);
if (!membership) return Response.json({ error: "Not a member" }, { status: 403 });
return handler(req, orgId);
};
}
\`\`\`
## Avoid
- Checking roles with inline `if (user.role === "admin")` — use a permissions middleware or helper
- Invitations without expiry — always expire tokens after 7 days, allow re-invite
- Allowing the last owner to leave — require ownership transfer before leaving
- Forgetting to update Stripe seat count on member changes — sync on every add/remove
- Org data leaking across teams — scope every database query to `orgId` via middlewareInstall
Why Use the Team Management Skill?
Without this skill, your AI guesses at team management patterns. It might hallucinate deprecated APIs, use outdated conventions, or miss best practices entirely. With it, your AI follows a proven ruleset — every suggestion aligns with current standards.
Drop this skill into your project and your AI instantly knows the rules. Better code suggestions, fewer errors, faster shipping.
Try These Prompts
These prompts work better with the Team Management skill installed. Your AI knows the context and writes code that fits.
"Build an organization/team system with invitations, roles, and org switcher"
"Create an email invitation flow with token-based accept and automatic org join"
"Implement seat-based billing that syncs member count with Stripe subscription quantity"
Works Great With
Team Management skill — FAQ
It provides rules for organization data models, email invitation flows, role assignment, seat-based billing with Stripe, org switcher UX, and ownership transfer. Your AI builds complete team management features.
Run `npx skills add YepAPI/skills --skill team-management` in your project root. This copies the skill file into your repo where your AI coding tool can read it automatically.
Use a many-to-many relationship: Organization -> Membership (userId, orgId, role) -> User. Each membership has a role (owner, admin, member). The skill includes the complete data model and query patterns.