CRM notes for a store tenant: customers, end-user accounts and relations ## The two kinds of people on a brand | | Staff (the store owner and their team) | Customers (shoppers) | |---|---|---| | Created by | `/account_setup/` (DW sign-up) or staff `/crm/` `create_person` | `/end_user_account_setup/` `verify` on the store domain | | Rows | `person`, `email`, `data_access` rights (SUPER_ADMIN, STORE, FILE, CRM…) | `person` + `email` (owner_type PRSN). **No rights.** An `end_user_account_setup` row records the sign-up (`verified_at`, `person_id`, `company_id`). | | Signs in with | `/session/`: the id is emailed, sent as JSON `session` + `brand`, and has no expiry in code | `/customer_session/` email code. HttpOnly cookie `__Host-dw_cs`, 30 days, bound to the exact host. A `session` row with rights `[]` plus a `site_session` row whose jti starts with `cu`. | | Can use | Every staff endpoint their rights allow | Their own carts, addresses, invoices, payments (PENDING only) and shipments | Any person on the brand who has an email can sign in as a customer with `/customer_session/`. That includes staff, so the owner can test as a shopper with their own email. ## What a customer's record holds after checkout - `person`: first, middle and last name, from `profile`. - `email`: the address they verified. - `telephone`: from `profile` (`line_type` VOICE_TEXT, VOICE, TEXT, FAX or OTHER). - `address`: - Shipping, Billing or Other rows (owner_type PRSN), from `profile` or `/address/`. - A customer may have several. `profile` updates the newest one of each type, and `/address/` create always adds a new row. - `company` + `relation`: only if they gave a `company_name` in `profile`. The company is created on the brand, and a `relation` row (person_id, company) links them. That is the B2B case, such as a clinic buying wholesale. - `cart` → `invoice` (`invoice.cart_id`, `person_id`, `company_id` = the **selling** company), with `invoice_product` lines and `invoice_address`. Each invoice has exactly one SHIPPING copy and one BILLING copy, so later address edits never change a past order. - `payments` and `shipment`: per invoice. ## Selling company vs customer company (don't mix them up) - `invoice.company_id` and `cart.company_id` = **the store's company**, the one that claims the product in `product_company`. Categories belong to that company too. - A customer's own company comes from `profile.company_name`. It's linked to the customer person through `relation`, and is **not** the seller. - A brand can hold several selling companies, like a marketplace. A cart holds products from one seller only, and `add` needs `company_id` when more than one company claims the product. ## Staff CRM calls that exist | Need | Call | |---|---| | Create, rename or delete a person or company | `/crm/` `create_person`, `update_person`, `delete_person`, `create_company`, `update_company`, `delete_company` (session + brand, module CRM rights) | | Link a person to a company | `/relation/` `create` (person_id, company_id). `read` by person_id or company_id | | A customer's addresses | `/address/` `list` with owner_type PRSN, owner_id (CRM READ) | | A customer's orders | `/store/invoice/` `list` (staff; filter by company_id and status). Each row has `person_id`. | ## Delete account A signed-in customer can POST /end_user_account_setup/ {"action":"delete_account","confirm_email":"they@example.com"} from their own session only. This deletes their sign-in email, phone numbers, saved addresses and open carts (history rows are kept), ends every session on this store, and signs them out. Orders and invoices are kept for the store's records. It is refused (409) while they have an order waiting for payment. ## What's missing (STATUS G8, G11) - **There's no way to list or look up customers through the app.** `/crm/` has no read or list action. An owner can see `person_id` on invoices but can't fetch that person's name or email through the API. Needed: `/crm/` `read_person`, `list_people` (search by name or email, paged), `read_company`. - Customers created by staff (not through sign-up) can sign in but can't use `profile`. - There's no opt-in field for marketing email, so don't email customers anything except their own order mail (the app already sends the checkout confirmation). ## Privacy rules for the tenant AI - Never paste customer emails, phones or addresses into public pages, logs, GitHub issues or chat. Refer to customers by first name or invoice id. - Test customers: use an inbox the owner controls. example.com and .test addresses never receive codes, so they can't finish sign-up.