Onboarding
Free · MITv0.1.1Configurable onboarding for your users: checklists, step-by-step welcome wizards and product tours, targeted with audience rules and completed by clicks, page visits or any event your app emits.
terminalnpx ajolla add onboardingWhat you get
- Checklist, wizard and product-tour flows built in your admin
- Steps complete manually, on a page visit or when an event fires
- Audience rules (plan, sign-up age, metadata, finished flows) in a small JSON language
- Embeddable checklist card and accessible product tour, no dependencies
- Per-user progress, dismiss and restore, admin reset
- Funnel stats per flow and per step
Routes it adds
/admin/onboarding/admin/onboarding/[flowId]/onboarding/onboarding/[flowKey]
Plus 1 Supabase migration with row-level security, and an AGENTS.md your coding agent reads after install.
Installs with
Kernel (added automatically).
Events
Other modules (and your own code) can react to these:
onboarding.step_completedonboarding.flow_completedonboarding.flow_dismissed
Use it from any stack
Ajolla Hosted runs the same code as a multi-tenant API. Create an app in your dashboard, enable Onboarding, and call /api/m/onboarding/v1 with your app key.
OpenAPI document — feed it to Ajolla to generate SDKs in 7 languages and an MCP server.
AGENTS.md
Read the instructions installed with this module
markdown# Ajolla Onboarding
Onboarding flows for your users: **checklists**, step-by-step **wizards** and **product tours**. Admins build flows in `/admin/onboarding`, target them with audience rules, and each user's progress is saved. Steps complete when the user marks them done, when they visit a page, or when an event fires (for example `profiles.updated` from Ajolla Profiles, or any event your own code emits).
## What was installed
**Routes**
- `/onboarding`: the signed-in user's active guides with progress, plus the guides they dismissed, which they can bring back.
- `/onboarding/[flowKey]`: one guide on its own page. A checklist shows as a card; wizards and tours go one step at a time (`?step=n`).
- `/admin/onboarding`, `/admin/onboarding/[flowId]`: flows, steps editor, audience rule, status, funnel stats, per-user reset and delete. Requires the `onboarding.manage` permission.
**Components** (`components/ajolla/onboarding/`)
- `<OnboardingChecklist />`: embed on your dashboard. Takes an optional `flowKey`, `returnTo` (the path to refresh after a change) and `hideCompleted` (default true). Renders nothing for signed-out users.
- `<ProductTour flowKey="welcome-tour" />`: put it on the page the tour covers. It highlights each step's `target` (a CSS selector) with an accessible popover. Esc closes the tour, focus is trapped while it's open, and steps whose target isn't on the page are skipped.
- `<OnboardingVisitTracker />`: put it once in your root layout. It completes "visit" steps when the user opens the matching path, and only calls the server on paths a step waits for.
- `ChecklistCard`, `ProgressBar`, `StepBody` and `OnboardingActionButton` are the building blocks, if you want your own layout.
**Code**
- `lib/ajolla/onboarding/core.ts`: all logic, framework-free.
- `rules.ts`: the audience rule language.
- `body.ts`: the safe markdown-lite renderer.
- `paths.ts`: visit-path matching.
- `server.ts`: the user context for rules and event emission.
- `lib/ajolla/subscribers/onboarding.ts`: event-driven step completion.
- `lib/ajolla/admin/onboarding.ts`: the admin registration.
**Tables** (`ajolla_onboarding_`)
- `flows`: unique `key`; type `checklist|wizard|tour`; status `draft|active|archived`; `audience` jsonb; `priority`.
- `steps`: unique `(flow_id, key)`; `position`; title and body; optional CTA; completion `manual|event|visit`; tour `target` and `placement`.
- `progress`: one row per user, flow and step.
- `states`: one row per user and flow, with `started_at`, `completed_at` and `dismissed_at`.
**RLS**
- **Anonymous visitors:** nothing.
- **Signed-in users:**
- Read active flows and their steps.
- Read and write only their own progress and state.
- Can't complete an event-driven step or a step of a non-active flow.
- **`onboarding.manage`:** everything.
- Audience rules decide what a user is shown. They are not access control.
**Events**
- `onboarding.step_completed`: `{ userId, flowId, flowKey, stepKey, source }`.
- `onboarding.flow_completed`: `{ userId, flowId, flowKey }`.
- `onboarding.flow_dismissed`: `{ userId, flowId, flowKey }`.
The subscriber listens to every event. For any step waiting on that event type, it completes the step for the event's actor, or for `payload.userId` when there is no actor.
**Env:** none beyond the kernel's.
## Setup
1. Apply the migration: `supabase db push`.
2. Add `<OnboardingVisitTracker />` to your root layout if you'll use "visit" steps.
3. As an admin, open `/admin/onboarding`, create a flow, add steps, then press **Activate**.
4. Show it:
- `<OnboardingChecklist />` on your dashboard.
- `<ProductTour flowKey="…" />` on the toured page.
- Or link users to `/onboarding`.
## Audience rules
Leave the rule empty to target everyone. Otherwise write JSON, for example:
```json
{ "all": [{ "path": "metadata.plan", "in": ["pro", "team"] }, { "signedUpWithinDays": 14 }] }
```
**Combinators:** `all`, `any`, `not`.
**Comparisons:** `equals`, `in`, `contains` (a case-insensitive substring for strings, an element for arrays), `exists`, `gt` and `lt` (numbers or ISO dates), and `signedUpWithinDays`.
**Paths** start at `email`, `createdAt`, `metadata` or `completedFlows`. `completedFlows` lets you chain flows: `{ "path": "completedFlows", "contains": "getting-started" }`.
**Where `metadata` comes from:** `userContextFor()` in `server.ts` builds it from Supabase `user_metadata`, then overlays `app_metadata`. A user can edit `user_metadata` but not `app_metadata`, so target plans and roles through `app_metadata`.
## Customising
- **Step text:** plain text. Blank lines separate paragraphs, `**bold**` works, and `[links](/path)` work. Links must be same-site paths or `https://` URLs; anything else is shown as text.
- **Event-driven steps:** emit your own events with `emitEvent("app.project_created", {...})` from `@/lib/ajolla/events`, then pick that event type on a step.
- **Styles:** `components/ajolla/onboarding/onboarding.module.css` and the kit's `--aj-*` variables.
- **Wording:** change the copy in the components and pages directly; you own them.