# FieldOps Cloud Business Logic Rulebook

This file summarises the business rules Claude should verify against code and turn into test cases.

## 1. Auth, Sessions, Demo Entry

Primary files:

- `src\User\Controller\AuthController.php`
- `src\User\Service\AuthService.php`
- `src\User\Repository\UserRepository.php`
- `src\Infrastructure\Security\SessionAuth.php`
- `src\Application\Environment\AppEnvironment.php`
- `public/index.php`

Rules:

- Passwords must be hashed and verified through `PasswordHasher`/`AuthService`.
- Login must create an authenticated session.
- Invalid login must not create an authenticated session.
- Signup creates an owner session.
- Session identities are normalised to `id`, `tenant_id`, `email`, `role`, and optional `name`.
- Support impersonation stores original platform admin user and tenant support context.
- Expired support sessions must return control to the platform admin.
- Demo role switching must be explicit.
- Platform admin demo login must be unavailable when demo mode is disabled.
- Demo user must never be silently promoted to platform admin.

Critical tests:

- Login success/failure.
- Signup success/failure.
- Logout destroys session.
- Production-like `APP_ENV=production` and `DEMO_ENABLED=0` disable demo auto-login.
- `/demo/platform-admin` denied when demo disabled.
- Support impersonation requires platform admin role.
- Support session expiry restores original user.

## 2. RBAC and CSRF

Primary files:

- `src\Infrastructure\Security\RbacService.php`
- `src\Infrastructure\Security\SessionAuth.php`
- `src\Infrastructure\Security\CsrfService.php`
- `src\Application\App.php`

Rules:

- Every protected controller method must call `SessionAuth::requirePermission()`.
- UI navigation hiding is not sufficient; server-side denial must be tested.
- All non-API POST routes require `_csrf`.
- API routes under `/api/` are exempt from central CSRF and must have their own validation/auth/token strategy.
- 403 pages must not leak sensitive details.

Critical tests:

- Every role against every high-risk route.
- Missing CSRF returns 403 before route handler runs.
- Invalid CSRF returns 403 before route handler runs.
- API routes are tested for their own security rules.

## 3. Dashboard

Primary files:

- `src\Dashboard\Controller\DashboardController.php`
- `src\Demo\Service\OperationsDemoData.php`
- `src\Job\Service\JobWorkflowService.php`
- `templates/dashboard/index.php`

Rules:

- Dashboard requires `view_dashboard`.
- Demo dashboard summarises jobs, pending quotes, unpaid invoices, and monthly revenue.
- Quick actions must link to valid routes.
- Dashboard data must not expose platform-only data to tenant users.

Critical tests:

- Counts match demo data and/or repository data.
- Links are valid.
- Role visibility matches navigation rules.

## 4. Clients

Primary files:

- `src\Client\Controller\ClientController.php`
- `src\Client\Service\ClientService.php`
- `src\Client\Repository\ClientRepository.php`
- `src\Client\Repository\DemoClientSessionRepository.php`
- `templates/client/*`

Rules:

- Clients require `view_clients`.
- Create requires `create_clients`.
- Update requires `update_clients`.
- Client name is required.
- Email must be valid when supplied.
- Unsupported status is rejected.
- Demo/session edits must override seeded client rows without creating duplicate display rows.
- Client drill-in supports view and edit by name.

Critical tests:

- Create valid/invalid client.
- Edit seeded client and verify no duplicate.
- Search by name/email/phone/address.
- Tenant isolation in database repository.
- XSS payload in name/address is escaped in list, view, and form.

## 5. Jobs and Workflow

Primary files:

- `src\Job\Controller\JobController.php`
- `src\Job\Service\JobWorkflowService.php`
- `src\Job\Repository\JobRepository.php`
- `src\Job\Repository\DemoJobSessionRepository.php`
- `templates/job/*`

Rules:

