Web razvoj
Next.jsSaaSOnboardingAutentikacijaStripeEmailRBACApp Router

Next.js SaaS kontrolna lista za onboarding: računi, dozvole, emailovi i probni periodi (App Router, 2026.)

AO
Adrijan Omićević
·16 min čitanja

# Što ćete izgraditi#

Ovaj vodič je praktična kontrolna lista za onboarding Next.js SaaS aplikacije za produkcijski spreman tok u Next.js App Routeru. Fokusira se na ono što se u stvarnim proizvodima najčešće lomi: računi, organizacije, uloge, pozivnice, transakcijski emailovi i konverzija iz probnog u plaćeni plan.

Ako želite dublji kontekst o povezanoj arhitekturi i detaljima naplate, ovi tekstovi nadopunjuju ovu kontrolnu listu:

Zašto onboarding zaslužuje inženjersko vrijeme#

Mala poboljšanja se zbrajaju. Industrijski benchmarkovi tipično pokazuju da 20 do 40 posto prijava u B2B SaaS-u nikad ne dođe do aktivacijskog događaja, a trenje u onboardingu je jedan od glavnih razloga. Tretirajte onboarding kao ključnu površinu proizvoda: mjerite ga, testirajte i učinite robusnim.


# Mapa onboarding toka i metrike uspjeha#

Prije implementacije definirajte korake lijevka i što znači “gotovo”. Uobičajeni B2B SaaS onboarding lijevak:

  1. 1
    Kreiraj račun
  2. 2
    Verificiraj email
  3. 3
    Kreiraj ili se pridruži organizaciji
  4. 4
    Dovrši postavljanje workspacea
  5. 5
    Pozovi članove tima
  6. 6
    Ostvari prvi “value” događaj
  7. 7
    Započni probni period
  8. 8
    Konvertiraj u plaćeno

Pratite nekoliko ključnih metrika po koraku, ne samo ukupne konverzije.

Korak lijevkaDogađaj “uspjeha”Što pratitiCiljano vrijeme
Prijavauser_createdKorišteni provider, uređaj, referrerOdmah
Verifikacijaemail_verifiedVrijeme do verifikacije, bounce stopaIspod 10 minuta
Postavljanje orgaorg_created ili org_joinedOdustajanje, vrijeme do završetkaIspod 2 minute
Prva vrijednostactivatedKoja značajka je aktiviralaIsta sesija
Start probnogtrial_startedTrajanje probnog, segmentIsti dan
Checkoutcheckout_startedPlan, cijena, broj seatovaTijekom probnog
Plaćenosubscription_activeMRR, signali rizika churn-aPrije kraja probnog

ℹ️ Napomena: Rano odlučite koji je vaš aktivacijski događaj. Npr. “kreiran prvi projekt” ili “povezana prva integracija” bolje korelira s retencijom nego “posjećen dashboard”.


# Kontrolna lista jezgre podatkovnog modela za Multi-Tenant SaaS#

Vaš onboarding tok ograničen je podatkovnim modelom. Neka bude jednostavan i eksplicitan.

Minimalne tablice i odnosi#

EntitetKljučna poljaNapomene
usersid, email, name, emailVerifiedAtAuth provider može dio ovoga spremati
organizationsid, name, slug, createdByUserIdSlug pomaže za URL-ove i domene pozivnica
membershipsuserId, orgId, role, statusUnique index na userId + orgId
invitesid, orgId, email, role, tokenHash, expiresAt, acceptedAtNikad ne spremati raw tokene
subscriptionsorgId, stripeCustomerId, stripeSubscriptionId, status, currentPeriodEndTretirati kao server-truth cache
entitlementsorgId, featureKey, value, source, updatedAtOpcionalno, ali moćno za gating

Preporučeni obrasci#

  • Sve je scoped na org: projekti, računi, API ključevi, zapisi potrošnje.
  • Status membershipa: active, invited, removed. Izbjegavajte brisanje redaka jer gubite auditabilnost.
  • Entitlements umjesto provjera plana: ograničavajte značajke preko featureKey i vrijednosti poput seats=5, api_requests=100000.

💡 Savjet: Ako kasnije očekujete enterprise značajke, dodajte role kao string enum i implementirajte provjere dozvola kroz centraliziranu policy funkciju. Izbjeći ćete refaktoriranje desetaka UI provjera.


# Autentikacija i kreiranje računa (App Router)#

Odaberite auth stack koji odgovara vašoj brzini isporuke i potrebama usklađenosti. Ključna stvar je kako auth integrirate u onboarding korake.

Odabir auth providera (brza tablica odluke)#

