# Specification: 036-billing-tracking-system

## Status

| Field | Value |
|-------|-------|
| **Created** | 2026-02-10 |
| **Current Phase** | Implementation Plan Reviewed — Ready for Implementation |
| **Last Updated** | 2026-02-10 |

## Documents

| Document | Status | Notes |
|----------|--------|-------|
| product-requirements.md | completed | Codex reviewed: 3 blockers resolved, 3 important fixed, 4 medium fixed, 2 enhancements added. 12 features total. |
| solution-design.md | completed | Codex reviewed: 1 blocker (resolved), 4 important (resolved), 4 enhancements (3 resolved, 1 deferred). All 8 ADRs confirmed. Validation checklist passed. |
| implementation-plan.md | completed | 8 phases, ~190 tasks. Codex reviewed: 2 blockers + 5 important + 2 enhancements resolved. Ready for implementation. |

**Status values**: `pending` | `in_progress` | `completed` | `skipped`

## Decisions Log

| Date | Decision | Rationale |
|------|----------|-----------|
| 2026-02-10 | Unified billing system | Consolidate base rate, premium, and all SMS categories into one billing/invoice system |
| 2026-02-10 | Tracking + Reporting + Full Invoicing | Both billing dashboard and formal invoice generation with line items |
| 2026-02-10 | Per-category SMS rate table | Each store gets per-category rates, included counts, and enable/disable per SMS type |
| 2026-02-10 | Admin + Store Owner views | Global admin sees all stores; store owners see their own billing via sidebar item |
| 2026-02-10 | Calendar month billing cycle | All stores bill on 1st of month for previous month. Simplest for aggregation |
| 2026-02-10 | Free items shown as $0.00 | Included texts appear on invoice with quantity and $0.00 for transparency |
| 2026-02-10 | Full month premium charge | If premium active at any point during billing period, charge full $30 |
| 2026-02-10 | In-app dashboard + PDF invoices | Both interactive dashboard and downloadable PDF for store records |
| 2026-02-10 | Code-defined billing catalog | Line item types as PHP enums/constants. Adding new items requires code change + migration |
| 2026-02-10 | Auto-generate via TaskEngine | Scheduled job on 1st of month generates invoices for all active stores |
| 2026-02-10 | TextMessageService-level tracking | Billing hook in send*() methods - single point of truth for all SMS |
| 2026-02-10 | Keep legacy Invoice.php | Old PDF invoices remain accessible alongside new billing system |
| 2026-02-10 | Concept-based base rates | PC/OU/SE/CM = $175/mo, PIAS = $99/mo. Determined by storeType column. Admin can override per store. |
| 2026-02-10 | $0.01/segment all SMS categories | Unified rate for all billable SMS. Simpler than per-category rates. |
| 2026-02-10 | Billing contact email field | Optional per-store billing email. Falls back to owner email if not set. |
| 2026-02-10 | Auto-finalize invoices | Invoices immediately visible to store owners. No admin approval workflow needed. |
| 2026-02-10 | PRD Codex review completed | 3 blockers (rate timing, category taxonomy, invoice ID), 3 important, 4 medium issues resolved |
| 2026-02-10 | Billable flag at send time, rate at invoice time | Resolves timing contradiction: category billable/included snapshotted at send; dollar rate applied at invoice generation |
| 2026-02-10 | Canonical SMS category taxonomy defined | 7 categories: buy_completion, service_completion, survey, chat_transactional, chat_interactive, marketing, custom |
| 2026-02-10 | Invoice ID uses typeNum | Format: BK-{YYMM}-{typeNum}. One invoice per store per period. |
| 2026-02-10 | Invoice lifecycle: finalized → voided | No draft state. Admin can void + regenerate. Voided invoices kept for audit. |
| 2026-02-10 | Included free count in messages (not segments) | Resets each billing period. Measured in messages regardless of segment count. |
| 2026-02-10 | UTC billing period boundaries | All periods use UTC. Store timezone for display only. |
| 2026-02-10 | ADR-1: Central DB for billing | All billing tables in kiosk_buykiosk for cross-store reporting |
| 2026-02-10 | ADR-2: Separate billingSmsUsage table | New table, not extending chat_sms_usage. Different schema needs. |
| 2026-02-10 | ADR-3: Hook in TextMessageService | SMS tracking in send*() methods, not in provider senders |
| 2026-02-10 | ADR-4: Required + Null Object pattern | SmsUsageTrackerInterface required in constructor. NullSmsUsageTracker for tests. |
| 2026-02-10 | ADR-5: Single source via dual-write | billingSmsUsage is sole billing source. ChatApiController dual-writes. chat_sms_usage kept for chat admin views only. |
| 2026-02-10 | ADR-6: Syncfusion EJ2 Grid + Chart | For dashboard tables and usage trend charts |
| 2026-02-10 | ADR-7: On-demand PDF generation | PDFs generated when downloaded, not pre-stored |
| 2026-02-10 | ADR-8: Config split | Simple billing fields on stores table + normalized billingSmsCategoryConfig table |
| 2026-02-10 | SDD Codex review completed | 1 blocker (marketing SMS), 4 important (config timing, rate model, defaults, pagination), 4 enhancements resolved |
| 2026-02-10 | Marketing SMS category: retained but inactive | Marketing system removed (spec 028). Enum value kept for forward compat. No hook needed now. |
| 2026-02-10 | Per-message billing (not per-segment) | V1 bills per-message for simplicity. Segment counts stored for future per-segment option. |
| 2026-02-10 | Platform defaults as PHP constants | Default SMS category config (billable/rate/freeCount) defined in BillingConfigService constants. No defaults table needed. |
| 2026-02-10 | Config timing split clarified | Billable flag locked at send time in usage record. Rate applied at invoice generation from current config. Explicitly documented in algorithm. |
| 2026-02-10 | ADR-2 trade-off text reconciled with ADR-5 | Removed stale "query two tables" trade-off from ADR-2. Aligned with ADR-5 dual-write decision. |
| 2026-02-10 | Features 10, 11, 12 explicitly deferred | Billing Alerts, Invoice Adjustments, Config Audit Log deferred to future phase with design notes. |
| 2026-02-10 | PDF template spec added | Invoice PDF layout defined: branding, line items table, category subtotals, grand total. Uses TCPDF or Syncfusion. |
| 2026-02-10 | API pagination standardized | Summary endpoint: page/pageSize/sort params. Store detail: latestInvoice only, use /invoices for full list. |
| 2026-02-10 | Implementation Plan created | 8 phases: Foundation → Repositories → Services → Integration Hooks → TaskEngine Job → API Layer → UI Layer → E2E Validation |
| 2026-02-10 | PLAN Codex review completed | 2 blockers, 5 important, 2 enhancements. All resolved — see PLAN Review Summary below. |
| 2026-02-10 | Legacy Invoice.php integration added | Explicit build task for merging legacy PDFs into store billing invoice list (Blocker B1) |
| 2026-02-10 | Segment count method pinned | Decision: extract ChatMessage::calculateSegmentCount() into shared utility (Blocker B2) |
| 2026-02-10 | Config timing split test added | Concrete mid-period config change test to prove billable flag snapshot vs rate-at-invoice behavior |
| 2026-02-10 | Phase 6 dependency relaxed | API layer can start after Phase 3, parallel with Phases 4+5 |