- Jobs require `view_jobs`.
- Create requires `create_jobs`.
- Update requires `update_jobs`.
- Team members can view/update only assigned jobs.
- Trainees cannot create jobs.
- Job status, priority, title, client, dates, address, assigned technician, checklist, timeline, financial snapshot, blockers, and next actions are managed through `JobWorkflowService`.
- Detail view must support drill-in by id.
- Job workflow transitions should not allow skipped or unsupported statuses.
- Related actions include schedule, quote, invoice, customer portal, and AI where applicable.

Critical tests:

- Role-based job access, especially team member assigned/unassigned scope.
- Create/edit validation.
- Workflow transition matrix.
- Search/filter.
- Detail view renders checklist/timeline/financial/action data.
- Tenant isolation in repository queries.

## 6. Recurring Jobs

Primary files:

- `src\Recurring\Controller\RecurringJobController.php`
- `src\Recurring\Service\RecurringJobService.php`
- `src\Recurring\Repository\MaintenanceAgreementRepository.php`
- `templates/recurring/index.php`

Rules:

- Recurring agreements define service templates and next run dates.
- Frequencies include weekly, monthly, quarterly, and annual behavior.
- Paused agreements cannot generate jobs.
- Generated jobs must be linked to agreement history.
- Status actions require valid CSRF and permission.

Critical tests:

- Frequency date advancement.
- Create agreement validation.
- Generate job.
- Pause/resume.
- No duplicate generation for the same run window.

## 7. Dispatch

Primary files:

- `src\Dispatch\Controller\DispatchController.php`
- `src\Dispatch\Service\DispatchService.php`
- `src\Dispatch\Repository\CrewRepository.php`
- `templates/dispatch/index.php`

Rules:

- Dispatch board requires `manage_dispatch`.
- Crew creation and assignment are POST actions.
- Jobs can be assigned to technician or crew.
- Assignment must block same-technician or same-crew time conflicts.
- Unavailable technician assignment must be blocked.
- Crew lead should be represented correctly when crew assignment is used.

Critical tests:

- Supervisor/owner/manager access allowed.
- Team member/trainee denied.
- Create crew valid/invalid.
- Assign job to technician.
- Assign job to crew.
- Conflict detection.
- Audit expectations if added later.

## 8. Schedule and Appointments

Primary files:

- `src\Schedule\Controller\ScheduleController.php`
- `src\Schedule\Service\ScheduleService.php`
- `src\Schedule\Repository\DemoAppointmentSessionRepository.php`
- `templates/schedule/index.php`

Rules:

- Schedule requires `view_schedule`.
- Bookings support `job`, `appointment`, `meeting`, and `reminder`.
- Week starts on Monday.
- Time slots are currently hourly from 08:00 to 17:00.
- Duration supports configured options and validation range.
- Customer/attendee can be existing client, potential client, or internal.
- Existing client selection is required when source is `existing`.
- Potential client name is required when source is `potential`.
- Potential client email must be valid if provided.
- Technician can be chosen by id or name.
- Conflicts are detected by technician id if present, otherwise technician name.
- Calendar time slots should be clickable and prefill booking form.

Critical tests:

- Click a time slot and verify date/time populate.
- Book valid appointment.
- Duplicate overlapping booking blocked.
- Existing client and potential client flows.
- Internal meeting flow.
- Week previous/today/next navigation.
- Role denial for trainee.

## 9. Quotes

Primary files:

- `src\Quote\Controller\QuoteController.php`
- `src\Quote\Service\QuoteService.php`
- `src\Quote\Service\QuoteCalculator.php`
- `src\Money\Service\LineItemMoneyCalculator.php`
- `src\Quote\Repository\QuoteRepository.php`
- `templates/quote/*`

Rules:

- Quote list requires `view_quotes`.
- Create requires `create_quotes`.
- Update requires `update_quotes`.
- Quote statuses: `draft`, `sent`, `approved`, `declined`.
- Only draft quotes are editable.
- Quote number is auto-generated when blank and uppercased when provided.
- Client is required.
- Valid-until date must be ISO format in forms.
- Tax rate must be numeric from 0 to 100.
- At least one line item is required.
- Line item description, quantity, and unit price have validation limits.
- Quote totals use shared line item calculator.
- Seeded draft quote edits should override seeded rows without duplicates.
- Approved quotes can be converted to invoices.