ZahtjevClerkSupabase AuthNextAuth
Najbrže do produkcijeJakoSrednjeSrednje
Ugrađene organizacije i pozivniceJakoSlaboSlabo
Potpuna kontrola nad DB-omSrednjeJakoJako
SSR i ergonomija u App RouteruJakoJakoSrednje
Enterprise SSO kasnijeJakoSrednjeSrednje

Za dublju usporedbu i postavljanje, koristite: Vodič za Next.js autentikaciju: NextAuth vs Clerk vs Supabase

Kontrolna lista: kreiranje računa#

  • Koristite server-side provjere sesije u server komponentama i route handlerima.
  • Za B2B proizvode zahtijevajte verifikaciju emaila osim ako nemate vrlo jak razlog da ne.
  • Normalizirajte i spremite email u lowercase radi jedinstvenosti.
  • Obradite OAuth račune koji možda nemaju verificiran email ovisno o provideru.
  • Kreirajte user redak pri prvom loginu preko webhooka ili callbacka, ne na klijentu.

App Router guard obrazac#

Koristite server-side guard za onboarding korake kako biste izbjegli “flash pogrešne stranice” i client bypass.

TypeScript
// app/(app)/onboarding/page.tsx
import { redirect } from "next/navigation";
 
export default async function OnboardingPage() {
  const user = await getCurrentUser(); // server-side
  if (!user) redirect("/sign-in");
 
  const org = await getActiveOrgForUser(user.id);
  if (org) redirect(`/app/${org.slug}`);
 
  return <OnboardingWizard />;
}

Ovaj obrazac sprječava korisnike da preskoče onboarding tako da direktno posjete URL-ove.


# Kreiranje organizacije i postavljanje workspacea#

Većina SaaS proizvoda nije zauvijek single-user. Čak i ako krenete s “personal accounts”, B2B kupci će brzo tražiti timove i vlasništvo nad naplatom.

Kontrolna lista: korak kreiranja organizacije#

  • Omogućite putanje kreiraj org i pridruži se orgu.
  • Osigurajte jedinstven slug i validirajte pravila imenovanja.
  • Kreirajte prvi membership kao owner.
  • Odlučite može li jedan user pripadati više orgova i podržite prebacivanje orgova.
  • Persistirajte activeOrgId u cookie ili profilno polje, ali ga validirajte server-side.

Uobičajen UI tok#

  • Korak 1: Naziv organizacije i slug
  • Korak 2: Opcionalni workspace defaulti (timezone, industrija, predložak)
  • Korak 3: Pozovi članove tima

Neka prvi korak bude minimalan. Svako dodatno polje smanjuje konverzije.

⚠️ Upozorenje: Nemojte spremati autorizacijsko stanje poput role=owner u local storage i tretirati ga kao istinu. Uloge uvijek rješavajte iz baze na serveru.


# Uloge i dozvole (RBAC) koje stvarno možete održavati#

RBAC je lako započeti, a lako i pokvariti kad značajke rastu. Koristite jednostavan skup uloga i centralno derivirajte dozvole.

Preporučene osnovne uloge#

UlogaTipične dozvoleTko je dobiva
ownernaplata, upravljanje korisnicima, brisanje orgaOsnivač, billing admin
adminupravljanje postavkama, upravljanje korisnicima, bez brisanja naplateVoditelj tima
memberkorištenje značajki proizvodaVećina korisnika
viewersamo čitanjeFinance, stakeholderi

Funkcija policyja za dozvole#

Centralizirajte logiku dozvola kako ne biste posvuda imali if role === ....

TypeScript
// lib/authz.ts
export type Role = "owner" | "admin" | "member" | "viewer";
 
export function can(role: Role, action: string) {
  const rules: Record<Role, string[]> = {
    owner: ["billing:write", "users:write", "org:delete", "app:use"],
    admin: ["users:write", "settings:write", "app:use"],
    member: ["app:use"],
    viewer: ["app:read"],
  };
  return rules[role]?.includes(action) ?? false;
}

Koristite ovo u route handlerima i server actions za provođenje pristupa.

Kontrolna lista: RBAC implementacija#

  • RBAC provodite u server kodu, ne samo u UI-u.
  • Neka svaki write endpoint zahtijeva org kontekst.
  • Dodajte audit trail za osjetljive akcije: promjene uloga, promjene naplate, brisanja.
  • Spriječite ownera da ukloni zadnjeg ownera.
  • Logirajte authorization failure s org i user identifikatorima.

# Team pozivnice koje ne pucaju (tokeni, istek, idempotencija)#

Pozivnice su mjesto gdje mnogi SaaS proizvodi propuštaju sigurnost. Tretirajte pozivnice kao linkove za reset lozinke.

