User Onboarding Flow
Architecture documentation — complete user onboarding journey from sign-up to first API key, including team creation, project setup, and documentation links strategy.
This document explains the complete user onboarding and getting-started flow in OptStuff Dashboard — from sign-up to having a working API key.
Overview
When a new user signs up for OptStuff, they go through a streamlined journey:
- Create a personal team — Required before accessing the dashboard
- Create a project — Configure image sources, get a default API key automatically
- Copy their API key — Shown immediately in the project creation dialog
- Integrate — Documentation links are provided at every step
Phase 1: Team Creation (Onboarding)
Key Concepts
Personal Team
| Property | Description |
|---|---|
| Unique per user | Each user has exactly one personal team |
| Required | Users cannot access the dashboard without a personal team |
| Non-deletable | Personal teams cannot be deleted |
| Extensible | Users can create additional (non-personal) teams later |
Team Slug
The slug is the URL identifier for a team (e.g., optstuff.com/my-team).
| Rule | Description |
|---|---|
| Length | 3–50 characters |
| Characters | Lowercase letters (a-z), numbers (0-9), hyphens (-) |
| Format | Must start and end with a letter or number |
| Uniqueness | Globally unique across all teams |
User Journey
1. Sign Up / Sign In
User authenticates via Clerk (email, Google, GitHub, etc.).
2. Redirect Decision
After authentication, the system checks if the user has a personal team:
- No personal team → Redirect to
/onboarding - Has personal team → Redirect to
/[team-slug]dashboard
3. Onboarding Page
The onboarding page:
- Pre-fills a suggested team name based on user profile (e.g., "John's Team")
- Auto-generates a slug from the team name
- Shows real-time slug availability feedback
- Provides a "randomize" button for generating a random slug
4. Team Creation
When the user submits the form:
- Validates team name (1–255 characters)
- Validates slug format and length
- Checks slug availability (must be unique)
- Creates the personal team record in database
- Redirects to the new team's dashboard
Error Scenarios
| Scenario | Behavior |
|---|---|
| Slug already taken | Show error, user must choose different slug |
| Invalid slug format | Show validation error with format requirements |
| User already has personal team | In normal navigation they are redirected before onboarding; race-condition submit returns an explicit error |
| Network error | Show generic error, allow retry |
Phase 2: Project Creation (with Default API Key)
After landing on the team dashboard, new users see an empty state prompting them to create their first project.
CreateProjectDialog — Two-Step Flow
The dialog uses a two-step pattern (form → success):
Step 1: Form
- Project Name (required)
- Description (optional)
- Image Sources — where original images are hosted (e.g.,
https://images.unsplash.com,https://cdn.mysite.com). Subdomains are included automatically. - Authorized Websites (optional) — which websites can display optimized images. Leave empty to allow all. These can be configured later in Settings.
- Submit creates the project and a default API key automatically
Step 2: Success (API Key Display)
After project creation, the dialog transitions to a success screen showing:
- Success header — "Project Created" with project name
- Warning banner — "Copy and add these to your
.envfile before closing. The secret key is only shown once." - Combined env block — Variables shown in
.envformat (OPTSTUFF_BASE_URL,OPTSTUFF_PROJECT_SLUG,OPTSTUFF_SECRET_KEY,OPTSTUFF_PUBLIC_KEY) with one copy button. The preview masks the secret, but copy payload includes plaintext. - Next Steps — Link to Integration Guide on the docs site
- Done button — Navigates to the new project's overview page
The copy button copies both keys together with their environment variable names, ready to paste into a .env file:
OPTSTUFF_SECRET_KEY="sk_..."
OPTSTUFF_PUBLIC_KEY="pk_..."The dialog is locked during the success step:
- Close button is hidden
- ESC key is disabled
- Clicking outside does not close
This ensures users see and copy their keys before proceeding.
Setup Checklist
After project creation, the Overview tab shows a setup checklist if configuration is incomplete:
- Configure image sources (link to Settings)
- API key ready
The checklist disappears once all steps are completed.
Backend Behavior
The project.create tRPC mutation:
- Creates the project record (with
allowedSourceDomainsandallowedRefererDomainsif provided) - Generates a default API key pair (public + secret)
- Encrypts the secret key (AES-256-GCM) before storing
- Returns the project data along with
defaultApiKeyanddefaultSecretKey
Documentation Links Strategy
Environment Variable
The docs site base URL is configured via the NEXT_PUBLIC_DOCS_URL environment variable:
# .env or .env.local
NEXT_PUBLIC_DOCS_URL="http://localhost:3002"- Validated in
src/env.jsvia@t3-oss/env-nextjswith Zod (z.string().url()) - Required — validation will fail if
NEXT_PUBLIC_DOCS_URLis missing or empty - Different environments can point to different docs sites (e.g., localhost for dev)
Centralized Link Object
All documentation links are derived from the env var in src/lib/constants.ts:
import { env } from "@/env";
/** Centralized documentation links — driven by `NEXT_PUBLIC_DOCS_URL` env var */
export const DOCS_LINKS = {
home: env.NEXT_PUBLIC_DOCS_URL,
quickstart: `${env.NEXT_PUBLIC_DOCS_URL}/getting-started/quickstart`,
integration: `${env.NEXT_PUBLIC_DOCS_URL}/getting-started/integrate-nextjs`,
keyManagement: `${env.NEXT_PUBLIC_DOCS_URL}/guides/key-management`,
security: `${env.NEXT_PUBLIC_DOCS_URL}/guides/security-best-practices`,
urlSigning: `${env.NEXT_PUBLIC_DOCS_URL}/guides/url-signing`,
codeExamples: `${env.NEXT_PUBLIC_DOCS_URL}/guides/code-examples`,
cdnCaching: `${env.NEXT_PUBLIC_DOCS_URL}/guides/cdn-caching`,
pricing: `${env.NEXT_PUBLIC_DOCS_URL}/introduction/cost-analysis`,
faq: `${env.NEXT_PUBLIC_DOCS_URL}/faq`,
changelog: `${env.NEXT_PUBLIC_DOCS_URL}/changelog`,
} as const;To change the docs URL, update NEXT_PUBLIC_DOCS_URL in the environment — no code changes needed.
Where Documentation Links Appear
| Location | Link Target | Context |
|---|---|---|
| Header (BookOpen icon) | Home | Always visible, global navigation |
| EmptyProjectState | Getting Started guide | When user has no projects |
| EmptyApiKeyState | API Keys guide | When a project has no API keys |
| CreateProjectDialog (success) | Integration Guide | After creating a project + default key |
| CreateApiKeyDialog (success) | Integration Guide | After creating an additional API key |
| Overview Tab (setup checklist) | Settings tab | Incomplete setup step links to domain/security settings |
| Overview Tab (resource cards) | Project Setup + Integration guides | Persistent quick links in project overview |
Design Principles
- Docs site is the primary teaching medium — The dashboard itself does not try to be a tutorial
- Dashboard provides escape hatches — When users are unsure, clear links point them to docs
- No third-party tour libraries — Native components keep the experience consistent
- No intrusive overlays — Links are available but don't block the user's workflow
Related Files
| File | Purpose |
|---|---|
src/env.js | NEXT_PUBLIC_DOCS_URL environment variable definition |
src/lib/constants.ts | DOCS_LINKS centralized documentation URL builder |
src/app/onboarding/page.tsx | Onboarding page component |
src/modules/onboarding/ui/components/onboarding-form.tsx | Team creation form with validation |
src/modules/team/ui/components/create-project-dialog.tsx | Two-step project creation dialog (form → API key display) |
src/modules/team/ui/components/project-list.tsx | Project list with empty state + docs link |
src/modules/project-detail/ui/components/create-api-key-dialog.tsx | API key creation dialog with docs link |
src/modules/project-detail/ui/components/api-key-skeleton.tsx | Empty API key state with docs link |
src/modules/project-detail/ui/views/overview-tab.tsx | Project overview (endpoint info + setup checklist + stats) |
src/server/api/routers/project.ts | Backend project + default API key creation |
src/server/api/routers/team.ts | Backend team creation logic |
src/lib/slug.ts | Slug generation utilities |
src/app/[team]/page.tsx | Team page with redirect logic |
Database Constraints
The teams table enforces:
- Unique slug — No two teams can have the same slug
- One personal team per user — Partial unique index on
(ownerId)whereisPersonal = true
Related Documentation
- Create API Key Flow — Detailed API key creation and encryption flow
- Control Plane and Multi-Tenancy — Team/project ownership and access model
- URL Signing — Request signing and authentication
- Domain Whitelisting — Domain whitelist configuration
- Next.js Integration — How to integrate OptStuff
Last updated on