# Feature catalog

This list is generated from the product, so it cannot drift from the code. For a plain-language guide to each switch, see [Turn features on and off](./turning-features-on.md).

Machine-readable twin: [`catalog.json`](/cms/docs/catalog.json). Feature keys are the names in `site/config/features.config.ts`. Ask your agent to turn a key on or off. You cannot flip these in admin today.

- **shipped** — in use on live sites
- **current** — also in use (memberships and session packs)

Leads, the blog, the link-in-bio page, follow-up messages, and texting are **not** switches. See [leads](./leads.md), [public website](./public-site.md), and [messages](./messages.md).

## Always on

These have no `defineFeatures` switch. They are the platform.

| Key | Name | Owner doc | What it is |
| --- | --- | --- | --- |
| `customers` | Customers | [customers](./customers.md) | One record for everyone the business serves. Locations, tags, custom fields. A won lead becomes a customer. “Member” means a customer with an open membership, not a separate kind of person. |
| `staff` | Staff | [admin](./admin.md) | People with a staff row can sign in to admin (owner or staff). Sessions assign to staff. Owners invite staff and refund payments. |
| `leads` | Leads | [leads](./leads.md) | The enquiry pipeline. Not a feature switch today: lead forms always create leads, and admin always has the board. Turning leads off so forms only email the owner is still planned. |
| `scheduling` | Scheduling | [scheduling](./scheduling.md) | Recurrence, staff assignees, availability, closures and conflict checks. Group sessions use this engine. There is no appointments or jobs feature in this commit. |
| `messageQueue` | Message queue | [messages](./messages.md) | Features emit events (quote.sent, invoice.due, membership.started, …). The site’s automations and lead sequences say what to send. /api/cron/nurture sends what is due. |
| `siteConfig` | Site config | [vocabulary](./vocabulary.md) | Business details, vocabulary, forms, CRM follow-ups and feature switches live in site/config. An owner Settings page in admin is still planned. |
| `admin` | Admin | [admin](./admin.md) | The signed-in staff area at /admin. |
| `publicSite` | Public website | [public-site](./public-site.md) | Static public pages, blog posts, the link-in-bio page, and public forms. No feature switch: every site has them. Optional bits (phone, address, schedule) render nothing when missing. |

## Switches

Every key below is declared in `FEATURE_DEFAULTS` and is off unless the site turns it on.

| Key | Name | Maturity | Owner doc | Needs | Admin | Public |
| --- | --- | --- | --- | --- | --- | --- |
| `customerPortal` | Customer portal | shipped | [customer-portal](./customer-portal.md) | — | Customers (invite) | `/portal`; `/portal/account`; `/sign-in` |
| `groupSessions` | Group sessions | shipped | [group-sessions](./group-sessions.md) | — | /admin/schedule | `/schedule` |
| `groupSessionBooking` | Group session booking | shipped | [group-sessions](./group-sessions.md) | `groupSessions`, `customerPortal` | /admin/schedule (add a customer to a session) | `/portal/sessions` |
| `memberships` | Memberships | current | [memberships](./memberships.md) | `payments`, `customerPortal` | /admin/catalog (plans); /admin/memberships | `/portal/memberships`; `/portal/memberships/manage` |
| `sessionPacks` | Session packs | current | [session-packs](./session-packs.md) | `payments`, `customerPortal` | /admin/catalog (packs); /admin/customers (balance) | `/portal/session-packs` |
| `files` | Files | shipped | [files](./files.md) | — | /admin/files | `/files/{slug}` |
| `payments` | Payments | shipped | [payments](./payments.md) | — | /admin/payments | `/pay/{token}` |
| `invoices` | Invoices | shipped | [invoices](./invoices.md) | — | /admin/invoices | `/i/{token}`; `/i/{token}/pdf` |
| `quotes` | Quotes | shipped | [quotes](./quotes.md) | — | /admin/quotes; /admin/catalog | `/q/{token}`; `/q/{token}/pdf` |

## Collections

Table names in Postgres (`public`). Memberships use `membership_plans` and `memberships`, not a table named `subscriptions`.