## PLAN Review Summary (2026-02-10)

**Reviewer**: Codex MCP (read-only sandbox)

### Findings Addressed

| Category | Count | Status |
|----------|-------|--------|
| Blockers | 2 | All resolved (legacy Invoice.php integration task added; segment count method pinned) |
| Important | 5 | All resolved (billing email fallback, billingConfigUpdatedAt, test audit, config timing test, SDD risk review) |
| Enhancements | 2 | All resolved (Phase 6 dependency relaxed, export button wiring clarified) |

### Key Changes Made

1. **Added T4.1.6-T4.1.7**: Segment count method investigation + TextMessageService test audit
2. **Added T4.2.10-T4.2.11**: Shared segment calculator implementation + existing test updates
3. **Added T3.3.8-T3.3.9**: Billing contact email fallback test + billingConfigUpdatedAt test
4. **Added T3.5.9a**: Config timing split concrete test scenario
5. **Added T6.2.13**: Legacy invoice list API test
6. **Added T7.4.4**: Legacy Invoice.php PDF integration in store billing view
7. **Added T8.5a**: SDD risk review section with 6 risk mitigation verification tasks
8. **Updated Phase 6 dependency**: Can start after Phase 3 (not Phase 5)
9. **Clarified T7.3.6**: Export button wiring to server-side endpoint vs grid export

