Поточний код, міграція та самоперевірка
Історичний проєкт
Ця сторінка фіксує попередній проєкт, а не поточний стан випуску. Підготовка ресурсів, scoped authorization і trusted MCP уже реалізовані в комітах Agentfy; див. контракт серверного чату та межі доказів. Браузерні/BONSITE протоколи й ширші пропозиції щодо оплати/життєвого циклу зберігають власні умови випуску. Бойовий запуск партнера не мається на увазі.
Факти поточного коду
Скорочені шляхи від api/src/slices/, якщо повний префікс api/ не вказано; прочитані в checkout AGNT2-424. Не плутати потрібні зміни з наявною поведінкою.
| Поточний доказ | Наслідок / міграція |
|---|---|
api/src/slices/user/user/user.prisma: required unique email, optional password, platformRole | Credential-independent actor; nullable/non-applicable email для partner без fake addresses; direct credential uniqueness лишається |
user/auth/domain/auth.types.ts: email в IAuthUser/JWT, union access/refresh/session | Scoped principal/source/audience, version DTO/SDK; не розширити global guard одним type |
user/auth/domain/auth.service.ts: email-stub claim, new team, founding | Dedicated credential-only/link/bootstrap; без stub takeover/extra team/partner founder; exclude external actors from founding |
user/auth/guards/jwtAuth.guard.ts: signature/type, sub/email request | State revocation, explicit endpoint opt-in; account/platform/financial-consent лише direct proof |
user/auth/domain/auth.service.ts: refresh type + user lookup, new tokens | Persisted rotating families/source/epoch/version/reuse detection; нині цього немає |
user/team/domain/team.service.ts: separate team/key, seat, provisioning | Transactional allocation gateway + durable outbox; поточний метод не atomic |
user/team/domain/teamProvision.port.ts: handler errors logged/swallowed | Persist readiness/retry; signup success не доводить concierge readiness |
user/userTeam/userTeam.prisma, domain/userTeam.service.ts: unique actor/team, several owners, count before write | Role — source ownership; lock/transaction last-owner/transfer/inactive actor |
agent/agent/agent.prisma: Agent(ownerId, teamId) FK→UserTeam(userId, teamId) | Stable IDs; reassign або retain inactive membership/stop jobs |
billing/{subscription,invoice,payment,paymentMethod}/*.prisma: team scope, invoice unique subscription/period, cascade | Payer timeline/retained invoice lines, без переносу history/subscriptions; remove financial cascade risk |
billing/invoice/domain/invoice.service.ts, billing/payment/domain/payment.service.ts: invoice on completed payment | PayPal subscription flow не usage-invoicing; certify consent/cancel/callbacks обох modes |
system/usage/meter/meter.prisma: frozen costUsdPico, no resource FK, rollups | Preserve ledger/precision; historical commercial attribution events/aggregates перед payer switches |
Розміщення за CleanSlice
Прочитано MCP get-started, list-categories, виконано пошуки cross-slice authentication/organization і transactions/idempotency/billing, прочитано docs/architecture/dependency-flow.md. Другий пошук не знайшов transaction guide: транзакція тут — явна пропозиція, не вигадане правило MCP. Додаткові обмеження — шари і constitution.
Organization/identity/membership — singular user-group slices, user auth owns browser/link contexts. Billing L6 координує provisioning user allocation L2 + payer state через domain gateway, data implementation якого тримає спільну local transaction. План має визначити цей boundary, не назвати незалежні service calls атомарними. Agent L5 споживає durable operation через downward contracts; remote effects поза транзакцією.
System usage L1 не імпортує user/billing: upper consumers передають immutable attribution через lower-layer domain ports/snapshots; stale snapshots перевіряються до paid dispatch. Domain без Prisma; DTO validation — presentation, persistence/mapping — data, cross-slice — aliases/barrels. Prisma sources/SDK змінюються лише під час реалізації, не цього docs task.
Expand, backfill, gate, contract
| Фаза | Умова переходу |
|---|---|
| 1. Expand, flags вимкнені | Org/external/link/session/operation/outbox/payer tables; compatible direct auth, partner default deny |
| 2. Backfill | Existing IDs/owners/plans/payments/subscriptions unchanged; teams→Agentfy; attribution лише з evidence, ambiguous history quarantined |
| 3. Auth/allocation | No-email end-to-end, dual proof, endpoint opt-in, versioned lifecycle sync, atomic bootstrap/owner guard; executable A cases |
| 4. Billing | Обидва v1 modes, provider consent/cutover/reconciliation, retention, hard budget, sponsorship; без paid pilot до passing |
| 5. Pilot | Test namespace потім limited production; measured cancellation/lease, serializers, EN/RU/UK UX/recovery |
| 6. Contract | Retire legacy email assumptions після old clients/tokens і compatible rollback readers |
Окремі flags для provisioning, browser/link, paid billing. Rollback зупиняє issuance/paid dispatch, зберігає actors/links/tombstones/ledger/assignments; committed outbox/provider effects reconciled idempotently. Старі binaries, що не розуміють no-email actor, небезпечні після їх появи: compatible readers або roll forward. Не rollback через merge users/delete history/reuse external IDs.
Нумерований розбір атак і гонок
Очікування дизайну та майбутні executable tests, не passed runtime report.
| ID | Умови / дія | Очікуваний результат | Enforcement / майбутній тест |
|---|---|---|---|
| A01 | Два bootstrap, same key | Один actor/team/owner/assignment/operation | Unique receipt/transaction; concurrent HTTP |
| A02 | Різні keys/expired receipt, same external team | Same fingerprint resumes, changed conflicts; creator не regrant | Permanent mapping; rotation/expiry/retry |
| A03 | Crash після commit до response/outbox | Same operation, без orphan charged team/duplicate agent | Outbox/step idempotency; crash injection |
| A04 | BONSITE key з foreign org/team/agent | Нерозкривна відмова, no read/write | Whole-chain namespace; routes/jobs/search/export |
| A05 | Malicious issuer як linked subject | Лише свої partner rights, без direct/private/other-org/link metadata | Source-bound principal; routes/serializers |
| A06 | Provision key→browser issuance/payer accept | Denied навіть із known IDs | Scopes/independent proof; negative API |
| A07 | Два direct accounts link same subject | Один winner, no account disclosure | Lock/unique; concurrent confirm |
| A08 | Email collision invite/direct/partner | No auto-link/credential claim/retarget | Independent proof/fixed target; forwarded invite |
| A09 | Unsolicited callback/code, wrong browser/PKCE | No session/account replacement | Binding/state/nonce; login-CSRF/leak |
| A10 | Two-tab code redemption/replay/expiry/cancel | Один winner, no other context mutation | Atomic consume/tab context; browser race |
| A11 | Unlink→stale JWT/refresh/socket/download | Derived denied, unrelated independent sessions intact | Epoch/family/proxy; refresh/stream |
| A12 | D→P→other link або partner refresh→direct | No union/source widening | One-hop/immutable source; token/graph |
| A13 | Два owners одночасно demote/remove | Active owner лишається | Team lock/version; transaction race |
| A14 | Revoke last external owner with live agents | Revoke succeeds, team/jobs stop, no arbitrary promote | Lifecycle/owner checks; live cancel |
| A15 | Remove agent owner/transfer без payer consent | Explicit reassign/suspend, payer unchanged | FK/workflow; background/ownership |
| A16 | Cutoff + late usage + duplicate callback | One historical assignment, no duplicate money/invoice | Timeline/occurredAt/dedup; boundary/reorder |
| A17 | Concurrent last-budget reserves/provider timeout | No overspend/premature release | Atomic reservation/reconcile; fault |
| A18 | Sponsor removed while pending payer | Paid only with valid coverage; no owner autocharge | Activation revalidate; sponsor removal |
| A19 | Deleted subject then stale active event | No activation/lease extension by duplicate/stale revision | Monotonic revision/tombstone; replay/reorder |
| A20 | Deleted team bootstrap retry | Tombstone/unavailable, no new team/session | Permanent ID/current state; delete/retry |
| A21 | BONSITE outage/closure, team-paid team | Org work denied, other direct/private intact, no auto-move | Status/subject lease; outage/closure |
| A22 | Issuer compromise with pending codes/links | Revoke proofs, quarantine links, direct credentials intact | Credential/epoch/provenance; incident interval |
| A23 | Old payer lost membership, opens bill | Invoice-only, no team content | Separate payer ACL; invoice auth |
| A24 | Add credentials in empty installation | No extra team/agent/founder | Dedicated flow/founding exclusion; empty install |
| A25 | Delete direct vs unlink vs partner deprovision | Distinct effects, preserve other actor/team/debt, no grant resurrection | Lifecycle/relink integration |
| A26 | Test key/worker/guest token→production user route | Denied despite signature/known ID | Environment/audience/type; matrix |
| A27 | Accept owner transfer after membership/policy change | Reject, no partial demotion | Proof/version; accept/revoke race |
| A28 | State store unavailable/subject lease expired | Fail closed; heartbeat/stale event не поновлює lease | Action gate/fresh subject proof; outage/replay |
| A29 | External owner invites own direct account | Denied, same-namespace external customer actors only | Target policy; deprovision bypass |
| A30 | Org A30+B70, team-paid C20, internal sponsorship | Org invoice100, C20 separately, sponsorship не revenue; same direct payer не об’єднує team bills | Mode/team grouping key; mixed-payer invoice test |
Знайдені та виправлені проблеми
Відкрите питання payer mode замінено вимогою обох у v1. Global merge замінено stable actors. Provisioning відділено від browser issuance; issuer impersonation power визнано явно. Direct invites у partner customer teams заборонені проти deprovision bypass. Last owner не блокує security revoke. Idempotency переживає rotation/expiry без resurrection. Contact/ownership/financial consent розділені; local allocation atomic, remote readiness async. Уточнено service initiator проти owner, subject/code freeze, compromise quarantine, per-subject fresh lease та billable sell-price budget, mixed-payer invoice grouping.
TTL/cutoff/lease — рекомендації, не нові підтверджені рішення. Release gates: provider обох modes, виміряна cancellation/lease, identity verification recovery, retention/legal policy, protocol interoperability. Failed gate блокує capability; «потім» не дозволяє unsafe paid/login path. Cross-org migration, privacy from identity issuer, nested resellers поза v1; closure — authorized export/support, не auto-transfer.
Після виправлень walkthrough не виявляє взаємних суперечностей інваріантів. Дизайн готовий до review з названими gates, не є доказом безпеки чи дозволом випуску runtime.
Перевірка документації
VitePress build, local links/anchors, navigation, EN/RU/UK section/scenario parity. Фактичні make check, app/admin builds, current HTTP startup results записуються в PR. API/app source не змінено, нових runtime test results немає. Пройти direct signup, external-only BONSITE, existing direct link та A01–A30 за контрактами.