# Specification: 046-server-side-goals-forecasting

## Status

| Field | Value |
|-------|-------|
| **Created** | 2026-04-13 |
| **Current Phase** | Implementation Complete — All 8 Phases Delivered |
| **Last Updated** | 2026-04-21 |

## Documents

| Document | Status | Notes |
|----------|--------|-------|
| product-requirements.md | completed | Codex-reviewed. 13 features, 14 business rules, 14 edge cases. |
| solution-design.md | completed | Codex-reviewed. 10 ADRs confirmed. All honored in implementation. |
| implementation-plan.md | completed | 8 phases, ~190 tasks. All phases delivered. |

## Implementation Summary (2026-04-21)

| Metric | Value |
|--------|-------|
| **PHP Source Files** | 17 (`src/BuyerKiosk/Goals/`) |
| **Test Files** | 15 (`tests/Unit/Goals/`) |
| **Tests** | 196 |
| **Assertions** | 897 |
| **PHPStan Errors** | 0 |
| **JS Controllers** | 6 (`public_html/js/admin/goals/`) |
| **Templates** | 6 (`templates/themes/default/admin/goals/`) |
| **CSS Module** | 1 (`css/admin/modules/goals.css`, 786 lines) |
| **Migrations** | 3 (goalConfigurations, goalConfigAudit, goalForecast) |
| **API Endpoints** | 6 (config GET/PUT, preview POST, forecast GET, variance GET, audit GET) |
| **Route Files** | 2 (admin/goals.php, groups/goals-api.php) |

### ADR-9 Deviation Note
SDD specified Syncfusion Schedule for Method 2 calendar. Implementation uses a custom HTML table grid instead, as the Schedule component is designed for events, not per-day data entry. All functional requirements are met.

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

## Decisions Log