Pregled toka pozivnice#

  1. 1
    Admin upisuje email i ulogu.
  2. 2
    Server kreira invite s expiresAt i tokenHash.
  3. 3
    Šalje se email koji sadrži raw token u URL-u.
  4. 4
    Primatelj klikne link, prijavi se i prihvati pozivnicu.
  5. 5
    Server verificira token hash i istek, zatim kreira membership.

Kontrolna lista: sigurna implementacija pozivnica#

  • Spremite samo hashirani token, nikad raw token.
  • Uključite expiresAt (često 7 dana).
  • Accept endpoint učinite idempotentnim: klik dvaput ne smije kreirati duplikate.
  • Ako membership već postoji, pretvorite pozivnicu u UX “pridruži se postojećem”.
  • Invalidirajte pozivnice nakon prihvaćanja postavljanjem acceptedAt.

Generiranje tokena i hashiranje#

TypeScript
// lib/invites.ts
import crypto from "crypto";
 
export function generateInviteToken() {
  const token = crypto.randomBytes(32).toString("hex");
  const tokenHash = crypto.createHash("sha256").update(token).digest("hex");
  return { token, tokenHash };
}

Prihvat pozivnice u route handleru#

TypeScript
// app/api/invites/accept/route.ts
import { NextResponse } from "next/server";
 
export async function POST(req: Request) {
  const { token } = await req.json();
  const user = await getCurrentUser();
  if (!user) return NextResponse.json({ error: "unauthorized" }, { status: 401 });
 
  const tokenHash = sha256(token);
  const invite = await db.invite.findValidByHash(tokenHash);
  if (!invite) return NextResponse.json({ error: "invalid" }, { status: 400 });
 
  await db.membership.upsert({
    userId: user.id,
    orgId: invite.orgId,
    role: invite.role,
  });
 
  await db.invite.markAccepted(invite.id);
  return NextResponse.json({ ok: true });
}

Ako je moguće, DB operacije držite transakcijskima.

💡 Savjet: Dodajte gumb “ponovno pošalji pozivnicu” koji kreira novi token i invalidira stari invite. Ponovno slanje istog tokena povećava rizik curenja linka u shared inboxovima.


# Transakcijski emailovi: verifikacija, pozivnice, trial događaji i računi#

Email je dio onboardinga, ne marketing. Ako korisnici ne primaju poruke, onboarding se lomi.

Preporučeni email stack#

PotrebaOpcijaZašto
Slanje emailova preko API-jaResend, Postmark, SendGridPouzdana dostavljivost i webhooks
PredlošciReact Email ili MJMLPredlošci u kodu s verzioniranjem
Inbound događajiProvider webhooksBounce, complaints, delivery

Vrste emailova koje biste trebali rano implementirati#

EmailOkidačKritična polja
Verificiraj emailsign-upverification URL, istek
Poziv u workspaceinvite creatednaziv orga, uloga, accept URL, istek
Probni period započeopočetak trialadatum završetka triala, sljedeći korak
Probni period uskoro završava3 dana prije krajaCTA za upgrade, što se dalje događa
Uspješna uplatainvoice paidlink na račun, plan, iznos

Kontrolna lista: pouzdanost transakcijskih emailova#

  • Konfigurirajte SPF, DKIM i DMARC za svoju domenu.
  • Koristite dedicated sending domenu poput mail.yourapp.com.
  • Kroz provider webhooks označite emailove kao bounced ili complained.
  • Ne šaljite onboarding emailove iz client koda.
  • Uključite plain-text fallback i izbjegavajte spammy naslove.

# Logika probnog perioda i feature gating u Next.js-u#

Probni periodi postaju kaos kad se “trial” tretira kao UI labela. Implementirajte ga kao stanje plus entitlements.

Model stanja probnog perioda#

Trial možete implementirati u svojoj bazi ili isključivo u Stripeu. U praksi timovi često koriste oboje:

  • Stripe pretplata s probnim periodom radi točnosti naplate.
  • DB polje radi onboarding UX-a, praćenja i internih overrideova.
PoljePrimjerSource of Truth
trialEndsAt2026-07-07T00:00:00ZStripe, preslikano u DB
subscriptionStatustrialing, active, past_dueStripe
entitlementsseats=5, exports=trueDerivirano iz Stripea i internih pravila

