Vendor onboarding — Gitea teams a per-developer accounts¶
Status: draft (2026-05-14) Verze spec: 0.1 Související:
per-app-container.md,app-distribution.md,auth-organization.md
1. Motivace¶
Před touto změnou push template do nově vytvořeného repa probíhal pod jediným site-admin Gitea účtem (paincelebrator). To bránilo:
- Auditu —
git logukazoval „AVAX Platform service" pro všechny commity, ne skutečného developera - Code review — žádná branch protection s „PR od ne-autora"
- Multi-vendor izolaci — vendor A měl read-only přístup ke všem repům, ne jen ke svým
- Onboardingu — přidat developera znamenalo dát mu super-admin token
2. Cílový stav¶
Každá firma typu vendor v AVAX (řádek v companies tabulce s vlastní AVAX aplikací v adminu) má:
- Vlastní Gitea team v org
avax-apps - Sloupec
gitea_team_slugvcompaniestabulce mapuje AVAX company UUID na Gitea team - Členové týmu jsou skuteční developeři vendora s individuálními Gitea účty
Když Avaxis super-admin vytvoří app pro vendora:
1. POST /admin/app-management/create vytvoří Gitea repo v avax-apps/<slug>-app
2. Push template kostry
3. NEW: Pokud má publisher's company nastavený gitea_team_slug → přidá team jako collaborator s write permission
4. Developeři vendora okamžitě mohou klonovat + commitovat pod svým jménem
3. Architecturní rozhodnutí¶
Teams vs collaborators¶
Gitea nabízí dvě cesty grantování přístupu: - Collaborators — per-repo, per-user - Teams — per-org, granularita per-repo přiřazení
Volíme Teams protože: - Vendor má typicky víc apps (např. acme-soft → fakturace + mzdy + sklad) — team se přiřadí ke všem repům, member změna se promítne všude - Onboarding/offboarding developera = jedna operace, ne N - Branch protection rules lze nastavit per-team
Permission level pro vendor team¶
Write — developer může push do feature branche + PR do main. Avaxis tým může mít separátní admin permission přes site-admin nebo dedikovaný avaxis-internal team s admin ve všech repech.
Slug konvence¶
Gitea team slug = krátké pojmenování firmy/vendora, lowercase, kebab-case. Příklady:
- qwen (existující vendor avax-legal)
- acme-soft
- avaxis-internal (Avaxis sám)
Validace: [a-z0-9-]+, length 2-32.
4. DB schema změna¶
ALTER TABLE companies
ADD COLUMN gitea_team_slug VARCHAR(64) NULL;
CREATE UNIQUE INDEX uq_companies_gitea_team_slug
ON companies (gitea_team_slug)
WHERE gitea_team_slug IS NOT NULL;
- NULL = firma nemá vendor status (běžní zákazníci AVAXu, kteří jen kupují/používají apps)
- NOT NULL UNIQUE = vendor s teamem v
avax-appsorg
Migrace: XXX_add_companies_gitea_team_slug.py, downgrade dropne sloupec.
5. Backend API rozšíření¶
Gitea service (services/gitea.py)¶
Nové funkce — wrapper nad Gitea REST API:
def create_team(slug: str, description: str = "", permission: str = "write") -> dict:
"""POST /orgs/{GITEA_ORG}/teams — vytvoří team. Vrátí {id, name, permission}.
Vyhodí GiteaError pokud team už existuje."""
def get_team_id(slug: str) -> int | None:
"""GET /orgs/{GITEA_ORG}/teams/search?q=<slug> — najde team. None pokud neexistuje."""
def add_team_member(team_id: int, username: str) -> None:
"""PUT /teams/{team_id}/members/{username}"""
def remove_team_member(team_id: int, username: str) -> None:
"""DELETE /teams/{team_id}/members/{username}"""
def add_team_to_repo(team_id: int, repo_name: str) -> None:
"""PUT /orgs/{org}/teams/{team_id}/repos/{org}/{repo}"""
def list_team_members(team_id: int) -> list[str]:
"""GET /teams/{team_id}/members"""
Wire do create_app¶
V routers/app_management.py po úspěšném push_template:
publisher_company = await db.get(Company, publisher_id)
team_slug = publisher_company.gitea_team_slug if publisher_company else None
if team_slug:
try:
team_id = gitea.get_team_id(team_slug)
if team_id is None:
log_entries.append(f"⚠ Vendor team `{team_slug}` neexistuje v Gitea")
else:
gitea.add_team_to_repo(team_id, f"{body.slug}-app")
log_entries.append(f"✓ Team `{team_slug}` přidán k repu (write)")
except gitea.GiteaError as e:
log_entries.append(f"⚠ Team grant selhal: {e}")
else:
log_entries.append("⚠ Publisher company nemá gitea_team_slug — repo bez vendor přístupu")
Tolerantní — pokud team grant selže, app row + repo zůstávají. Avaxis admin to může napravit přes admin endpoint.
Admin endpointy¶
PUT /admin/companies/{id}/gitea-team
Body: {slug: str, create_if_missing: bool = false, description: str = ""}
→ Nastaví companies.gitea_team_slug. Pokud create_if_missing a team neexistuje,
vytvoří ho. Idempotentní (lze volat opakovaně).
POST /admin/companies/{id}/gitea-team/members
Body: {username: str}
→ Přidá username do vendor teamu. Vyžaduje gitea_team_slug nastaven.
DELETE /admin/companies/{id}/gitea-team/members/{username}
→ Odebere uživatele z teamu.
GET /admin/companies/{id}/gitea-team/members
→ Vrátí seznam aktuálních členů (jméno + email z Gitea).
Všechny vyžadují super_admin v AVAX (a token musí mít Gitea write:organization).
6. Migrace existujícího vendora qwen¶
Existující app avax-legal-client má gitea_repo_url: https://git.avaxis.cz/qwen/avax-legal — repo v uživatelské namespace qwen, ne v avax-apps org. To je legacy.
Migrace (manuální, jednorázová):
- V Gitea UI vytvořit team
qwenvavax-appsorg (write permission) - Přidat existující
qwenGitea uživatele jako člena teamu - V AVAX adminu volat
PUT /admin/companies/{qwen-company-id}/gitea-team {slug: "qwen"}— nastaví DB sloupec - Legacy repo
qwen/avax-legalzatím zůstává. Možnosti pro budoucnost: - Mirror: vytvořit
avax-apps/avax-legal-appjako mirror legacy repa (Gitea máPOST /repos/migrate) - Move: transfer ownership přes
POST /repos/{owner}/{repo}/transfer(vyžaduje souhlas qwen vendora) - Nechat: pro tuto jedinou existující app necháme legacy URL; nové apps už půjdou novou cestou
Doporučuju nechat — migrace existující app je risk a vendor musí být součástí rozhodnutí.
7. Onboarding nového vendora — workflow¶
Když nový vendor podepíše smlouvu s Avaxis:
- AVAX admin:
POST /org/companies— vytvořit firmu vendora (IČO, název, ...)-
PUT /admin/companies/{id}/gitea-team {slug: <vendor-slug>, create_if_missing: true}— vytvořit Gitea team + namapovat na company -
Vendor strana:
- Každý developer si v Gitea udělá vlastní účet (Gitea: Sign Up)
-
Pošle Avaxis adminu seznam svých Gitea usernames
-
AVAX admin:
-
Pro každého:
POST /admin/companies/{id}/gitea-team/members {username: <gitea_username>} -
Avaxis admin vytvoří první app pro vendora:
POST /admin/app-management/createspublisher_id = <vendor company UUID>- Backend automaticky přidá vendor team jako collaborator
- Developeři clone'nou a začnou pracovat
8. Otevřené otázky¶
- Branch protection — má
mainvyžadovat PR + review? Lze nastavit per-repo v Gitea, ale chceme to default při create. Gitea API:POST /repos/{owner}/{repo}/branch_protections. Pravděpodobně přidat dopush_templatepo push. - Avaxis internal team — má vlastní
avaxis-internalteam s admin permission ke všemavax-apps/*repům? Pravděpodobně ano, pro code review a hotfix. - Onboarding developera bez Avaxis admina — vendor admin (
company_adminrole) by mohl sám přidávat své developery, místo přes Avaxis. To by vyžadovalo role check (vendor admin své firmy ano, jiné ne) —gitea_team_slugv request musí matchovatcurrent_user.company.gitea_team_slug. - Mazání teamu při delete_app — pokud má firma víc apps, nemažeme. Pokud poslední app firmy mazaná, ponechat team (vendor relace pokračuje i bez apps).
- Vendor accountability — máme jen Gitea audit. Vyplatí se přidat AVAX
audit_logzáznam při změně členství?
9. Acceptance criteria¶
MVP¶
- DB migrace
companies.gitea_team_slugaplikovaná -
services/gitea.pyrozšířen o team API -
create_apppřidá vendor team jako collaborator (pokud nastaveno) - Admin endpoint
PUT /admin/companies/{id}/gitea-teamfunguje - End-to-end test: vendor company → team → create app → vendor developer může push
V1¶
- Admin endpoint pro člen-management (POST/DELETE/GET members)
- Migrace
qwenvendora (DB sloupec nastaven) - Branch protection na
main(volitelné, default opt-in) -
avaxis-internalteam setup s admin přístupem všude
V2¶
- UI v adminovi pro správu vendor teamů (místo přes API)
- Vendor self-service: company_admin své firmy může spravovat své developery
- Mirror legacy
qwen/avax-legaldoavax-apps/avax-legal-app
10. Související¶
per-app-container.md— širší architektura (kde apps běží)app-distribution.md— distribuce binárek (vendor → S3 bucket)auth-organization.md— AVAX role model (super_admin, company_admin, user)