### Readiness Assessment
- [x] All blockers resolved
- [x] Plan covers all SDD components
- [x] Tasks are actionable and well-sequenced
- [x] Test tasks included in each phase (TDD)
- [x] Dependencies correctly mapped (with relaxed Phase 6)
- [x] README updated with review notes
- **Decision: Ready for implementation**

## SDD Review Summary (2026-02-10)

**Reviewer**: Codex MCP (read-only sandbox) + Codebase Verification Agent

### Findings Addressed

| Category | Count | Status |
|----------|-------|--------|
| Blockers | 1 | Resolved (marketing SMS — system removed per spec 028, enum retained) |
| Important | 4 | All resolved (config timing, rate model, defaults, pagination) |
| Enhancements | 4 | 3 resolved (ADR reconciliation, PDF spec, Could-Have deferrals), 1 N/A |

### Codebase Verification Results

All 10 integration points verified against actual codebase:
- TextMessageService constructor: Confirmed `(TextSenderInterface, Store, PDO)` — adding SmsUsageTracker as 4th param is correct approach
- Store::setTextMessageService(): Private method called from `createStoreFromRowArray()` — confirmed as sole construction site
- ChatBillingService: Writes to `chat_sms_usage` in central DB — confirmed schema and `trackUsage()` method
- PremiumService/Repository: `premiumEventLog` table confirmed, `logEvent()` method with JSON properties
- TaskEngine BaseJob: `handle()`, `checkpoint()`, `progress()` methods all confirmed
- TrialExpirationJob: Global scope job pattern confirmed — matches InvoiceGenerationJob design
- Store billing fields: All 6 existing billing columns confirmed (billingActive, billingType, etc.)
- Sidebar template: Permission-gated menu items with Font Awesome icons confirmed
- Migration JSON format: Confirmed from premium migration files (alter_table, create_table operations)

### Key Architectural Decisions Confirmed
- All 8 ADRs remain valid after review
- ADR-2 trade-off text reconciled with ADR-5 (no more stale "two tables" reference)
- Config timing split explicitly documented in invoice algorithm

### Readiness Assessment
- [x] All blockers resolved
- [x] Design covers all Must-Have PRD requirements (Features 1-7)
- [x] Should-Have features designed (Features 8-9)
- [x] Could-Have features explicitly deferred with future design notes (Features 10-12)
- [x] Architecture sound and verified against codebase
- [x] Interfaces clearly defined with pagination standardized
- [x] Security and error handling addressed
- [x] Validation checklist passed
- **Decision: Ready for Implementation Plan phase**

## Context

Multi-store billing tracking system for BuyerKiosk SaaS platform. Tracks:

1. **Base rate** per store (monthly subscription)
2. **Premium scheduling module** (enabled/disabled add-on, $30/mo from spec 035)
3. **Text message usage** with category-based pricing:
   - Buy Completion texts: free/included
   - Two-way customer texting: per-text pricing
   - Survey texts: per-text pricing
   - Other categories TBD
4. **Per-store customization** of rates and included/excluded items
5. **Extensible line-item system** for future billing additions

### Requirements Summary
- Admin billing report across all stores
- API for billing details (all stores or individual)
- Store-level invoice visibility
- Per-store rate customization
- Flexible line-item architecture for future items

### Related Specifications
- `035-premium-scheduling-module` - Premium module already implemented with `premiumStatus` column
- `009-two-way-sms-chat` - Two-way SMS infrastructure
- `028-text-marketing-removal` - SMS category changes
- `018-store-configuration` - Store settings infrastructure

### Existing Infrastructure
- `BuyerKiosk\Premium\` namespace - Premium service, repository, event logging
- `BuyerKiosk\SMS\TextMessageService\` - Text sending abstraction (Twilio/Vonage)
- `BuyerKiosk\Core\Store` - Store entity with configuration
- Multi-store DB architecture (`kiosk_users` central, `kiosk_{typeNum}` per-store)

---
*This file is managed by the specification-management skill.*