| Collection | Summary | Used by |
| --- | --- | --- |
| `customers` | The person or organisation every feature hangs off: name, emails, phones, locations, tags, and site-defined custom fields. A lead becomes a customer when it is won. | `memberships`, `sessionPacks`, `customerPortal`, `quotes`, `invoices`, `payments`, `groupSessions`, `groupSessionBooking` |
| `staff` | People assigned to sessions. Staff availability and time off feed the scheduling engine. A staff row is also what lets someone sign in to admin. | `groupSessions` |
| `membership_plans` | Admin catalog of recurring offers (name, amount in cents, month or year). Checkout uses these plans; the browser is not trusted to supply Stripe product or price IDs. | `memberships` |
| `memberships` | Local subscription and access state for one customer’s plan. Status names match Stripe. One open membership per customer. Not a table named subscriptions. | `memberships` |
| `session_packs` | Admin catalog of one-time session-credit packs (name, amount in cents, credit count, optional expiry in days). Checkout uses these packs; the browser is not trusted to supply Stripe product or price IDs. | `sessionPacks` |
| `session_pack_purchases` | A customer’s one-time pack Checkout (or simulated purchase). Credits are granted once on paid Checkout. | `sessionPacks` |
| `session_pack_lots` | A grant of session credits with remaining balance and optional expiry. Available balance is unexpired remaining. | `sessionPacks` |
| `session_pack_credits` | Ledger of grants and uses (purchase, admin grant, booking use, deduct, reverse, refund). | `sessionPacks` |
| `catalog_items` | Products and services used as quote and invoice line items. Owners edit them on admin → Catalog, next to membership plans and session packs. | `quotes`, `invoices` |
| `quotes` | Priced offers with optional line items, tax, deposit, approval signature, and PDF. | `quotes`, `customerPortal`, `payments` |
| `invoices` | Amounts in integer cents, one currency per site, document numbers such as INV-1001. Stored statuses: draft, awaiting_payment, paid, bad_debt, void. past_due is computed. | `invoices`, `payments`, `customerPortal` |
| `payments` | One-time payment records. Stripe events are logged idempotently in stripe_events. Memberships reuse this foundation rather than a second ledger. | `payments`, `invoices`, `quotes`, `memberships`, `sessionPacks` |
| `scheduled_messages` | Queued email and SMS pointed at a lead, customer, quote, invoice, membership or session pack, with consent and quiet-hour safeguards. | `invoices`, `quotes`, `memberships`, `sessionPacks` |
| `site_files` | Uploaded files served at /files/{slug}. Access is public or signed-in customers (and staff). | `files` |
| `public_links` | Hashed tokens for /q/{token}, /i/{token} and /pay/{token}. The server checks the token before reading the record. | `quotes`, `invoices`, `payments` |
| `leads` | Enquiry pipeline from public forms. Stages and programs are the site’s CRM config. | — |
| `schedule_occurrences` | Dated instances of the scheduling engine (group sessions today). Capacity, cancel state, staff assignees. | `groupSessions`, `groupSessionBooking` |
| `group_session_bookings` | A customer booked on a group-session occurrence. | `groupSessionBooking` |
| `tax_rates` | Named tax rates in basis points. One default. Copied onto quotes and invoices. | `quotes`, `invoices` |

## Routes in this commit

### Admin

- `/admin`
- `/admin/account`
- `/admin/catalog`
- `/admin/customers`
- `/admin/customers/:customerId`
- `/admin/files`
- `/admin/invoices`
- `/admin/invoices/:invoiceId`
- `/admin/invoices/:invoiceId/pdf`
- `/admin/leads`
- `/admin/leads/:id`
- `/admin/memberships`
- `/admin/payments`
- `/admin/quotes`
- `/admin/quotes/:quoteId`
- `/admin/quotes/:quoteId/pdf`
- `/admin/schedule`
- `/admin/schedule/:sessionId`
- `/admin/schedule/weekly`
- `/admin/staff`

### Customer portal

- `/portal`
- `/portal/account`
- `/portal/invoices/:invoiceId`
- `/portal/memberships`
- `/portal/memberships/manage`
- `/portal/request`
- `/portal/session-packs`
- `/portal/sessions`

### Public token links

- `/files/:slug`
- `/i/:token`
- `/i/:token/pdf`
- `/pay/:token`
- `/q/:token`
- `/q/:token/pdf`

### Sign-in

- `/auth/confirm`
- `/forgot-password`
- `/sign-in`
- `/update-password`

### Public site and forms

- `/`
- `/.well-known/xylo.json`
- `/about`
- `/blog`
- `/blog/:slug`
- `/blog/page/:page`
- `/cancel-plan`
- `/forms/:form`
- `/get-started`
- `/links`
- `/privacy-policy`
- `/request-visit`
- `/schedule`
- `/services`
- `/services/:slug`
- `/terms-of-service`

