AstroBaaS

Customers & accounts

Invite Links

Free — GPL coresize Splanned, not built

Generated from docs/plan/core/invite-links/PLAN.md in the AstroBaaS repository. Nothing described below is implemented — it is the written plan for it.

Invite Links generates one-time URL tokens that merchants send to new staff, who click the link to set their password and complete account setup without needing a temporary password.

The problem

Merchants can’t easily onboard new team members; they must manually create accounts for each person.

What it does

  • Generate invite link token (URL-safe, 32+ random bytes, hashed in DB)
  • Email invite link to staff
  • Invite link valid 7 days (configurable)
  • Resend invite (new token, old becomes invalid)
  • Accepting invite: click link, set password, agree to terms, account activated
  • Show role and permissions before acceptance
  • Resend button: new link and re-email
  • Prevent double-accept: token consumed on first use
  • Cancel invite: revoke before user accepts
  • Audit log: created, sent, accepted, revoked, expired

What it deliberately does NOT do

Each boundary carries its reason. A boundary without a reason gets crossed by the next person who reads this.

  • Bulk invite (CSV upload of 100 emails) — single invite flow
  • Invite with SSO (Slack sign-in) — email and password only
  • Conditional invite (only if user doesn’t exist) — no duplicate checking
  • Invite tracking (user clicked but didn’t complete) — binary: accepted or expired
  • Multi-language invite email — English only

Data model

InviteToken: id, store_id, user_id (nullable initially), email, token_hash (SHA256), is_used, role_id, created_by, created_at, expires_at, accepted_at. Migration: add invite_tokens table with index on token_hash and store_id/email.

API

  • POST /admin/team/invite
  • GET /auth/invite/{token}
  • POST /auth/invite/{token}/accept
  • POST /admin/team/invite/{token}/resend
  • POST /admin/team/invite/{token}/cancel
  • GET /admin/team/invites

Every route added here must also appear in src/pages/openapi.json.ts — a test fails the build if it does not.

Admin

Invite form: email input, role selector, ‘Send invite’ or ‘Copy link’ buttons. Pending invites table: email, role, sent date, expiration, resend/cancel buttons.

The seam — why this is core

Core owns: InviteToken table, token generation/hashing, link validity check, password-set-on-accept. Paid module owns: email delivery (or copy-paste fallback).

Core owns the interface + honest invite generator; user onboarding is infrastructure, not a support commitment or credential.

Dependencies

  • admin-user-management
  • password-policy-enforcement

Acceptance checks

Each of these must be able to fail. Before claiming this is done, break the code deliberately and watch each one go red.

  • Creating invite generates 32-byte token, hashes it, stores hash, returns plaintext once
  • Email sent with link ‘https://…/invite/abc123’; clicking shows role+permissions, prompts for password
  • Submitting policy-invalid password returns rejected, form stays
  • Submitting valid password creates account, is_active=true, StoreUser created, is_used=true
  • Clicking same link again returns 400 Bad Request ‘Invite already used’
  • Expired link (after 7 days) returns 410 Gone
  • Resend generates new token, immediately invalidates old

Risks

Token guessed (weak randomness). Email not sent. Double-accept (two simultaneous requests). Invite link in forwarded emails leaks token. Old token still valid after resend.

Commercial context

Suggested pricefree (core)
Rival anchorShopify: included; Magento: included

The anchor is what the nearest equivalent charges on Shopify or Magento today. It is context for a pricing decision, not the decision.


Generated from the commerce plan. See docs/COMMERCE-PLAN.md for the full catalogue and ../../AI-GUIDE.md for how to work on this repository.