| Date | Decision | Rationale |
|------|----------|-----------|
| 2026-04-13 | Server primary, Sync fallback | Graceful transition; no disruption for stores still using Sync app |
| 2026-04-13 | All 3 methods (fixed + completed) | Method 0 bug fix (buys growth %), Method 2 completion with calendar grid + smart prefill |
| 2026-04-13 | 365-day forecast horizon | Enables annual planning, quarterly reviews, and year-over-year projections |
| 2026-04-13 | Smart cascade fallback for missing data | 12+ mo → standard lookup; 3-11 mo → average; <3 mo → Method 1 defaults. With confidence indicators. |
| 2026-04-13 | Calendar grid with smart prefill for Method 2 | Pre-fill from Method 0/1, allow manual override per day, average buttons per weekday |
| 2026-04-13 | Per-store only (no corporate defaults) | Simplicity first. Cross-store benchmarking is a future Could Have |
| 2026-04-13 | Hourly goal distribution | Use hourlyStaffingMetrics history + manager time-band adjustments interpolated to hourly |
| 2026-04-13 | Use existing KPI config for toggles | Leverage workbook_kpi_config (showGoal/showComps) instead of replicating Sync's 4-toggle system |
| 2026-04-13 | Full period comparison suite | WTD/MTD/YTD + trailing 7/30/90 + same-period-last-year |
| 2026-04-13 | No real-time broadcasting | Server calculates, clients fetch on demand. No Ably updateGoals replication. |
| 2026-04-13 | Keep all method settings + preview | Switching methods preserves all configs; side-by-side preview before committing |
| 2026-04-13 | Historical + time-band hourly adjustments | Managers set simple time bands, system interpolates to hourly using historical pattern shape |
| 2026-04-13 | Config in central DB, cache in store DB | Master settings in kiosk_buykiosk for management. Computed daily goals cached in store DB for performance. |
| 2026-04-13 | Standalone goals admin page | Dedicated /admin/:typeNum/goals page |
| 2026-04-13 | Admin edit, Manager view | Store admins configure goals. Managers can view settings and forecasts, not edit. |
| 2026-04-13 | Full audit trail with config snapshots | Every save logged with who/what/when/old/new + full JSON config snapshot |
| 2026-04-13 | Hybrid pre-compute + invalidate | Nightly cron pre-computes 365 days. Settings changes invalidate and recompute affected range. |
| 2026-04-13 | Versioned goal config snapshots | Full config blob stored alongside each audit entry. Minimal storage, high retrospective value. |
| 2026-04-13 | Method 2 unconfigured months auto-fill | Unconfigured months fall back to Method 0/1 in 365-day forecast. Manager only overrides months they care about. (Codex review blocker resolved) |
| 2026-04-13 | Store timezone, Monday week start | All calculations use store's configured timezone. Weeks start Monday. Today = midnight-to-midnight store TZ. (Codex review blocker resolved) |
| 2026-04-13 | PRD Codex review completed | 2 blockers resolved, 2 important items addressed, 6 edge cases added, default distributions documented |
| 2026-04-13 | Syncfusion-heavy UI with Schedule for Method 2 | Tab component for method switching, NumericTextBox for inputs, Schedule (month view) for calendar grid |
| 2026-04-13 | Single JSON config table | goalConfigurations table with methodSettings JSON blob. Simpler than 3 normalized tables. |
| 2026-04-13 | One-row-per-day forecast cache with hourly JSON | goalForecast table per store DB. 24-float array for hourly distribution. Always consumed as complete set. |
| 2026-04-13 | Dedicated goalConfigAudit table | oldValueJson, newValueJson, configSnapshotJson per change. Full retrospective capability. |
| 2026-04-13 | TaskEngine job for nightly recompute | GoalForecastComputeJob runs nightly per store. Follows existing PosDataCatchupJob pattern. |
| 2026-04-13 | Four-service architecture | GoalConfigService, GoalCalculationEngine, GoalForecastService, GoalVarianceService. Split by responsibility. |
| 2026-04-13 | New API route group /api/:typeNum/goals/ | 6 endpoints: config GET/PUT, preview POST, forecast GET, variance GET, audit GET |
| 2026-04-13 | Inline Method 2 editing in day cells | Click day cell in Syncfusion Schedule month view to edit sales/buys targets inline |
| 2026-04-13 | Full page with smart defaults for first-time UX | New stores see Method 1 pre-selected with system defaults. Guided setup experience. |
| 2026-04-13 | Server-side AJAX preview | Preview calculations happen server-side via POST /api/:typeNum/goals/preview. No client-side math. |
| 2026-04-13 | SDD Codex review completed | 1 blocker (Method 2 sales+buys schema), 10 important (permissions, async recompute, cache-miss, edge cases), 2 enhancements |
| 2026-04-13 | Method 2 stores sales AND buys per day | Per-day objects: `{"sales": 5000, "buys": 1500}` instead of single value. Fixes blocker. |
| 2026-04-13 | Use existing uri_store_settings permission | No new permission needed. Aligned SDD with PRD. |
| 2026-04-13 | Async recompute on config save | Config save dispatches TaskEngine job (high priority) instead of synchronous 365-day recompute. Prevents request timeouts. |
| 2026-04-13 | Self-healing cache miss | Cache miss on configured store triggers on-demand single-day calculation + cache write. Non-configured stores fall back to LiveFinancials. |
| 2026-04-13 | Snapshot comparison API | Audit endpoint supports compareToId param for side-by-side config diff. |
| 2026-04-13 | fallbackMethod auto-set on method switch | Set to previously active method when switching TO Method 2. Defaults to 0 if Method 2 is first config. |
| 2026-04-13 | Display formatting spec | Goals as whole dollars, variance with cents, percentages to 1 decimal. N/A for zero-goal variance %. |
| 2026-04-13 | 8-phase implementation plan | Foundation → Calc Engine → Data Layer → Services → API → Integration → Frontend → E2E Validation |
| 2026-04-13 | Phases 2+3 parallelizable | Calc engine and data layer have no cross-dependency; can be built simultaneously |
| 2026-04-13 | TDD throughout all phases | Every phase follows Prime → Test → Implement → Validate cycle |
| 2026-04-13 | Full PRD traceability matrix | All 10 in-scope features mapped to specific implementation tasks |
| 2026-04-13 | Plan Codex review completed | 0 blockers, 7 important (missing migration, audit field, API test, concurrent edits, closures, Schedule spike, task split), 2 enhancements |
| 2026-04-13 | Syncfusion Schedule spike added | Prototype before full implementation to de-risk ADR-9 (Schedule for data entry, not events) |
| 2026-04-13 | Early integration checkpoint | Post-Phase 5 API curl/browser test against real data before starting frontend |
| 2026-04-13 | calculatedGoalForDate coverage added | Audit repo + config service tests for populating computed goal at save time |
| 2026-04-13 | PRD Scenarios 5, 6, 10 coverage added | Concurrent edits, average-button override, store closure $0 override |

## Context

Migrate the BuyerKioskSync desktop app's sales & buys goal calculation system to the server. Currently, goal settings and calculations live entirely in the desktop Sync app (C#/.NET, SQLite CONFIG/GOALSETTINGS tables). The server needs these calculations to:

1. **Forecast future goals** for scheduling optimization (spec 038 deterministic solver)
2. **Power server-side reports** (over/short, goal attainment, variance analysis)
3. **Provide goals via API** to mobile apps and web dashboards
4. **Enable multi-day/multi-period forecasting** instead of just "today's goal"

### Source Documentation
- `docs/systems/sync-app-goals-system.md` — Complete reverse-engineering of all 3 goal methods, formulas, DB tables, known bugs

### Key Methods to Replicate
- **Method 0**: Percentage of Prior Year (growth % applied to same-day-of-week last year) — BUG FIX: separate sales/buys growth %
- **Method 1**: Annual Target with Monthly/Daily Distribution (annual $ -> monthly % -> day-of-week %)
- **Method 2**: Monthly Target — COMPLETED with calendar grid, smart prefill, and save functionality

### Related Specs
- 026-ai-smart-scheduling — uses goal data for staffing
- 038-deterministic-scheduling-solver — needs daily revenue targets for shift optimization
- 022-admin-reporting-refresh — could consume goal attainment metrics

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