# Product Requirements Document

## Validation Checklist

- [x] All required sections are complete
- [x] No [NEEDS CLARIFICATION] markers remain
- [x] Problem statement is specific and measurable
- [x] Problem is validated by evidence (not assumptions)
- [x] Context → Problem → Solution flow makes sense
- [x] Every persona has at least one user journey
- [x] All MoSCoW categories addressed (Must/Should/Could/Won't)
- [x] Every feature has testable acceptance criteria
- [x] Every metric has corresponding tracking events
- [x] No feature redundancy (check for duplicates)
- [x] No contradictions between sections
- [x] No technical implementation details included
- [x] A new team member could understand this PRD

---

## Product Overview

### Vision
Provide a unified, automated billing system that gives BuyerKiosk operators full visibility into per-store charges across subscriptions, premium modules, and usage-based services — enabling accurate invoicing, transparent cost breakdowns, and effortless extensibility as the platform grows.

### Problem Statement
BuyerKiosk currently has no unified billing tracking system. The platform has multiple revenue streams per store (base subscription, premium scheduling at $30/mo, various SMS categories at per-text rates) but no centralized way to:

1. **Track what each store owes** — Base rates, premium module status, and SMS usage are spread across disconnected systems (store config columns, premium event logs, SMS file logs) with no aggregation.
2. **Bill accurately for SMS usage** — The TextMessageService logs to files only, not a queryable database. The ChatBillingService tracks two-way chat SMS but buy completion, survey, and marketing texts are untracked.
3. **Customize pricing per store** — SMS rates are hardcoded ($0.0075/segment in ChatBillingService). Different stores cannot have different rates or different included/excluded categories.
4. **Show stores their own charges** — Store owners have no visibility into what they're being charged for or why. Existing Invoice.php only serves static PDF files.
5. **Give admins a billing overview** — No cross-store billing dashboard exists. Generating billing reports requires manual data collection across multiple systems.

The consequence: billing is a manual, error-prone process that doesn't scale as the store count grows and new billable features are added. Currently, monthly billing requires cross-referencing multiple data sources and manual spreadsheet assembly — a process that grows linearly with store count.

### Value Proposition
A unified billing system that:
- **Automates invoice generation** — Monthly invoices generated automatically on the 1st via background job, eliminating manual billing work
- **Tracks every billable event in real-time** — SMS sends, premium module status changes, and all future billable items logged at the point of occurrence
- **Gives stores transparency** — Store owners see exactly what they're paying for with line-item detail, reducing billing disputes
- **Scales with the platform** — Code-defined billing catalog makes adding new billable items (AI features, integrations, storage) straightforward
- **Customizes per store** — Per-store rate tables allow different pricing for different stores without code changes

## User Personas

### Primary Persona: BuyerKiosk Platform Admin (Ryan)
- **Demographics:** Platform operator/owner, high technical familiarity, manages all stores
- **Goals:** Accurately bill every store monthly with minimal manual effort. Understand platform-wide revenue. Customize pricing for individual stores.
- **Pain Points:** Currently assembles billing manually. No single view of what each store owes. Adding new billable features requires ad-hoc tracking.

### Secondary Personas

#### Store Owner (Casey)
- **Demographics:** Individual store operator, moderate technical familiarity, manages one or a few stores
- **Goals:** Understand what they're being charged for. See usage breakdowns. Download invoices for accounting/tax purposes.
- **Pain Points:** No visibility into billing details. Doesn't know how many texts are being sent or what they cost. Can't plan costs ahead.

#### Store Manager
- **Demographics:** Day-to-day store manager, may have `uri_store_settings` access
- **Goals:** Monitor store's text message usage to control costs. Understand which features are generating charges.
- **Pain Points:** Cannot see billing impact of operational decisions (e.g., enabling two-way texting).

## User Journey Maps

### Primary User Journey: Admin Monthly Billing Cycle
1. **Awareness:** Admin knows billing is due on the 1st of each month for the previous month's charges.
2. **Consideration:** Admin needs to review all store invoices before they're finalized. Checks for anomalies or disputes.
3. **Adoption:** System auto-generates invoices via TaskEngine on the 1st. Admin receives notification.
4. **Usage:**
   - Admin opens billing dashboard showing all stores for current/previous period
   - Reviews total amounts, identifies stores with unusual charges
   - Drills into individual store invoices to see line items
   - Adjusts per-store rates or configurations as needed (takes effect next period)
   - In exceptional cases, admin can void and regenerate a current period invoice (applies current rates to existing usage data)
5. **Retention:** Automated monthly generation eliminates manual work. Dashboard becomes the single source of truth for billing.

### Secondary User Journeys

#### Store Owner Viewing Their Invoice
1. **Awareness:** Store owner navigates to "Billing" section in their store's sidebar menu.
2. **Usage:**
   - Sees current month's billing summary (running total of charges)
   - Views past invoices with status (generated/finalized)
   - Drills into any invoice to see line-by-line breakdown
   - Downloads PDF version for their records
   - Sees usage trends (e.g., text messages this month vs last)
3. **Retention:** Monthly transparency builds trust. No billing surprises.

#### Admin Configuring Store Billing
1. **Awareness:** New store onboarded, or existing store needs pricing adjustment.
2. **Usage:**
   - Admin navigates to store's billing configuration
   - Sets base monthly rate
   - Configures which SMS categories are billable vs included
   - Sets per-category SMS rates (or uses platform defaults)
   - Enables/disables premium module billing
   - Saves configuration (takes effect on next billing cycle)
3. **Retention:** One-time setup per store. Changes propagate automatically to future invoices.

## Feature Requirements

### Must Have Features

#### Feature 1: Unified Billing Line Item Tracking
- **User Story:** As a platform admin, I want all billable events tracked as line items in a central system so that I can generate accurate invoices without manual data collection.
- **Acceptance Criteria:**
  - [ ] Base subscription rate tracked as a monthly fixed line item per store
  - [ ] Premium scheduling module tracked as a monthly fixed line item (charged if active at any point during billing period)
  - [ ] Every outbound SMS tracked with category, segment count, and billable flag
  - [ ] SMS categories use the canonical category list (see Canonical SMS Category Taxonomy below)
  - [ ] Each line item tagged with billing period (YYYY-MM format)
  - [ ] Line items include both billable ($X.XX) and included ($0.00) entries

**Canonical SMS Category Taxonomy:**

| Category Code | Description | Source Method / System | Default Billable |
|---------------|-------------|----------------------|------------------|
| `buy_completion` | Buy/offer ready for pickup | `TextMessageService::sendBuyText()` | No (included) |
| `service_completion` | Equipment service ready | `TextMessageService::sendServiceText()` | No (included) |
| `survey` | Post-transaction survey | `TextMessageService::sendSurveyText()` | Yes |
| `chat_transactional` | Automated chat templates | `ChatBillingService` (category=transactional) | No (included) |
| `chat_interactive` | Two-way freetext/inbound | `ChatBillingService` (category=interactive) | Yes |
| `marketing` | Seller marketing campaigns | `SellerMarketingService` / sms_queue | Yes |
| `custom` | Ad-hoc custom messages | `TextMessageService::sendCustomText()` | Yes |

All SMS tracking throughout this PRD references these exact category codes.

#### Feature 2: Per-Store Billing Configuration
- **User Story:** As a platform admin, I want to configure billing rates and rules per store so that each store can have customized pricing.
- **Acceptance Criteria:**
  - [ ] Base rate defaults are concept-dependent: PC/OU/SE/CM = $175/mo, PIAS = $99/mo (derived from `storeType`)
  - [ ] Admin can override the default base rate with a custom rate per store
  - [ ] Admin can configure per-SMS-category rates per store (rate per message/segment)
  - [ ] Admin can mark specific SMS categories as "included" (free) or "billable" per store
  - [ ] Admin can set an "included free count" per SMS category per store, measured in **messages** (not segments). Resets each billing period. Example: first 50 survey messages free, regardless of segment count per message.
  - [ ] Platform-wide default rates exist; stores inherit defaults unless overridden
  - [ ] Premium module rate configurable per store (default $30/mo)
  - [ ] Optional billing contact email per store (falls back to owner email if not set)
  - [ ] Configuration changes take effect on the next billing period, not retroactively

#### Feature 3: Automated Monthly Invoice Generation
- **User Story:** As a platform admin, I want invoices auto-generated on the 1st of each month so that billing happens without manual intervention.
- **Acceptance Criteria:**
  - [ ] TaskEngine job runs on the 1st of each month
  - [ ] Job generates one invoice per active store for the previous calendar month
  - [ ] Invoice includes all line items: base rate, premium module (if applicable), SMS usage by category
  - [ ] Each line item shows: description, quantity, unit rate, total amount
  - [ ] Included/free items appear with $0.00 rate and quantities for transparency
  - [ ] Invoice has a unique invoice number (format: `BK-{YYMM}-{typeNum}`, e.g., `BK-2602-ou00`). One invoice per store per period ensures uniqueness.
  - [ ] Invoice shows period start/end dates, issue date, and total amount
  - [ ] Job is idempotent (re-running for same period doesn't create duplicate invoices)

#### Feature 4: Admin Billing Dashboard
- **User Story:** As a platform admin, I want a dashboard showing billing across all stores so that I can monitor revenue and identify issues.
- **Acceptance Criteria:**
  - [ ] Dashboard shows list of all stores with their current period's billing total
  - [ ] Can filter by billing period (month/year selector)
  - [ ] Summary row shows platform-wide totals (total base, total premium, total SMS, grand total)
  - [ ] Each store row is clickable to drill into that store's invoice detail
  - [ ] Can export billing data (CSV or Excel)
  - [ ] Shows invoice status per store (generated, not yet generated)
  - [ ] Accessible only to users with admin-level permissions

#### Feature 5: Store Billing View
- **User Story:** As a store owner, I want to see my store's billing details so that I understand what I'm being charged for.
- **Acceptance Criteria:**
  - [ ] New "Billing" item in store sidebar menu
  - [ ] Current period summary showing running total of charges by category
  - [ ] List of past invoices with period, total, and status
  - [ ] Invoice detail view showing all line items
  - [ ] PDF download button for any invoice
  - [ ] Accessible to store owners and users with billing permission
  - [ ] Legacy PDF invoices (from existing Invoice.php system) also shown in invoice list

#### Feature 6: Billing API
- **User Story:** As a platform admin, I want API endpoints to retrieve billing data so that I can build integrations and the mobile app can display billing information to store owners.
- **Acceptance Criteria:**
  - [ ] `GET /api/billing/summary?period=YYYY-MM` — Returns billing summary for all stores (admin only)
  - [ ] `GET /api/billing/:typeNum?period=YYYY-MM` — Returns billing detail for a specific store
  - [ ] `GET /api/billing/:typeNum/invoices` — Returns list of invoices for a store
  - [ ] `GET /api/billing/:typeNum/invoices/:invoiceId` — Returns detailed invoice with line items
  - [ ] `GET /api/billing/:typeNum/usage?period=YYYY-MM` — Returns current period usage (running totals)
  - [ ] All endpoints respect permission checks (admin vs store-level access)
  - [ ] Responses include pagination: default 50 items/page, max 200, sorted by period descending. Format: `{ data: [...], pagination: { page, pageSize, total } }`

#### Feature 7: SMS Usage Tracking at TextMessageService Level
- **User Story:** As a platform admin, I want every text message automatically logged for billing so that no SMS usage goes untracked.
- **Acceptance Criteria:**
  - [ ] Every `send*()` method in TextMessageService logs the send to the billing system
  - [ ] Log includes: store typeNum, SMS category, segment count, provider, timestamp, billable flag
  - [ ] Category is determined by which send method was called (sendBuyText = "buy_completion", sendSurveyText = "survey", etc.)
  - [ ] Failed sends are tracked but not billable
  - [ ] Existing ChatBillingService data feeds into the unified billing system
  - [ ] Tracking adds no more than 50ms p95 latency to SMS send operations (synchronous DB insert to central billing table)

### Should Have Features

#### Feature 8: PDF Invoice Generation
- **User Story:** As a store owner, I want to download a professional PDF invoice so that I can use it for accounting and tax purposes.
- **Acceptance Criteria:**
  - [ ] PDF includes BuyerKiosk branding, store details, billing period
  - [ ] Line items formatted in a clear table
  - [ ] Subtotals by category (Subscriptions, SMS Usage)
  - [ ] Grand total prominently displayed
  - [ ] Invoice number, issue date, and period dates shown
  - [ ] PDF generated on-demand (not pre-generated and stored)

#### Feature 9: Billing Period Usage Trends
- **User Story:** As a store owner, I want to see usage trends over time so that I can understand how my costs are changing.
- **Acceptance Criteria:**
  - [ ] Chart showing SMS usage by category over last 6 months
  - [ ] Chart showing total billing amount over last 6 months
  - [ ] Visible on the store billing page
  - [ ] Data loads asynchronously via AJAX, with charts rendering within 2 seconds of page load

### Could Have Features

#### Feature 10: Billing Alerts
- **User Story:** As a store owner, I want to be notified when my SMS usage exceeds a threshold so that I can manage costs proactively.
- **Acceptance Criteria:**
  - [ ] Configurable usage threshold per SMS category
  - [ ] Notification when threshold is reached (in-app or email)
  - [ ] Admin can set global thresholds as defaults

#### Feature 11: Invoice Notes and Adjustments
- **User Story:** As a platform admin, I want to add manual adjustments or credits to an invoice so that I can handle special billing situations.
- **Acceptance Criteria:**
  - [ ] Admin can add a manual line item (credit or charge) with description and amount
  - [ ] Manual adjustments appear on the invoice with clear labeling
  - [ ] Audit trail for who added the adjustment and when

#### Feature 12: Billing Configuration Audit Log
- **User Story:** As a platform admin, I want to see a history of billing configuration changes so that I can track who changed what and when.
- **Acceptance Criteria:**
  - [ ] Log of all rate changes, category enable/disable, and billing configuration updates
  - [ ] Shows who made the change, what changed, old value, new value, timestamp

### Won't Have (This Phase)

- **Payment processing** — No Stripe, PayPal, or credit card charging. Invoices are for tracking/reporting only.
- **Automated payment collection** — No auto-debit or payment reminders.
- **QuickBooks integration** — Future phase. Invoice data could feed into QuickBooks later.
- **Multi-currency support** — All billing in USD only.
- **Tax calculation** — No sales tax, VAT, or tax line items.
- **Billing disputes/ticketing** — No formal dispute resolution workflow.
- **Usage alerts via SMS** — Alerts (Feature 10) would be in-app only, not via text.
- **Retroactive billing adjustments** — Rate changes apply going forward only.
- **Annual billing plans** — Monthly billing only for this phase.

**Invoice Lifecycle:**
Invoices follow a simple lifecycle: `finalized` → `voided` (optional, admin only). There is no "draft" state — auto-generated invoices are immediately finalized and visible to store owners. An admin can void an invoice and regenerate it if rates were incorrectly configured. Voided invoices are kept for audit trail but hidden from store owner view.

## Detailed Feature Specifications

### Feature: Automated Monthly Invoice Generation (Feature 3)

**Description:** A TaskEngine scheduled job that runs on the 1st of every month, iterates through all active stores, calculates their charges for the previous calendar month, and creates an invoice record with line items.

**User Flow:**
1. TaskEngine scheduler triggers the invoice generation job at midnight on the 1st
2. System retrieves all stores where `billingActive = 1`
3. For each store, system:
   a. Creates an invoice record for the previous calendar month
   b. Adds base rate line item (from store's billing configuration)
   c. Checks if premium was active at any point during the period → adds premium line item if yes
   d. Aggregates SMS usage by category from the usage log
   e. For each SMS category: calculates quantity, applies store's rate, determines if billable or included
   f. Applies any "included free count" deductions per category
   g. Calculates invoice total
4. System marks invoice as "finalized" (immediately visible to store owners)
5. Admin can review all invoices via the billing dashboard

**Business Rules:**
- Rule 1: If premium was active for even 1 day during the billing period, charge the full monthly premium rate.
- Rule 2: SMS categories marked as "included" in the store's config appear as $0.00 line items with usage quantities.
- Rule 3: If a store has an "included free count" for a category (e.g., 50 free survey texts), only texts beyond that count are charged. The free texts still appear as a $0.00 line item showing the quantity.
- Rule 4: Failed SMS sends (delivery_status = 'failed') are NOT billed but MAY appear in usage reporting.
- Rule 5: Invoice numbers use format `BK-{YYMM}-{typeNum}` (e.g., `BK-2602-ou00`). One invoice per store per billing period guarantees uniqueness. The `typeNum` is the store's unique identifier throughout the system.
- Rule 6: Re-running the job for a period that already has invoices does NOT create duplicates. It skips stores that already have an invoice for that period.
- Rule 7: If a store's billing was activated mid-month, the base rate is still charged in full for that month (no pro-rating for base rate).
- Rule 8: Calendar month means the period covers from the 1st 00:00:00 to the last day 23:59:59 in UTC.

**Edge Cases:**
- Scenario 1: Store has no SMS usage for the month → Invoice generated with only base rate (and premium if applicable). No SMS line items with 0 quantity (clean invoice).
- Scenario 2: Store deactivated mid-month → Still generates invoice for usage up to deactivation. Base rate still charged in full.
- Scenario 3: Premium activated and deactivated within same month → Full premium charge applies (Rule 1).
- Scenario 4: New store created on the 15th → First invoice covers 15th-end of month. Base rate charged in full.
- Scenario 5: TaskEngine job fails mid-run → Job is idempotent. Re-running picks up where it left off (skips already-invoiced stores).
- Scenario 6: SMS category added to billing catalog mid-month → Only texts sent AFTER the category was added are tracked. Historical texts before the category existed are not retroactively billed.
- Scenario 7: Rate changed mid-month → Invoice uses the rate in effect at the time of invoice generation (current rate). Rate changes are not retroactive.
- Scenario 8: Store has no billing configuration → System uses platform defaults based on `storeType` for base rate and global defaults for SMS rates. Invoice generated normally.
- Scenario 9: Store timezone vs UTC → All billing periods use UTC boundaries (1st 00:00:00 UTC to last day 23:59:59 UTC). SMS timestamps stored in UTC. Store timezone only affects display formatting.
- Scenario 10: Admin voids and regenerates invoice → Old invoice marked as "voided" (kept for audit trail). New invoice generated with current rates applied to same period's usage data. New invoice number uses same format (only one active invoice per store per period).
- Scenario 11: Duplicate SMS send (retry) → Each successful send creates its own usage record. If same message retried due to provider failure, only successful delivery is billed. Failed attempts logged with `billable = false`.

### Feature: Per-Store Billing Configuration (Feature 2)

**Description:** Each store has a billing configuration that defines its base rate, which SMS categories are billable, what rate applies per category, and how many free texts are included per category. Platform defaults exist that stores inherit unless overridden.

**User Flow:**
1. Admin navigates to store's admin settings
2. Opens "Billing Configuration" section
3. Sees current configuration with platform defaults indicated
4. Adjusts base monthly rate (or keeps default)
5. For each SMS category:
   - Toggles billable/included
   - Sets per-message/segment rate (or keeps default)
   - Sets included free count (0 = none included)
6. Sets premium module rate (or keeps default $30)
7. Saves configuration
8. Confirmation shown: "Changes take effect on next billing period"

**Business Rules:**
- Rule 1: Platform defaults apply to all stores that haven't been customized.
- Rule 2: Once a store has a custom rate for any field, that field no longer inherits the default (even if the default changes).
- Rule 3: A store can be "reset to defaults" to re-inherit platform defaults.
- Rule 4: Rate changes apply to the NEXT billing period only, never retroactively.
- Rule 5: Disabling a category mid-month means texts already sent in that category during the current period will still be billed at the rate in effect at invoice generation time.

**Edge Cases:**
- Scenario 1: Admin changes platform default rate → Only stores still inheriting defaults are affected. Stores with custom rates are not changed.
- Scenario 2: New SMS category added to code → All stores automatically inherit the default configuration for the new category.
- Scenario 3: SMS category removed from code → Existing usage for that category remains on past invoices. Category no longer appears in configuration.

### Feature: SMS Usage Tracking (Feature 7)

**Description:** Every text message sent through TextMessageService is automatically logged for billing purposes. The tracking happens at the service level so no caller can bypass it.

**User Flow:**
1. Any part of the system calls `TextMessageService->sendBuyText()`, `sendSurveyText()`, `sendCustomText()`, etc.
2. TextMessageService sends the text via Twilio/Vonage as normal
3. After send (success or failure), the service logs a usage record:
   - Store typeNum
   - SMS category (derived from method name)
   - Segment count (calculated from message length)
   - Provider used (twilio/vonage)
   - Success/failure status
   - Timestamp
   - Billable flag (determined by store's billing configuration for that category)
4. Log entry is written to the central billing usage table
5. No impact to the SMS send flow — logging is a secondary concern

**Business Rules:**
- Rule 1: Category mapping follows the Canonical SMS Category Taxonomy defined in Feature 1. TextMessageService methods map as: `sendBuyText()` → `buy_completion`, `sendServiceText()` → `service_completion`, `sendSurveyText()` → `survey`, `sendCustomText()` → `custom`. Chat categories (`chat_transactional`, `chat_interactive`) are tracked by ChatBillingService. Marketing (`marketing`) is tracked by SellerMarketingService.
- Rule 2: Chat messages already tracked by ChatBillingService continue to be tracked there. The unified billing system reads from ChatBillingService data at invoice generation time.
- Rule 3: Segment count is calculated using GSM-7/UCS-2 encoding rules (already implemented in ChatMessage::calculateSegmentCount).
- Rule 4: If the SMS send fails, the usage is logged with `billable = false` and `status = 'failed'`.
- Rule 5: **Billable vs rate timing distinction**: The `billable` flag (whether a category is charged or included) is snapshotted at send time based on the store's current config. The `rate` (cost per segment) is applied at invoice generation time using the store's config at that point. This means: changing a category from "included" to "billable" mid-month does NOT retroactively bill already-sent texts, but changing the per-segment rate DOES apply the new rate to all usage in that period.

**Edge Cases:**
- Scenario 1: TextMessageService send throws exception → Log entry still created with failed status (wrap in try/catch).
- Scenario 2: Database unavailable for logging → SMS still sends successfully. Usage logged to fallback file log (`logs/billing-sms-fallback.log`) in JSON format. A reconciliation TaskEngine job can import missed records from the fallback log.
- Scenario 3: Bulk marketing sends → Each individual message gets its own usage record (not batched).

## Success Metrics

### Key Performance Indicators

- **Adoption:** 100% of active stores have auto-generated invoices within first month of launch
- **Engagement:** Admin accesses billing dashboard at least monthly; 50%+ of store owners view their billing page within 3 months
- **Quality:** Invoice accuracy rate > 99% (no missed line items or incorrect calculations); zero duplicate invoices
- **Business Impact:** Reduce manual billing effort by >90%; enable per-store revenue tracking

### Tracking Requirements

| Event | Properties | Purpose |
|-------|------------|---------|
| `billing.invoice_generated` | typeNum, period, totalAmount, lineItemCount | Track invoice generation success and volume |
| `billing.invoice_viewed` | typeNum, period, viewerUserId, viewerRole | Measure store owner engagement with billing |
| `billing.invoice_pdf_downloaded` | typeNum, period, invoiceId | Track PDF usage |
| `billing.config_updated` | typeNum, changedFields, updatedByUserId | Audit configuration changes |
| `billing.dashboard_viewed` | period, userId | Measure admin dashboard usage |
| `billing.sms_usage_logged` | typeNum, category, segmentCount, billable, provider | Real-time SMS tracking |
| `billing.generation_job_completed` | storeCount, totalRevenue, duration, errors | Monitor job health |
| `billing.generation_job_failed` | error, storesProcessed, storesRemaining | Alert on job failures |

---

## Constraints and Assumptions

### Constraints
- **No payment processing** — This system tracks and reports billing. Actual payment collection is external.
- **PHP 8.x + Slim 2.6.2 stack** — Must work within existing framework. No new frameworks or languages.
- **Multi-store DB architecture** — SMS usage data may be in per-store DBs while billing data must be centralized.
- **TaskEngine capacity** — Invoice generation job must complete within reasonable time even with hundreds of stores.
- **Existing ChatBillingService** — Must integrate with, not replace, the existing chat SMS tracking.
- **Migration system** — All schema changes must go through the conductor migration system (JSON format).
- **Syncfusion components** — Use Syncfusion EJ2 for data grids, charts, and PDF generation where possible.

### Assumptions
- All stores on the platform are billable (billingActive flag determines if they generate invoices).
- SMS providers (Twilio/Vonage) do not change their per-segment pricing frequently enough to require dynamic rate importing.
- Store owners have web access to view billing (no mobile-first billing view required for MVP).
- The existing `stores` table in `kiosk_buykiosk` is the appropriate place for billing configuration.
- Calendar month billing (1st to last day) is acceptable for all stores.
- Invoice generation for all stores can complete within a single TaskEngine job run (< 10 minutes).
- The existing permission system (`uri_store_settings`) is sufficient for billing access control.

## Risks and Mitigations

| Risk | Impact | Likelihood | Mitigation |
|------|--------|------------|------------|
| SMS tracking misses some sends (code paths that bypass TextMessageService) | High | Medium | Audit all SMS send code paths during implementation. Add monitoring for untracked sends. |
| Invoice generation job takes too long with many stores | Medium | Low | Process stores in parallel or batches. Monitor job duration. Set timeout alerts. |
| Incorrect billing calculations lead to store disputes | High | Low | Extensive unit tests for calculation logic. Invoice review workflow before finalizing. Audit trail for all changes. |
| Legacy ChatBillingService data format conflicts with unified system | Medium | Medium | Design billing aggregation to read ChatBillingService data as-is, transforming at query time rather than migrating. |
| Rate changes applied retroactively by mistake | High | Low | Business rule enforcement: rates at invoice generation time, not retroactive. Clear UI messaging on effective dates. |
| Store owners confused by $0.00 line items | Low | Medium | Clear labeling: "Included" badge on free items. Tooltip explaining included vs billable. |

## Open Questions

- [x] Should base rate be pro-rated for new stores? → Decision: No, full month charge regardless of start date.
- [x] Should premium be pro-rated? → Decision: No, full month if active at any point.
- [x] How to handle SMS category changes mid-month? → Decision: Current rate at invoice generation time applies.
- [x] Where should billing config live? → Decision: Central `kiosk_buykiosk` database, code-defined catalog.
- [x] What is the default base rate for stores? → **Concept-dependent**: PC/OU/SE/CM = $175/mo, PIAS = $99/mo. Base rate determined by `storeType` column.
- [x] What are the default per-text rates for each SMS category? → **$0.01/segment** for all billable SMS categories (unified rate).
- [x] Should there be a "billing contact email" per store? → **Yes**, new optional field per store. Falls back to store owner's email if not set.
- [x] Who approves/finalizes invoices? → **Auto-finalized**. Invoices are immediately visible to store owners when generated. Admin can review anytime.

---

## Supporting Research

### Competitive Analysis
SaaS billing systems like Stripe Billing, Chargebee, and Recurly provide:
- Usage-based billing with metering
- Per-customer pricing overrides
- Invoice generation and PDF export
- Billing period customization

BuyerKiosk's approach is intentionally simpler: tracking and reporting without payment processing. This aligns with the current manual billing model while providing the data foundation for future payment integration.

### User Research
Based on existing platform usage:
- Store owners frequently ask "what am I being charged for?" indicating a transparency gap
- Admin spends significant time manually compiling billing data each month
- Premium module (Spec 035) introduced the first per-store add-on, creating the need for line-item billing
- Two-way SMS chat (Spec 009) was the first usage-based feature, leading to ChatBillingService as a proof of concept

### Market Data
- B2B SaaS platforms increasingly use hybrid billing (fixed subscription + usage metering)
- SMS costs range from $0.0075-$0.02/segment depending on provider and volume
- 78% of B2B buyers prefer itemized invoices over flat-rate billing (Salesforce 2025 B2B Commerce Report)
- Usage-based billing transparency reduces churn by 15-20% in B2B SaaS (OpenView Partners)
