Release Candidate RC1 — Production Readiness
| Field | Value |
|---|---|
| Recommended tag | v1.2.0-rc.1 (never tagged — ship GA as v1.1.0) |
| Release date | 2026-07-14 |
| Status | Release Candidate — absorbed into v1.1.0 |
| Base | Platform foundation + CRM Sprint 2 |
| Scope | Hardening only — no new business modules |
Summary
RC1 closes Critical and High severity production blockers discovered during the production readiness audit across Backend, Frontend, and ops docs. The platform remains under the architecture freeze; this release is security, resilience, and operator readiness.
Release Notes
Security
- Suspended users: Sanctum tokens revoked on suspend;
not.suspendedmiddleware rejects remaining sessions - Workspace self-registration defaults to off
- Branding uploads reject SVG (stored XSS); privileged user fields stay non-fillable
- CORS origins pinned via
FRONTEND_URL/CORS_ALLOWED_ORIGINS - Impersonation targets workspace owner (
superadmin) only - Password-reset emails include
workspacequery param for tenant SPA routing - SPA: Safe post-login redirects; email-verify
redirectallowlisted to API origin - SPA: React Query cache cleared on login, impersonation, logout, and 401 handling
- Payment API / webhook logs redact raw gateway bodies
- Protected role assignment: cannot assign
superadminvia tenant user APIs
Billing & webhooks
- Webhook logs store safe summaries only (never full Stripe payloads)
- Unique
(payment_gateway_id, provider_event_id)prevents double processing - Cashier
/stripe/webhookand/webhooks/gateways/stripeshare the same idempotency store - Stripe driver requires signature unless
preVerified: true(Cashier path only)
Ops & observability
- Health
/upchecks DB; also Redis when cache/queue drivers use Redis - Queued notifications; scheduler uses
withoutOverlapping - Production runbook updated
Frontend UX / a11y
- Lead / Task detail sheets sync to
?lead=/?task=(Back closes the drawer) - Billing pages surface
ErrorStateon query failure - Skip-to-content link; Kanban keyboard sensor
- Remember-me defaults off
- Email verified gate treats missing
email_verified_atas unverified
Performance
- Kanban board APIs cap cards per column (
per_column, default 50, max 100) while returning accurate counts
Upgrade Notes
- Pull RC1; run
composer install --no-dev/npm ci && npm run buildas applicable. - Set production env (see Production Checklist). Especially:
APP_DEBUG=falseCACHE_STORE=redis(required for Stancl tenant cache tags)QUEUE_CONNECTION=redis(recommended)STRIPE_WEBHOOK_SECRETnon-empty when Stripe is live- Pin
FRONTEND_URL/CORS_ALLOWED_ORIGINS
- Run migrations:bashIncludes
php artisan migrate --forcewebhook_logsunique index (duplicates are pruned to the earliest row). - Warm caches:
config:cache,route:cache,event:cache,view:cache - Restart queue workers:
php artisan queue:restart - If using open registration, explicitly set
registration_enabledto true in Central system settings (seeded default is now false). - Point Stripe to one primary business webhook preferred:
/webhooks/gateways/stripe. Keep/stripe/webhookfor Cashier subscription mirroring if needed — both are idempotent for BillingEngine side effects.
Production Checklist
- [ ]
APP_ENV=production,APP_DEBUG=false,APP_KEYbacked up - [ ] TLS terminated;
SESSION_SECURE_COOKIE=true - [ ]
CACHE_STORE=redis+ Redis reachable - [ ] Emails queue worker running (
queue:work --queue=emails); scheduler every minute - [ ]
STRIPE_WEBHOOK_SECRETset; gateway sandbox/live mode correct - [ ] CORS /
FRONTEND_URLexact SPA origins - [ ]
registration_enabledintentional - [ ]
FILESYSTEM_DISK=s3+AWS_*configured;storage:migrate-to-s3if migrating local branding; bucket backups (object-storage.md) - [ ] Log rotation configured; Nightwatch/Telescope policy decided
- [ ] Database + Redis backups scheduled
- [ ]
GET /upreturns 200 - [ ] Smoke: central login, tenant login, lead create, task create, test webhook, forgot-password queued
Deployment Checklist
bash
php artisan down --retry=60 # optional
git checkout v1.2.0-rc.1 # or deploy artifact
composer install --no-dev --optimize-autoloader
php artisan migrate --force
php artisan config:cache
php artisan route:cache
php artisan event:cache
php artisan view:cache
php artisan queue:restart
php artisan upFrontend: build SPA and publish static assets behind HTTPS.
Rollback Checklist
- Redeploy previous release artifact / prior tag
- Rollback migrations only if safe for this release (
webhook_logsunique index is reversible; data loss risk is low) php artisan queue:restart- Verify
/up, login, and Stripe webhook reachability - If registration was relied upon while default was on, re-enable via Central settings after rollback if needed
Known Issues / Limitations
| Item | Severity | Notes |
|---|---|---|
| Assignee pickers load first 100 users | Medium | Searchable async select deferred; use list filters for large orgs |
| Bearer tokens in web storage | Medium | SPA/Sanctum Bearer design; XSS surface locked down; remember defaults off |
Spatie teams false | Low | Roles scoped by tenant_id column; avoid Role::findByName without tenant |
| Dual Stripe ingress | Info | Shared idempotency; prefer documenting one ops webhook URL |
Verification (RC1)
| Suite | Result |
|---|---|
| New/updated Pest (suspend, webhook idempotency, impersonation owner, related auth/settings) | Passed in hardening runs |
| Full Pest / Playwright | Re-run before GA tag |
Recommended GA tag: v1.1.0 (RC1 never received a git tag; GA uses clean SemVer).