video-accessibility/backend/app/models/membership.py
Vadym Samoilenko 6f1be645ce feat(saas): Phase 0+1 — Organization/Membership entities and dev branch
Introduces the multi-tenant SaaS foundation alongside the existing
client/team/project model (zero-downtime shim period):

Backend:
- app/models/organization.py — Organization + OrgRole enum (OWNER/ADMIN/MANAGER/MEMBER/VIEWER)
- app/models/membership.py — Membership model with MemberDetail for enriched responses
- app/services/membership_service.py — upsert/remove/list/has_org_role helpers
- app/api/v1/routes_organizations.py — /organizations CRUD + /members sub-resource + /me/memberships
- main.py — registers organizations router
- migrations: create memberships collection (unique index) + backfill from pm_client_ids/team members

Frontend:
- types/api.ts — Organization, OrgRole, Membership, OrganizationCreateRequest types; Client marked @deprecated
- hooks/useClients.ts — useOrganizations, useOrganization, useOrgMembers, useAddOrgMember,
  useUpdateOrgMember, useRemoveOrgMember, useMyMemberships
- lib/api.ts — listOrganizations, getOrganization, createOrganization, updateOrganization,
  listOrgMembers, addOrgMember, updateOrgMember, removeOrgMember, getMyMemberships

Reads fall back to the clients collection during transition; all writes go to organizations.
Existing /clients endpoints and hooks are untouched.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-27 16:46:24 +01:00

34 lines
728 B
Python

from datetime import datetime
from typing import Optional
from pydantic import BaseModel
from .organization import OrgRole
class Membership(BaseModel):
id: Optional[str] = None
user_id: str
organization_id: str
role_in_org: OrgRole
created_at: Optional[datetime] = None
created_by: Optional[str] = None
class MembershipCreate(BaseModel):
user_id: str
role_in_org: OrgRole = OrgRole.MEMBER
class MembershipUpdate(BaseModel):
role_in_org: OrgRole
class MemberDetail(BaseModel):
"""Membership enriched with user info for list endpoints."""
membership_id: str
user_id: str
email: str
full_name: str
role_in_org: OrgRole
created_at: Optional[datetime] = None