Critical tests:

- Create valid quote with multiple line items.
- Reject missing client/line items/bad tax/bad dates.
- Edit draft quote.
- Block edit of sent/approved/declined quote.
- Convert quote to invoice.
- Verify decimal totals and rounding.
- Drill in to quote detail.
- XSS in line item description is escaped.

## 10. Invoices

Primary files:

- `src\Invoice\Controller\InvoiceController.php`
- `src\Invoice\Service\InvoiceService.php`
- `src\Invoice\Service\InvoiceCalculator.php`
- `src\Money\Service\LineItemMoneyCalculator.php`
- `src\Invoice\Repository\InvoiceRepository.php`
- `templates/invoice/*`

Rules:

- Invoice list requires `view_invoices`.
- Create requires `create_invoices`.
- Update requires `update_invoices`.
- Stored statuses: `unpaid`, `partial`, `paid`.
- `overdue` is calculated from due date and unpaid status; manually selected overdue is rejected.
- Unpaid and partial invoices are editable.
- Paid invoices are locked from edit.
- Payment recording validates amount, method, and reference length.
- Partial payment updates status and balance.
- Full payment marks invoice paid and records paid time.
- Quote-to-invoice payload should preserve client, line items, tax rate, and totals.

Critical tests:

- Create valid invoice.
- Reject missing client, unsupported status, bad due date, bad tax, bad line items.
- Edit unpaid/partial invoice.
- Block edit of paid invoice.
- Record partial payment.
- Record full payment.
- Reject zero/negative payment.
- Overdue calculation based on current date.

## 11. Customer Portal

Primary files:

- `src\Portal\Controller\CustomerPortalController.php`
- `src\Portal\Service\CustomerPortalService.php`
- `templates/portal/view.php`

Rules:

- Customer portal is token based and unauthenticated.
- Quote, invoice, and job portal payloads are signed.
- Invalid or expired token is blocked.
- Quote approval and decline are POST actions under `/api/portal/quote`.
- Payment link is currently placeholder/foundation.

Critical tests:

- Valid signed quote renders.
- Approve quote.
- Decline quote.
- Invalid token denied.
- Expired token denied.
- Tampered payload denied.
- Portal must not expose unrelated tenant/customer data.

## 12. Import Data

Primary files:

- `src\Demo\Controller\OperationsController.php`
- `src\Importing\Service\ImportSchemaRegistry.php`
- `src\Importing\Service\ImportValidationService.php`
- `src\Importing\Service\ImportPipelineService.php`
- `templates/data/import.php`

Rules:

- Import requires `import_csv`.
- User selects import type before validation.
- Supported types: customers, jobs, quotes, invoices, team.
- Mandatory fields:
  - Customers: `name`
  - Jobs: `title`, `client_name`, `status`
  - Quotes: `quote_number`, `client_name`, `status`, `subtotal`, `total`
  - Invoices: `invoice_number`, `client_name`, `status`, `total`, `due_date`
  - Team: `name`, `email`, `role`
- Header aliases are normalised.
- Validation preview must occur before commit.
- Invalid preview cannot be committed.
- Last import can be undone.
- Import actions are audit logged when audit service is available.

Critical tests:

- Each import type mandatory fields.
- Header aliases.
- Invalid rows/headers.
- Commit after valid preview.
- Commit blocked before preview.
- Undo.
- CSV formula injection handling for later export.
- Tenant isolation and created id tracking.

## 13. Export Data

Primary files:

- `src\Demo\Controller\OperationsController.php`
- `templates/data/export.php`

Rules:

- Export requires `export_csv`.
- Live exports require active Pro/trial subscription and manager/owner unless demo mode is enabled.
- Supported datasets: all, clients, jobs, quotes, invoices.
- CSV cells beginning with `=`, `+`, `-`, `@`, tab, CR, or LF must be prefixed with `'`.
- Export is audited when audit service is available.