Kontrolna lista: feature gating koji preživljava edge caseove#

  • Ograničavajte server-side u route handlerima i server actions.
  • Koristite entitlements poput exports=true umjesto plan=pro.
  • past_due tretirajte kao “ograničen pristup” ili “samo čitanje”, ne instant lockout.
  • Pažljivo s vremenskim zonama, uvijek spremajte timestampove u UTC.
  • Cacheajte entitlements po orgu s kratkim TTL-om, ali omogućite trenutno osvježenje nakon webhook događaja.

⚠️ Upozorenje: Ako trial status provjeravate samo na klijentu, korisnici mogu zaobići ograničenja direktnim pozivima API-ja. Svi paid gateovi moraju se provoditi server-side.


# Konverzija iz probnog u plaćeni plan uz Stripe (Checkout, webhooks i pristup)#

Upgrade tok treba biti bez trenja i determinističan. Najčešći produkcijski incident je “korisnik je platio, ali je i dalje zaključan”, uzrokovan izostankom webhook obrade ili pogrešnim mapiranjem orga.

Za dublju implementaciju naplate, koristite: Next.js Stripe pretplate: SaaS naplata

Kontrolna lista: kreiranje Checkout sessiona#

  • Kreirajte Checkout sessione server-side.
  • U Stripe metadata uvijek proslijedite orgId.
  • Koristite stabilan customerId po orgu kako bi fakture i payment metode bile centralizirane.
  • Odlučite naplaćujete li po seat-u i uskladite s brojem membershipa.
  • Nakon uspjeha redirectajte na stranicu koja poll-a za refresh entitlements.

Primjer Stripe metadata#

TypeScript
// app/api/billing/checkout/route.ts
export async function POST() {
  const { orgId } = await requireOrgContext();
 
  const session = await stripe.checkout.sessions.create({
    mode: "subscription",
    customer: await getOrCreateStripeCustomerId(orgId),
    line_items: [{ price: process.env.STRIPE_PRICE_ID!, quantity: 1 }],
    success_url: `${process.env.APP_URL}/billing/success`,
    cancel_url: `${process.env.APP_URL}/billing`,
    metadata: { orgId },
  });
 
  return Response.json({ url: session.url });
}

Kontrolna lista za webhooks (nepregovorno)#

  • Verificirajte Stripe webhook signature.
  • Obradite događaje idempotentno koristeći event ID-ove.
  • Ažurirajte svoju subscriptions cache tablicu i ponovno izračunajte entitlements.
  • Razmotrite checkout.session.completed, customer.subscription.updated, invoice.paid, invoice.payment_failed.
  • Nikad se ne oslanjajte samo na success redirect.

Obrazac idempotencije webhooks#

TypeScript
// app/api/stripe/webhook/route.ts
export async function POST(req: Request) {
  const body = await req.text();
  const sig = req.headers.get("stripe-signature")!;
  const event = stripe.webhooks.constructEvent(
    body,
    sig,
    process.env.STRIPE_WEBHOOK_SECRET!
  );
 
  const already = await db.webhookEvents.exists(event.id);
  if (already) return new Response("ok");
 
  await db.webhookEvents.insert({ id: event.id, type: event.type });
 
  await handleStripeEvent(event);
  return new Response("ok");
}

Neka handler bude mali i delegirajte po tipu događaja.


# Onboarding UX u App Routeru: koraci, redirecti i server actions#

Želite da onboarding bude gladak, ali i ispravan pod refreshima i korištenjem više tabova.

Preporučeni pristup#

  • Spremite onboarding napredak server-side kao onboardingState po useru ili membershipu.
  • Redirectajte sa servera na temelju trenutnog stanja.
  • Koristite server actions za slanje koraka kako biste smanjili API boilerplate.

Jednostavan onboarding state machine#

StanjeZnačenjeSljedeći korak
needs_orgnema membership u orgukreiraj ili se pridruži orgu
needs_profilenedostaju obavezna profilna poljaprofil forma
needs_invitesnije pozvan nijedan teammateekran pozivnica
activatedostvaren prvi valueglavna aplikacija

Kontrolna lista: App Router onboarding mehanika#

  • Svaka ruta koraka treba biti direktno posjetiva i server-guardana.
  • Nakon slanja forme ažurirajte stanje i redirectajte na sljedeći korak.
  • Nikad ne računajte “trenutni org” iz client statea bez server-side provjere.
  • Držite forme otporne na refresh, retry i mrežne greške.

🎯 Ključna poruka: Onboarding treba biti serverom provedena state mašina, ne client wizard s best-effort redirectima.


# Observabilnost: mjerite odustajanje i debuggajte korisničke prijave#

Onboarding je “gotov” tek kad možete objasniti što se dogodilo za specifičnog usera i org.

