{
  "schemaVersion": 1,
  "source": "xylo-cms-export",
  "xyloCmsCommit": "d67e1c69e5f5b68f201edd0728a428a874035e6d",
  "alwaysOn": [
    "customers",
    "staff",
    "leads",
    "scheduling",
    "messageQueue",
    "siteConfig",
    "admin",
    "publicSite"
  ],
  "features": [
    {
      "key": "customerPortal",
      "name": "Customer portal",
      "summary": "Customers sign in at /portal with a password or a one-time email code. Staff invite them from admin → Customers. The home page stacks a section from each feature that has something for them.",
      "maturity": "shipped",
      "ownerDoc": "customer-portal",
      "configKey": "customerPortal",
      "requires": [],
      "adminAreas": [
        "Customers (invite)"
      ],
      "publicSurfaces": [
        "/portal",
        "/portal/account",
        "/sign-in"
      ],
      "tables": [
        "customers"
      ]
    },
    {
      "key": "groupSessions",
      "name": "Group sessions",
      "summary": "A weekly schedule of sessions many people attend. Staff run it in admin → Schedule; the public timetable is /schedule.",
      "maturity": "shipped",
      "ownerDoc": "group-sessions",
      "configKey": "groupSessions",
      "requires": [],
      "adminAreas": [
        "/admin/schedule"
      ],
      "publicSurfaces": [
        "/schedule"
      ],
      "tables": [
        "schedule_series",
        "schedule_occurrences",
        "schedule_closures",
        "group_session_settings"
      ]
    },
    {
      "key": "groupSessionBooking",
      "name": "Group session booking",
      "summary": "Signed-in customers book group sessions in the portal (/portal/sessions). Needs groupSessions and customerPortal. Book-ahead days are a setup setting; cutoff minutes live in group_session_settings (default 15).",
      "maturity": "shipped",
      "ownerDoc": "group-sessions",
      "configKey": "groupSessionBooking",
      "requires": [
        "groupSessions",
        "customerPortal"
      ],
      "adminAreas": [
        "/admin/schedule (add a customer to a session)"
      ],
      "publicSurfaces": [
        "/portal/sessions"
      ],
      "tables": [
        "group_session_bookings"
      ]
    },
    {
      "key": "memberships",
      "name": "Memberships",
      "summary": "Recurring plans in the admin catalog, Stripe Checkout in subscription mode on the owner’s Stripe account, webhooks into local memberships rows, and Stripe’s billing portal (or a simulated page when keys are absent).",
      "maturity": "current",
      "ownerDoc": "memberships",
      "configKey": "memberships",
      "requires": [
        "payments",
        "customerPortal"
      ],
      "adminAreas": [
        "/admin/catalog (plans)",
        "/admin/memberships"
      ],
      "publicSurfaces": [
        "/portal/memberships",
        "/portal/memberships/manage"
      ],
      "tables": [
        "membership_plans",
        "memberships",
        "membership_settings"
      ]
    },
    {
      "key": "sessionPacks",
      "name": "Session packs",
      "summary": "One-time packs of session credits in the admin catalog, Stripe Checkout in payment mode, a per-customer credit ledger, and consume-on-booking when group session booking is on (or admin check-in when it is not).",
      "maturity": "current",
      "ownerDoc": "session-packs",
      "configKey": "sessionPacks",
      "requires": [
        "payments",
        "customerPortal"
      ],
      "adminAreas": [
        "/admin/catalog (packs)",
        "/admin/customers (balance)"
      ],
      "publicSurfaces": [
        "/portal/session-packs"
      ],
      "tables": [
        "session_packs",
        "session_pack_purchases",
        "session_pack_lots",
        "session_pack_credits"
      ]
    },
    {
      "key": "files",
      "name": "Files",
      "summary": "Staff upload PDFs, text files and zips. Each file has a stable /files/{slug} link, either for anyone or only signed-in customers and staff.",
      "maturity": "shipped",
      "ownerDoc": "files",
      "configKey": "files",
      "requires": [],
      "adminAreas": [
        "/admin/files"
      ],
      "publicSurfaces": [
        "/files/{slug}"
      ],
      "tables": [
        "site_files"
      ]
    },
    {
      "key": "payments",
      "name": "Payments",
      "summary": "One-time money in the owner’s Stripe account (Checkout) plus cash and checks staff record. Other features ask for payment through this ledger. Without keys, local and preview deploys simulate charges.",
      "maturity": "shipped",
      "ownerDoc": "payments",
      "configKey": "payments",
      "requires": [],
      "adminAreas": [
        "/admin/payments"
      ],
      "publicSurfaces": [
        "/pay/{token}"
      ],
      "tables": [
        "payments",
        "stripe_events"
      ]
    },
    {
      "key": "invoices",
      "name": "Invoices",
      "summary": "What a customer owes: draft through paid, void or bad debt. Sent by email or text with a public /i/{token} page, PDF, and (with payments) a pay button. Reminders go through the message queue.",
      "maturity": "shipped",
      "ownerDoc": "invoices",
      "configKey": "invoices",
      "requires": [],
      "adminAreas": [
        "/admin/invoices"
      ],
      "publicSurfaces": [
        "/i/{token}",
        "/i/{token}/pdf"
      ],
      "tables": [
        "invoices",
        "invoice_line_items"
      ]
    },
    {
      "key": "quotes",
      "name": "Quotes",
      "summary": "Priced lines from the catalog, sent by email or text. The customer opens /q/{token}, ticks optional lines, and approves with a typed or drawn signature — or sends a note asking for changes. With payments on, they can pay a deposit there.",
      "maturity": "shipped",
      "ownerDoc": "quotes",
      "configKey": "quotes",
      "requires": [],
      "adminAreas": [
        "/admin/quotes",
        "/admin/catalog"
      ],
      "publicSurfaces": [
        "/q/{token}",
        "/q/{token}/pdf"
      ],
      "tables": [
        "quotes",
        "quote_line_items",
        "quote_activity"
      ]
    }
  ],
  "collections": [
    {
      "name": "customers",
      "summary": "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.",
      "usedBy": [
        "memberships",
        "sessionPacks",
        "customerPortal",
        "quotes",
        "invoices",
        "payments",
        "groupSessions",
        "groupSessionBooking"
      ]
    },
    {
      "name": "staff",
      "summary": "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.",
      "usedBy": [
        "groupSessions"
      ]
    },
    {
      "name": "membership_plans",
      "summary": "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.",
      "usedBy": [
        "memberships"
      ]
    },
    {
      "name": "memberships",
      "summary": "Local subscription and access state for one customer’s plan. Status names match Stripe. One open membership per customer. Not a table named subscriptions.",
      "usedBy": [
        "memberships"
      ]
    },
    {
      "name": "session_packs",
      "summary": "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.",
      "usedBy": [
        "sessionPacks"
      ]
    },
    {
      "name": "session_pack_purchases",
      "summary": "A customer’s one-time pack Checkout (or simulated purchase). Credits are granted once on paid Checkout.",
      "usedBy": [
        "sessionPacks"
      ]
    },
    {
      "name": "session_pack_lots",
      "summary": "A grant of session credits with remaining balance and optional expiry. Available balance is unexpired remaining.",
      "usedBy": [
        "sessionPacks"
      ]
    },
    {
      "name": "session_pack_credits",
      "summary": "Ledger of grants and uses (purchase, admin grant, booking use, deduct, reverse, refund).",
      "usedBy": [
        "sessionPacks"
      ]
    },
    {
      "name": "catalog_items",
      "summary": "Products and services used as quote and invoice line items. Owners edit them on admin → Catalog, next to membership plans and session packs.",
      "usedBy": [
        "quotes",
        "invoices"
      ]
    },
    {
      "name": "quotes",
      "summary": "Priced offers with optional line items, tax, deposit, approval signature, and PDF.",
      "usedBy": [
        "quotes",
        "customerPortal",
        "payments"
      ]
    },
    {
      "name": "invoices",
      "summary": "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.",
      "usedBy": [
        "invoices",
        "payments",
        "customerPortal"
      ]
    },
    {
      "name": "payments",
      "summary": "One-time payment records. Stripe events are logged idempotently in stripe_events. Memberships reuse this foundation rather than a second ledger.",
      "usedBy": [
        "payments",
        "invoices",
        "quotes",
        "memberships",
        "sessionPacks"
      ]
    },
    {
      "name": "scheduled_messages",
      "summary": "Queued email and SMS pointed at a lead, customer, quote, invoice, membership or session pack, with consent and quiet-hour safeguards.",
      "usedBy": [
        "invoices",
        "quotes",
        "memberships",
        "sessionPacks"
      ]
    },
    {
      "name": "site_files",
      "summary": "Uploaded files served at /files/{slug}. Access is public or signed-in customers (and staff).",
      "usedBy": [
        "files"
      ]
    },
    {
      "name": "public_links",
      "summary": "Hashed tokens for /q/{token}, /i/{token} and /pay/{token}. The server checks the token before reading the record.",
      "usedBy": [
        "quotes",
        "invoices",
        "payments"
      ]
    },
    {
      "name": "leads",
      "summary": "Enquiry pipeline from public forms. Stages and programs are the site’s CRM config.",
      "usedBy": []
    },
    {
      "name": "schedule_occurrences",
      "summary": "Dated instances of the scheduling engine (group sessions today). Capacity, cancel state, staff assignees.",
      "usedBy": [
        "groupSessions",
        "groupSessionBooking"
      ]
    },
    {
      "name": "group_session_bookings",
      "summary": "A customer booked on a group-session occurrence.",
      "usedBy": [
        "groupSessionBooking"
      ]
    },
    {
      "name": "tax_rates",
      "summary": "Named tax rates in basis points. One default. Copied onto quotes and invoices.",
      "usedBy": [
        "quotes",
        "invoices"
      ]
    }
  ],
  "tables": [
    "catalog_items",
    "customer_locations",
    "customers",
    "group_session_bookings",
    "group_session_settings",
    "invoice_line_items",
    "invoices",
    "lead_activities",
    "leads",
    "membership_plans",
    "membership_settings",
    "memberships",
    "payments",
    "public_links",
    "quote_activity",
    "quote_line_items",
    "quotes",
    "schedule_assignees",
    "schedule_closures",
    "schedule_occurrences",
    "schedule_series",
    "schedule_series_assignees",
    "scheduled_messages",
    "session_pack_credits",
    "session_pack_lots",
    "session_pack_purchases",
    "session_packs",
    "site_files",
    "staff",
    "staff_availability",
    "staff_time_off",
    "stripe_events",
    "sync_conflicts",
    "tax_rates"
  ],
  "routes": {
    "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"
    ],
    "portal": [
      "/portal",
      "/portal/account",
      "/portal/invoices/:invoiceId",
      "/portal/memberships",
      "/portal/memberships/manage",
      "/portal/request",
      "/portal/session-packs",
      "/portal/sessions"
    ],
    "auth": [
      "/auth/confirm",
      "/forgot-password",
      "/sign-in",
      "/update-password"
    ],
    "token": [
      "/files/:slug",
      "/i/:token",
      "/i/:token/pdf",
      "/pay/:token",
      "/q/:token",
      "/q/:token/pdf"
    ],
    "public": [
      "/",
      "/.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"
    ]
  }
}