Critical tests:

- Basic live export blocked.
- Pro trial export allowed.
- Dataset filter.
- CSV headers and rows.
- Formula injection.
- Tenant scope.

## 14. AI Assistant and LLM Settings

Primary files:

- `src\Llm\Service\AiAssistantService.php`
- `src\Llm\Controller\LlmSettingsController.php`
- `src\Llm\Service\LlmConnectionService.php`
- `src\Llm\Service\LlmProviderRegistry.php`
- `templates/ai-assistant/index.php`
- `templates/llm/index.php`

Rules:

- `/ai-assistant` requires `use_ai_assistant`.
- `/ai-assistant/generate` is CSRF-protected and requires `use_ai_assistant`.
- Supported modes: `quote`, `schedule`, `general`.
- Job title max length: 160.
- Details max length: 1200.
- Current assistant is local deterministic only.
- No external LLM calls are made.
- No operational records are changed.
- Generated response includes safety note.
- API-key, token, password, secret, and long-card-number-like values are redacted from user details.
- LLM settings validate provider, display name, model, API key length, and HTTPS endpoint for custom providers.
- API keys are not stored in the current implementation.

Critical tests:

- Generate quote, schedule, and general responses.
- Invalid mode returns 422.
- Missing/invalid CSRF returns 403.
- Trainee denied.
- Secret redaction.
- Response rendered safely without `innerHTML` injection from user content.
- LLM provider validation, especially custom endpoint HTTPS.

## 15. Accounting Integrations

Primary files:

- `src\Accounting\Controller\AccountingSettingsController.php`
- `src\Accounting\Service\AccountingProviderRegistry.php`
- `src\Accounting\Service\AccountingConnectionService.php`
- `src\Accounting\Repository\AccountingConnectionRepository.php`
- `src\Accounting\Repository\DemoPlatformAccountingConnectionRepository.php`
- `templates/accounting/index.php`

Rules:

- Requested providers are represented:
  - Xero
  - Intuit QuickBooks Online
  - Sage Accounting
  - Zoho Books
  - MYOB
  - FreeAgent
  - Reckon
  - SMEPlus
  - FreshBooks
  - Wave Accounting
- Current connection flow is sandbox/foundation.
- Unsupported/unconfirmed provider is blocked.
- Platform accounting connection is available for platform admin.
- Sync modes are validated.

Critical tests:

- Each provider appears.
- Each sandbox provider validates.
- Unsupported provider denied.
- Sync mode validation.
- Platform accounting connect route is platform-admin only and CSRF protected.

## 16. Calendar Integrations

Primary files:

- `src\Calendar\Controller\CalendarSettingsController.php`
- `src\Calendar\Service\CalendarProviderRegistry.php`
- `src\Calendar\Service\CalendarSyncService.php`
- `templates/calendar/index.php`

Rules:

- Google Calendar and Outlook are represented.
- Current behavior is two-way sync strategy/foundation, not live OAuth.
- Sync strategy handles inbound provider changes and outbound FieldOps changes.
- Conflict is detected when both provider and FieldOps changed.

Critical tests:

- Provider registry.
- Google and Outlook settings visibility.
- Two-way sync strategy cases.
- Conflict queue behavior.
- Manage permission only for allowed roles.

## 17. SaaS Workspace, Subscription, Pricing

Primary files:

- `src\Saas\Controller\SaasController.php`
- `src\Saas\Controller\PricingAdminController.php`
- `src\Saas\Service\TradePlanCatalog.php`
- `src\Saas\Service\TenantSubscriptionService.php`
- `src\Saas\Service\PricingConfigurationService.php`
- `templates/saas/workspace.php`
- `templates/saas/subscription.php`
- `templates/saas/pricing.php`
- `templates/saas/pricing-admin.php`

Rules:

- Trade plan catalog includes Basic free and Pro GBP 30/month with 30-day free trial.
- Pricing configuration supports multi-currency global settings.
- Global discount can be active or expired.
- Subscription access state determines feature access.
- Basic retains core job access.
- Pro/trial unlocks Pro features such as accounting integrations.
- Expired trial falls back to Basic access.
- Seat limits apply to team growth.

Critical tests:

- Pricing display by currency.
- Discount active/expired behavior.
- Trial active/expired behavior.
- Feature gating.
- Seat limits.
- Global pricing admin RBAC and CSRF.

## 18. Platform Admin

Primary files:

- `src\Saas\Controller\PlatformAdminController.php`
- `src\Saas\Service\PlatformAdminService.php`
- `src\Saas\Service\PlatformBillingService.php`
- `src\Saas\Service\SystemHealthService.php`
- `src\Saas\Service\SecurityAdminService.php`
- `src\Saas\Service\MobileOfflineStatusService.php`
- `templates/saas/platform-admin.php`
- `templates/saas/tenant-index.php`
- `templates/saas/tenant-view.php`
- `templates/saas/system-health.php`
- `templates/saas/security-admin.php`
- `templates/saas/mobile-offline.php`

Rules:

- Platform admin root remains `/platform-admin`; no `/admin` duplicate.
- Tenant routes show tenant detail tabs: overview, users, billing, plan/trial, usage, imports/exports, audit log, support notes.
- Sensitive tenant actions require explicit confirmation and audit logging.
- Tenant actions include suspend, resume, start/extend/end trial, change plan, add grace period, mark payment failed, mark account active, export tenant data.
- Support login-as requires a reason and duration.
- Support sessions are time-limited and auditable.
- Platform billing shows package/cycle, contract value, billed so far, remaining amount, next invoice, and status.
- Manual billing override requires amount where applicable and a reason.
- Demo reset must be explicit and audited.
- System health/security/mobile-offline pages are admin visibility/foundation modules.

Critical tests:

- All platform admin routes denied to tenant roles.
- Platform admin denied tenant operational routes unless support impersonating.
- Tenant suspend/resume/action audit.
- Trial/plan/grace/payment actions.
- Billing override valid/invalid.
- Support login-as and return.
- Support access history.
- Demo reset not automatic.
- No `/admin` route introduced.

## 19. Audit Logging

Primary files:

- `src\Audit\Service\AuditLogService.php`
- `src\Audit\Repository\AuditLogRepository.php`
- `src\Audit\Repository\DatabaseAuditLogRepository.php`
- `src\Audit\Repository\DemoAuditLogRepository.php`

Rules:

- Audit logs are append-only in app logic.
- Events currently covered by tests include tenant suspend/resume, plan change, trial extension, support login, import run, export run, demo reset, role change, settings change.
- Database repository matches existing `audit_logs` table shape.

Critical tests:

- Each sensitive action writes an audit row.
- No application route supports editing/deleting audit rows.
- Audit rows include actor, tenant, event type, and metadata.
- Metadata does not store raw secrets.

## 20. Mobile, PWA, Offline

Primary files:

- `src\Mobile\Controller\OfflineTechnicianController.php`
- `src\Mobile\Service\OfflineTechnicianService.php`
- `public/assets/js/offline-technician.js`
- `public/service-worker.js`
- `public/manifest.json`
- `capacitor.config.json`
- `mobile/README.md`
- `android/README.md`
- `ios/README.md`

Rules:

- PWA manifest and service worker are present.
- Offline technician workspace uses tenant/user scoped browser storage key.
- Offline sync only accepts valid assigned technician updates.
- Unassigned job updates are rejected.
- Capacitor Android/iOS wrappers are configured/foundation-ready.
- App-store production readiness is not approved.

Critical tests:

- Manifest installability.
- Service worker offline fallback.
- Queue save offline.
- Sync now success/failure.
- Tenant/user isolation in localStorage key.
- Assigned vs unassigned job update validation.
- Mobile viewport no overflow.