Što instrumentirati#

  • Funnel događaje: sign-up, verify, org created, invite sent, invite accepted, checkout started, subscription active.
  • Latenciju: vrijeme od sign-upa do aktivacije, vrijeme od starta triala do checkouta.
  • Error rateove na kritičnim endpointima: accept pozivnice, kreiranje checkouta, obrada webhookova.

Praktična kontrolna lista#

  • Dodajte strukturirane logove s userId, orgId, requestId.
  • Pratite onboarding događaje product analytics alatom ili vlastitom tablicom.
  • Alertajte na Stripe webhook failure i backlog.
  • Spremite događaje dostave emaila i bounceove za invite emailove.

# Uobičajene zamke (i kako ih izbjeći)#

Ovi problemi se stalno pojavljuju u produkcijskim Next.js SaaS implementacijama.

Zamka 1: Miješanje user naplate i org naplate#

Ako jedan user pripada više orgova, naplata mora biti u vlasništvu orga ili ne možete čisto prebaciti vlasništvo.

Rješenje: spremite stripeCustomerId i subscription zapise na orgId, ne na userId.

Zamka 2: Slaba sigurnost pozivnica#

Plain tokeni spremljeni u bazi cure kroz logove, backupove i admin dashboarde.

Rješenje: spremite hash tokene, dodajte istek i invalidirajte na resend.

Zamka 3: Autorizacija samo na klijentu#

Ako sakrijete gumbe, ali dopustite API pristup, korisnici će i dalje izvršavati akcije.

Rješenje: provodite provjere dozvola u route handlerima, server actions i svim background jobovima.

Zamka 4: Ne-idempotentni webhookovi#

Stripe ponavlja evente. Ako kreirate više pretplata ili krivo prepišete stanje, pristup će se nasumično “prebacivati”.

Rješenje: spremite event ID-ove i učinite handlere sigurnima za ponovnu obradu.

Zamka 5: Trial gateovi temeljeni na nazivima planova#

Nazivi planova se mijenjaju, promocije se događaju, postoje enterprise overrideovi.

Rješenje: ograničavajte po entitlementima i zadržite jedan resolver za entitlements.


# Preporučene biblioteke i obrasci (2026.)#

Koristite provjerene, održavane alate. Izbjegavajte pisanje vlastitih security-critical primitiva.

PodručjePreporučene opcijeNapomene
AuthClerk, Supabase Auth, NextAuthOdaberite prema kontroli vs brzini
DB ORMPrisma, DrizzleKoristite migracije i unique constraintove
EmailoviResend, PostmarkDodajte domain auth i webhooks
PlaćanjaStripeWebhooks i idempotencija su obavezni
ValidacijaZodValidirajte inpute u server actions
Rate limitingUpstash, CloudflareZaštitite pozivnice i auth endpointove
ObservabilnostSentry, OpenTelemetryHvatajte onboarding greške

Za obrasce strukturiranja multi-tenant aplikacije koji utječu na onboarding i RBAC, pogledajte: Vodič za multitenant SaaS arhitekturu u Next.js-u


# Ključne poruke#

  • Implementirajte onboarding kao serverom provedenu state mašinu sa server-side redirectima u App Routeru.
  • Modelirajte multi-tenancy eksplicitno s organizations, memberships i invites, i uvijek scopeajte writeove na org.
  • Osigurajte team pozivnice s hashiranim tokenima, istekom i idempotentnim prihvatom, te logirajte svaku promjenu membershipa.
  • Ograničavajte plaćene značajke preko entitlements i provodite pristup server-side u route handlerima i server actions.
  • Učinite trial-to-paid pouzdanim uz Stripe metadata mapiranje na orgId i idempotentnu obradu webhookova.

# Zaključak#

Produkcijski spreman onboarding tok u Next.js-u nije samo sign-up forma. To je koordiniran sustav identiteta, org konteksta, dozvola, isporuke emaila i billing stanja koji mora ostati ispravan kroz retry, refresh i edge caseove.

Ako želite da Samioda implementira ili auditira vaš onboarding end-to-end, uključujući App Router guardove, org RBAC, transakcijske emailove i Stripe konverziju iz probnog u plaćeni plan, kontaktirajte nas i mi ćemo mapirati vaš funnel, isporučiti kontrolnu listu i instrumentirati metrike koje pomiču aktivaciju i prihod.

FAQ

Share
A
Adrijan OmićevićOsnivač i senior developer

Osnivač i senior developer u Samiodi. 8+ godina iskustva u izradi React, Next.js, Flutter i n8n rješenja za klijente diljem Europe.

Trebate pomoć s projektom?

Gradimo prilagođena rješenja koristeći tehnologije iz ovog članka. Senior tim, fiksne cijene.