Tryb reseller (B2B-z-B2B-z-B2B)
Buduj SaaS / PaaS w którym Twoi klienci mogą sprzedawać Twoją apkę dalej swoim klientom końcowym. WolfieAuth dostarcza prymitywy + SDK.
Tryb reseller — budowa B2B-z-B2B przy użyciu WolfieAuth
TL;DR: każda aplikacja zarejestrowana w WolfieAuth może opt-in włączyć tryb reseller. Po włączeniu admin owner-orga apki może oznaczać organizacje-klientów jako resellery — dostają seat-pack, dedykowany signup-link (i opcjonalnie własną domenę), oraz panel do prowizjonowania własnych end-customer-orgów. Trzy-poziomowa polityka fee dzieli przychód między platformę (Wolfie), owner-orga apki i resellera. SDK w każdym frameworku wystawiają
isResellerOf(),useReseller(), drop-in komponenty + typowanego klienta API — własne admin UI Twojej apki ma potrzebne 5 linii kodu.
Hierarchia
WolfieAuth Platform (Wolfie)
│
│ Stripe Connect onboarding
│ + 5% platform-fee od reseller-subskrypcji
▼
┌──── Owner-org OidcClient-a ─────────┐
│ (Twoja apka, np. acme-cloud) │
│ │
│ Sprzedaje seat-packi resellerom │
│ (Stripe Connect na owner-orgu) │
│ │
└──┬──────────────────────────────┬───┘
│ │
▼ ▼
Reseller-org A Reseller-org B
(Big Reseller Polska) (inny partner)
│ │
│ Rozdaje seaty │
│ end-customer-om │
│ (out-of-band invoicing — │
│ wolfieauth nie pośredniczy │
│ w transakcjach reseller→ │
│ klient) │
▼ ▼
┌─ Bob's Pizza GmbH ┌─ Inny end-customer
├─ Tom's Café └─ ...
└─ Foo's Bar Sp. z o.o.
Trzech aktorów, trzy odpowiedzialności
| Aktor | Co posiada | Co decyduje |
|---|---|---|
| Platforma (Wolfie) | WolfieAuth | Domyślny platform-fee BPS/flat dla wszystkich reseller-subskrypcji; per-app i per-resellerstwo override; emergency suspend |
| Owner-org apki | OidcClient (acme-cloud-product) | Czy w ogóle włączać tryb reseller; które customer-orgi zostają resellerami; seat-limity; per-reseller fee; signup-tokeny; custom domeny |
| Reseller-org | Swoja seat-pack subskrypcja + child-orgi | Których end-customerów provisionować (w limicie); kiedy ich suspendować; czy fakturować out-of-band |
Trzy-poziomowa polityka fee
WolfieAuth rozwiązuje per-payment fee tą hierarchią (najściślejszy wygrywa):
- Per-resellerstwo override (
AppReseller.platformFeeBpsOverride) — Wolfie umówił się ze konkretnym resellerem. - Per-app override (
OidcClient.platformResellerFeeBpsOverride) — Wolfie umówił się z owner-orgiem (np. Acme Cloud ma 7% zamiast 5%). - Platform default (
PlatformConfig.platformResellerFeeBps) — globalny default Wolfie, 500 bps (5%) z pudełka.
Owner-org-owe fee na seat-pack subskrypcji (cena którą reseller płaci za pakiet) siedzi osobno w OidcClient.resellerFeeBps / AppReseller.feeBps. Oba fee aplikuje się addytywnie — reseller płaci cenę seat-pack-a (= revenue owner-orga) + niewielki kawałek platform-fee który idzie do Wolfie.
Checklist setupu (admin owner-orga)
- Otwórz
/admin/clients/<your-app-id>→ zakładka Overview. - Włącz toggle 🤝 Tryb reseller / Reseller mode. Zapisz.
- Pojawi się nowa zakładka Resellers.
- Ustaw default
resellerFeeBps/resellerFeeFlatCents(lub zostaw 0 dla “darmowych seat-packów”). - Klik + Dodaj resellera, wybierz customer-orgę z dropdown-a, ustaw seat-limit. Generuje się signup-token i pokazuje raz — skopiuj go.
- (Opcjonalnie) Ustaw custom domenę dla resellera (np.
cloud.acme.com). Dodaj wskazany TXT record, klik ✓ Verify, gotowe. - Przekaż signup-token (lub URL custom-domeny) resellerowi.
Co się zmienia dla end-customera resellera
User rejestrując się przez:
https://auth.wolfieguard.com/signup?client_id=acme-cloud-product&reseller_token=<token>
…lub przez verified custom domain:
https://cloud.acme.com/signup?client_id=acme-cloud-product
…dostaje świeży Organization row z parentId = <orgId-resellera>. Jego OIDC tokeny niosą:
wolfieauth_org_parentId = "<reseller-orgId>"(apki rozpoznają że ten end-customer jest “pod” resellerem)wolfieauth_org_id= id nowo utworzonej child-orgi (jego własny scope danych)
Adminowie resellera logują się do admin UI owner-orga (Twojej apki — np. Acme Cloud admin panel zbudowany z SDK helpery poniżej). Ich tokeny niosą:
wolfieauth_reseller_apps[]=[{ client_id: "acme-cloud-product", org_id: "<reseller-orgId>", seat_limit: 100, seats_allocated: 17, status: "ACTIVE" }]
To jest mechanizm gating — Twoja apka czyta claim i pokazuje panel “Reseller portfolio”.
Wpięcie panelu w aplikacji — per SDK
React / Next.js
import { RequireResellerAdmin, ResellerChildrenTable, useReseller } from "@wolfieauth/sdk-react";
// Drop-in (działa od ręki):
<RequireResellerAdmin clientId="acme-cloud-product"
fallback={<p>Strona dla reseller-adminów.</p>}>
<ResellerChildrenTable clientId="acme-cloud-product" />
</RequireResellerAdmin>
// Albo własne UI z hook-a:
function MyResellerDashboard() {
const { isReseller, resellership, children, billing,
provisionChild, suspendChild } = useReseller("acme-cloud-product");
if (!isReseller) return null;
return <div>{resellership.seats_allocated}/{resellership.seat_limit} seats — …</div>;
}
Hook oczekuje że Twoja apka wystawi proxy pod /api/wolfieauth/resellers/... które forwarduje do auth.wolfieguard.com/api/admin/resellers/... z OIDC bearer-em. SDK middleware (handle.ts w SvelteKit, middleware w Next.js) zwykle ma już ten wzorzec — sprawdź per-stack guide.
SvelteKit
// +page.server.ts
import { loadResellerContext } from "@wolfieauth/sdk-sveltekit/server";
export const load = async ({ locals, fetch }) => {
const reseller = await loadResellerContext({
claims: locals.session?.claims ?? null,
clientId: "acme-cloud-product",
fetch,
});
return { reseller };
};
<!-- +page.svelte -->
<script>
let { data } = $props();
</script>
{#if data.reseller.isReseller}
<h1>Twoi klienci ({data.reseller.children.length})</h1>
{#each data.reseller.children as c}
<div>{c.name} — {c._count.members} userów</div>
{/each}
{/if}
Laravel / PHP
use WolfieAuth\Sdk\Resellers\Resellers;
public function dashboard(Request $request)
{
$claims = $request->attributes->get('wolfieauth')['claims'] ?? null;
if (!Resellers::isResellerOf($claims, 'acme-cloud-product')) {
abort(403);
}
$seats = Resellers::getResellerSeatStatus($claims, 'acme-cloud-product');
return view('reseller.dashboard', compact('seats'));
}
W Blade:
@if(\WolfieAuth\Sdk\Resellers\Resellers::isResellerOf($wolfieauth['claims'], 'acme-cloud-product'))
<a href="/reseller">Zarządzaj swoimi klientami</a>
@endif
Django / DRF
from wolfieauth.resellers import IsResellerAdmin, is_reseller_of, wolfieauth_reseller_admin
# DRF
class ResellerDashboard(APIView):
permission_classes = [IsResellerAdmin("acme-cloud-product")]
def get(self, request):
...
# Plain Django
@wolfieauth_reseller_admin("acme-cloud-product")
def reseller_dashboard(request):
...
Budowanie “PaaS-z-PaaS” przy użyciu WolfieAuth
Mając te prymitywy, szerszy wzorzec to: wszystko co budujesz na WolfieAuth może być multi-tier SaaS-em. Przykłady:
- WolfieCloud (managed hosting): Wolfie prowadzi platformę; resellery to agencje pakujące hosting dla swoich klientów; end-customery to klienci agencji (każdy ma własną orgę z własną bazą, mailboxami itp.)
- Branżowy CRM (np. CRM dla gabinetów dentystycznych): Wolfie prowadzi WolfieAuth; owner-org platformy sprzedaje “Dental Network” seat-pack dużym network operator-om; każdy network ma reseller-status pozwalający spawnować orgę per gabinet; staff każdego gabinetu loguje się przez branded subdomenę network-a.
- White-label e-learning: Ten sam wzorzec — corporate trainers kupują seat-packi i rozdają dostęp swoim “kursantom” w osobnych org-ach.
Kombinacja:
- per-OidcClient theme + reseller-scoped
defaultChildThemecascade, - per-org Stripe Connect dla owner-orga,
- per-resellerstwo signup tokenów + opcjonalnie custom domeny,
- gating przez claim-y w SDK,
oznacza że operator platformy nie musi pisać trzech warstw kodu żeby wspierać B2B-z-B2B-z-B2C — WolfieAuth ogarnie tożsamość, branding, fee, seaty i lifecycle. Twoja apka skupia się tylko na swoim produkcie.
Ograniczenia / caveats
- Sub-resellery (3+ poziomy w głąb) są gated przez
AppReseller.allowSubResellersi włącza je tylko SUPER_ADMIN platformy. Większość przypadków to płaska hierarchia: platforma → reseller → end-customer. - Każdy reseller-org potrzebuje własnego Stripe Connect konta jeśli chce fakturować swoich end-customerów przez WolfieAuth — ale transakcje reseller → end-customer są poza scope billingu WolfieAuth (reseller fakturuje swoich klientów sam, np. przez własne wolfiecrm). WolfieAuth tracking tylko seat-pack subskrypcję (reseller → owner-org).
- KSeF dla reseller → end-customer jest odpowiedzialnością resellera — jego wolfiecrm albo zewnętrzna księgowość.
Ostatnia aktualizacja: