# Rain Hair Studio — Invite Flow

> Scaffolded but not built. This document is the design contract. Implementation lands in Phase 3, when CeCe is ready to invite her first salon workmate.

## Purpose

Let CeCe (owner) bring stylists from Cosmo Salon Studios into the Rain Hair Studio hub without exposing the URL publicly. Soft-fence model, same as the rest of substrate — "no accidents," not "no attackers." Hardened auth (Firebase) is a separate, later effort.

## Roles

Defined in [`/cece/rainhairstudio/_data/members.json`](../_data/members.json):

- **owner** — full edit, can invite + revoke. Currently: CeCe.
- **member** — stylist with their own area + read access to `/shared/`. Currently: none.
- **viewer** — read-only family/admin. Currently: Sam.

## Flow (Phase 3 implementation)

1. **CeCe opens** [`/cece/rainhairstudio/invites/`](./index.html)
2. **Clicks "Generate invite link"** — types invitee name (e.g., "Sarah from Cosmo Salon Studios")
3. **System generates** a random URL-safe token and a unique URL:
   ```
   https://hub.samesolutionsllc.com/cece/rainhairstudio/invites/accept/?token=abc123…
   ```
4. **System records** the pending invite in `/_data/pending.json`:
   ```json
   { "token": "abc123…", "invitee_name": "Sarah", "created": "2026-05-19", "expires": "2026-05-26", "by": "cece" }
   ```
5. **CeCe sends** the URL to invitee via text/email/Signal/etc. (out of band)
6. **Invitee clicks link** → lands on welcome screen at `/cece/rainhairstudio/invites/accept/?token=…`
7. **Welcome screen prompts**:
   - "Hi Sarah — CeCe invited you to Rain Hair Studio. Pick a username (becomes your folder)."
   - Username validation: lowercase, no spaces, no collisions with existing members
8. **On submit**, the system:
   - Validates token is in `pending.json` and not expired
   - Adds entry to `members.json` with `role: "member"`, `active: true`, `added: <today>`
   - Adds entry to `stylists-roster.json` (mirrors basic fields)
   - Creates `/stylists/<username>/` folder with stub `index.html` (mirrors `/stylists/cece/` layout)
   - Removes token from `pending.json`
   - Sets `localStorage["ss-hub-user"] = <username>` so they're identified going forward
9. **Invitee is redirected** to `/cece/rainhairstudio/stylists/<username>/` — their dashboard
10. **CeCe sees** the new member in the active list on `/invites/`

## Revoke flow

1. CeCe opens `/invites/` → sees active members list
2. Clicks "Revoke" next to a member
3. System sets `active: false` in `members.json` (preserves history)
4. Member loses write access immediately (gate reads `active` flag)
5. Member's stylist folder is preserved for audit trail; can be permanently removed by hand later

## Technical notes for the implementer

- **Static substrate, no server** — pending invites and member edits need a write surface. Options:
  - (a) **Cloudflare KV** via the existing `/our/data` Worker endpoint (matches the calendar pattern) — recommended
  - (b) **GitHub Action** triggered by token-bearing webhook → commits JSON edits to repo — heavier, but no KV cost
  - (c) **Manual JSON edit** by CeCe via VS Code — works for Phase 3 MVP if invite volume is <5/month
- **Token format:** `crypto.randomUUID()` truncated to 22 chars, URL-safe base64. Tokens are bearer credentials — short-lived (7 days default), single-use, no value beyond accepting one invite.
- **Username collision:** if someone picks a username that matches an existing folder, regenerate with `-2` suffix or prompt for retry.
- **Folder scaffolding:** copy `/stylists/cece/` as the template, replace breadcrumbs and `role-badge` defaults.
- **Soft-fence reminder:** the gate is `localStorage["ss-hub-user"]` — a determined adversary can fake it. This is family/colleague trust, not hostile-actor security. Phase 4 hardens with Firebase auth on the same Worker that backs `/our/data`.

## Out of scope for Phase 3

- Email/SMS notification when invite is sent (CeCe sends out of band)
- Two-factor confirmation
- Owner transfer (renaming owner; for now, owner is fixed as `cece` in code)
- Multi-salon support (Rain Hair Studio is one salon; if CeCe ever joins/runs another, that's a separate scaffold)
- Bulk invites
- Audit log beyond the `added` and `active` fields

## When to actually build this

Trigger: CeCe says "Sarah wants in — how do I add her?" Until then, the scaffold is fine. No code needs to ship preemptively.

Estimated build effort once triggered: ~3-4 hours including KV Worker glue + acceptance screen + revoke UI.
