Skip to content
Back to skills

Dos Onboarding

ASecurity

Directive OS client onboarding workflow, lead email system, dashboard access, payment flow, and post-payment setup steps. Use when the user asks about onboarding a new client, activating Sarah for a client, setting up a nominated email, explaining the workflow, or removing the DEMO banner from a client landing page.

  • 207 stars
  • 0 votes
  • 0 copies
  • 2 views
  • Added September 4, 2026
businessapidatabasefrontend

Works with

  • cli
  • api

Security analysis

A100/100

Pro scans all 13 files and shows the line behind each finding

Scanned September 4, 2026

npx -y skills add NeverSight/skills_feed --skill dos-onboarding --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Dos Onboarding?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Dos Onboarding
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/neversight-dos-onboarding/badge)](https://www.skillsdirectory.com/skills/neversight-dos-onboarding)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: dos-onboarding
description: Directive OS client onboarding workflow, lead email system, dashboard access, payment flow, and post-payment setup steps. Use when the user asks about onboarding a new client, activating Sarah for a client, setting up a nominated email, explaining the workflow, or removing the DEMO banner from a client landing page.
---

# Directive OS — Client Onboarding & Seat Billing

> **Related skills:** Read `directive-os-system` for full product catalog, pricing, tech stack, and business plan.

---

## The Two User Types

### 1. Agency Owner (Client)
- Created by Jayson via admin Fleet Manifest (`POST /api/admin/clients`)
- Login: `directiveos.com.au/dashboard/login` — email + temp password (emailed on creation)
- JWT payload: `{ type: "agency", agencyId, email }`
- Full access: leads, transcripts, listings, staff management, billing, settings

### 2. Staff Member
- Invited by agency owner from dashboard → Seat Management page
- Login: same `/dashboard/login` — email + self-chosen password
- JWT payload: `{ type: "staff", staffId, agencyId, email, role }`
- Role-based access (see Roles & Access below)

---

## Roles & Access

| Role | Value | Dashboard Tabs |
|------|-------|----------------|
| Principal | `principal` | All tabs — Command Centre, Leads, Transcripts, Listings, Billing, Seat Management, Protocols |
| Admin | `admin` | Command Centre, Leads, Transcripts, Listings, Billing |
| Sales Executive | `sales_executive` | Command Centre, Leads, Transcripts, Listings |
| Sales Support | `sales_support` | Command Centre, Leads, Transcripts |

Agency owner (`type: "agency"`) always has full access regardless of role.
Principal staff members also get full access including Seat Management and Protocols.

---

## Onboarding Flow — Agency Owner (Client)

```
STEP 1 — Jayson creates client in Fleet Manifest (/admin/clients)
  POST /api/admin/clients (x-admin-secret header)
  Body: { name, abn, contactEmail, contactPhone, subscriptionStatus }

STEP 2 — System auto-generates temp password
  bcrypt.hash(tempPassword, 10) → saved to agencies.password_hash
  Welcome email → client email CC: jayson + adwordpress2012

STEP 3 — Client logs in
  directiveos.com.au/dashboard/login
  Email + temp password → JWT stored in localStorage.clientToken

STEP 4 — Client invites agents (optional)
  → Each invite triggers Stripe +1 seat + invite email to agent
```

---

## Onboarding Flow — Staff Agent Invite

```
STEP 1 — Agency owner: Dashboard → Staff → "Invite Agent"
  POST /api/staff (x-clerk-org-id header)
  Body: { name, email, role }

STEP 2 — System:
  - Inserts staff record (status: "invited")
  - Generates 48hr secure token (crypto.randomBytes(32))
  - Saves token + tokenExpiry to staff table
  - Increments seat_count on agencies table
  - Calls Stripe → adds 1 seat (prorated immediately) via adjustStripeSeats()
  - Sends invite email to agent CC: jayson + adwordpress2012

STEP 3 — Agent receives email
  "You've been invited to [Agency Name] — Set your password"
  Link: directiveos.com.au/dashboard/set-password?token=TOKEN
  Link expires in 48 hours

STEP 4 — Agent sets password
  POST /api/staff/verify-token { token } → validates, returns name + agencyName
  POST /api/staff/activate { token, password } → bcrypt hash saved, token cleared
  staff.status → "active"

STEP 5 — Agent logs in
  directiveos.com.au/dashboard/login → email + new password
  Sees agency Command Centre with limited tabs
```

---

## Staff Removal

```
Agency owner removes agent → DELETE /api/staff/:id
→ seat_count decremented
→ Stripe subscription updated: -1 seat (prorated credit)
```

---

## Key API Endpoints

| Method | Endpoint | Auth | Description |
|--------|----------|------|-------------|
| POST | `/api/client/login` | Public | Unified login — checks agencies then staff |
| GET | `/api/client/me` | JWT Bearer | Returns user type, agency + staff data |
| POST | `/api/staff` | x-clerk-org-id | Invite agent → Stripe +1 → invite email |
| DELETE | `/api/staff/:id` | x-clerk-org-id | Remove agent → Stripe -1 |
| POST | `/api/staff/verify-token` | Public | Validate 48hr set-password token |
| POST | `/api/staff/activate` | Public | Set password, activate account |
| POST | `/api/admin/clients` | x-admin-secret | Create agency + auto welcome email |
| POST | `/api/admin/quote` | x-admin-secret | Generate Stripe Checkout link (any tier) |
| POST | `/api/admin/clients/:id/reset-password` | x-admin-secret | Reset + email new password |
| POST | `/api/admin/clients/:id/set-password` | x-admin-secret | Manually set password |

---

## Database Schema — Key Fields

### agencies table
| Column | Type | Purpose |
|--------|------|---------|
| `contact_email` | text | Login username for owner |
| `password_hash` | text | bcrypt hash (null = no login yet) |
| `seat_count` | int | Total seats (owner + agents) |
| `stripe_customer_id` | text | Stripe customer for billing |

### staff table
| Column | Type | Purpose |
|--------|------|---------|
| `agency_id` | int | FK to agencies |
| `email` | text | Login username |
| `password_hash` | text | bcrypt hash (null until activated) |
| `password_set_token` | text | 48hr activation token |
| `token_expiry` | timestamptz | Token expiry time |
| `status` | text | "invited" \| "active" |
| `role` | text | "principal" \| "admin" \| "sales_executive" \| "sales_support" |

---

## JWT Token Structure

```
Agency: { type: "agency", agencyId: number, email: string }
Staff:  { type: "staff", staffId: number, agencyId: number, email: string, role: string }
```
- Secret: `CLIENT_JWT_SECRET` env var
- Expiry: 30 days
- Storage: `localStorage.clientToken`

---

## Pricing Tiers

| Tier | Setup | Monthly Base | Per Seat |
|------|-------|--------------|----------|
| Small | A$1,800 | A$299/mo | A$89/mo |
| Medium | A$2,500 | A$399/mo | A$99/mo |
| Large | A$4,500 | A$599/mo | A$119/mo |

Defined in `TIERS` constant in `artifacts/api-server/src/routes/admin.ts`.

---

## Quote Builder

Location: `/admin/quote` — Captain's Bridge nav → "QUOTE BUILDER"

1. Select tier (Small/Medium/Large)
2. Enter seats, agency name, contact name, email
3. Click "Generate Payment Link"
4. Calls `POST /api/admin/quote` → returns Stripe Checkout URL
5. Copy and send to prospect

---

## Email Flows

| Trigger | To | CC | Content |
|---------|----|----|---------|
| Agency created (admin) | Client email | jayson + adwordpress2012 | Welcome + temp credentials |
| Password reset | Client email | jayson + adwordpress2012 | New password |
| Agent invited | Agent email | jayson + adwordpress2012 | Set-password link (48hr) |

From: `Directive OS <leads@directiveos.com.au>`
Support: `support@directiveos.com.au`

---

## Frontend Pages

| Page | Path | Auth Required |
|------|------|---------------|
| Client/Staff Login | `/dashboard/login` | Public |
| Set Password (agents) | `/dashboard/set-password?token=TOKEN` | Public (token-gated) |
| Command Centre | `/dashboard` | JWT |
| Staff Management | `/dashboard/staff` | JWT + agency owner only |
| Billing | `/dashboard/billing` | JWT + agency owner only |
| Quote Builder | `/admin/quote` | Admin secret |

---

## Admin Credentials
- URL: `directiveos.com.au/admin`
- Username: `captainjaze` (ADMIN_USERNAME env var)
- Password: `M@gdalena2050` (ADMIN_PASSWORD env var)
- Header used: `x-admin-secret: <ADMIN_PASSWORD>`

## Test Client (Production DB — ID 19)
- Email: `jayson@directiveos.com.au`
- Password: `ocampo`
- Agency: "Directive OS (Test)"

---

## Legacy Onboarding (Clerk-based — pre April 2025)

The original flow used Clerk org-based auth. Now replaced by email+password JWT auth. Clerk org IDs still stored in `clerk_org_id` column for backwards compatibility with existing dashboard routes that use `x-clerk-org-id` header.

---

## Stripe Seat Billing — How It Works

`adjustStripeSeats(agency, delta)` in `artifacts/api-server/src/routes/staff.ts`:
1. Looks up active Stripe subscription for the agency's `stripe_customer_id`
2. Finds the `STRIPE_PRICE_PER_SEAT` line item (if any)
3. +1 seat: creates or increments the seat item with `proration_behavior: "create_prorations"`
4. -1 seat: decrements or deletes the seat item with prorated credit
5. Stripe immediately charges (or credits) the prorated amount

---

## Adding a New Client Page

1. Create artifact: `createArtifact({ slug: "agency-slug", kind: "web", title: "Agency Name" })`
2. Copy `artifacts/c21-rana` (light theme) or `artifacts/nidus-re` (dark theme)
3. Update: agency name, PHONE constant, brand colours, nav links → client's real site
4. Add DEMO banner (copy from c21-rana landing.tsx)
5. Add `GetStartedCTA` component with agency slug + name
6. Deploy → directiveos.com.au/agency-slug/
7. Onboard the client via admin Fleet Manifest → creates login credentials automatically

---

## Required Environment Variables

| Variable | Purpose |
|----------|---------|
| `CLIENT_JWT_SECRET` | JWT signing secret |
| `DOS_RESEND_KEY` or `RESEND_API_KEY` | Email sending via Resend |
| `STRIPE_KEY_ACTIVE` | Stripe API key |
| `STRIPE_PRICE_ONBOARDING` | Stripe price ID for setup fee |
| `STRIPE_PRICE_PER_SEAT` | Stripe price ID for per-seat billing |
| `ADMIN_USERNAME` | Admin login username (`captainjaze`) |
| `ADMIN_PASSWORD` | Admin login password + x-admin-secret |

Files in this skill

  • SKILL.md9.2 KB
  • description_ar.txt577 B
  • description_cn.txt290 B
  • description_de.txt417 B
  • description_en.txt318 B
  • description_es.txt468 B
  • description_fr.txt420 B
  • description_it.txt490 B
  • description_ja.txt578 B
  • description_ko.txt387 B
  • description_ru.txt754 B
  • description_tw.txt293 B
  • stats.json68 B

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…