Upgrade Guide
How to ship application releases to existing production installations without reseeding.
Standard upgrade
php artisan down --retry=60 # optional
git pull
composer install --no-dev --optimize-autoloader
php artisan migrate --force
php artisan optimize
php artisan queue:restart
php artisan reverb:restart # if Reverb is running
php artisan upThat is the complete path for catalog modules and tenant permission vocabulary changes that follow the platform pattern.
Documents 1.6.0 → 1.7.0 — nested folders + version history
- Deploy Backend and run
php artisan migrate --force(document_folders,document_versions,documents.folder_id, catalog bump — do notdb:seed) - Confirm catalog version: documents 1.7.0
- Deploy Frontend after production build; hard-refresh SPA
- Existing documents stay unfiled until assigned to a folder; prior replaces had no history
Go-live: Documents folders + versions production readiness.
Expenses 1.6.0 → 1.7.0 — itemized lines
- Deploy Backend and run
php artisan migrate --force(expense_linestable and catalog bump — do notdb:seed) - Confirm catalog version: expenses 1.7.0
- Deploy Frontend after production build; hard-refresh SPA. Ship the mobile build
- Existing expenses stay header-only until the next draft save
Go-live: Expense itemized lines production readiness.
Expenses 1.5.0 → 1.6.0 — undo payment
- Deploy Backend and run
php artisan migrate --force(catalog bump only — do notdb:seed) - Confirm catalog version: expenses 1.6.0
- Deploy Frontend after production build; hard-refresh SPA. Ship the mobile build
- Existing paid expenses stay paid until someone undoes the payment
Go-live: Expense unpay production readiness.
Assets 1.2.0 → 1.3.0 / Accounting 1.9.0 → 1.10.0 — depreciation journals
- Deploy Backend and run
php artisan migrate --force(asset depreciation columns,asset_depreciations,assets.depreciate, soft dependency, catalog bumps — do notdb:seed) - Confirm catalog versions: assets 1.3.0, accounting 1.10.0. Admin and manager have
assets.depreciate - Deploy Frontend after production build; hard-refresh SPA. Ship the mobile build
- Existing assets are not depreciated until someone posts a month
Go-live: Asset depreciation journals production readiness.
Invoice edit requests table already exists (Forge migrate 42S01)
If deploy fails on 2026_10_08_171215_create_customer_invoice_edit_requests_table with Table 'customer_invoice_edit_requests' already exists:
- Prefer pulling the Backend fix that makes that migration idempotent (
Schema::hasTable+ short indexcie_edit_req_tenant_invoice_status_idx), then re-runphp artisan migrate --force. - If you cannot deploy that fix first and the table is already correct, record the migration without re-running
up()(migrate-only — do notdb:seed/ drop the table unless empty and unused):
INSERT INTO migrations (migration, batch)
SELECT '2026_10_08_171215_create_customer_invoice_edit_requests_table',
IFNULL(MAX(batch), 0) + 1
FROM migrations;Then ensure the short composite index exists if missing:
CREATE INDEX cie_edit_req_tenant_invoice_status_idx
ON customer_invoice_edit_requests (tenant_id, customer_invoice_id, status);Finally: php artisan migrate --force and retry Forge deploy.
Guest share PDF-parity preview — invoices 1.12.1 / quotations 1.10.1
- Deploy Backend and run
php artisan migrate --force(catalog bumps only — do notdb:seed) - Confirm catalog:
invoices1.12.1,quotations1.10.1 - Deploy Frontend from
build-artifactsafter CI publishes — guest share pages show Branded logo chrome + full document preview - Smoke: open an unpaid invoice share link with Branded installed (tenant logo) and without (EloSync logo); confirm issuer/bill-to/lines/notes match PDF download
Multi-bank remittance + public share links — invoices 1.12.0 / quotations 1.10.0
- Deploy Backend and run
php artisan migrate --force(public view token columns + catalog bumps — do notdb:seed) - Confirm catalog:
invoices1.12.0,quotations1.10.0 - Deploy Frontend from
build-artifacts(notmain) after Frontend production build succeeds — Settings → Branding bank accounts; invoice/quotation Copy share link; guest/#/view/…pages. If Actions failed typecheck oninvoice_bank_accounts, merge the share-link SPA publish fix first so artifacts update. - Staging smoke: two banks / one disabled → send → share link → guest view + PDF → void/reject clears link
Go-live: Billing share + multi-bank production readiness.
Configurable digests — invoices 1.11.0 / departments 1.2.0 / attendance 1.8.0
- Deploy Backend and run
php artisan migrate --force(department_report_user+ catalog bumps — do notdb:seed) - Confirm catalog:
invoices1.11.0,departments1.2.0,attendance1.8.0 - Deploy Frontend — Settings → Notifications invoice digest; department Report recipients
- Staging smoke: enable invoice digest + recipients; assign department report recipients; confirm attendance digests stay silent until both Settings toggles and recipients are set
Go-live: Configurable digests production readiness.
WhatsApp Cloud 1.5.0 → 1.6.0 (+ Help Desk → 1.18.0) — auto-ticket + note sync
php artisan migrate --force(auto_create_help_desk_tickets, note/message FKs, catalog bumps — do notdb:seed)- Confirm catalog:
whatsapp-cloud1.6.0,help-desk1.18.0 - Deploy Frontend — WhatsApp Auto-create Help Desk tickets toggle
- Staging smoke: entitle both modules → enable auto-create → inbound creates ticket; public note syncs inside 24h; internal notes stay local
Go-live: WhatsApp Help Desk bridge 1.6.0 production readiness.
Tasks 1.10.0 → 1.10.1 / Help Desk 1.17.0 → 1.17.1 — human-readable status timing
php artisan migrate --force(do notdb:seed)- Confirm catalog:
tasks1.10.1,help-desk1.17.1 - Smoke: task/ticket timing shows values like
3h/1d 2h(notDD:HH:MM)
Help Desk 1.16.0 → 1.17.0 — status timing
php artisan migrate --force(do notdb:seed)- Confirm catalog:
help-desk1.17.0 - Smoke: ticket Open → In Progress → Resolved/Closed → Timeline shows Created → Resolved; reopen clears cycle
Go-live: Help Desk 1.17.0 production readiness.
Help Desk 1.15.0 → 1.16.0 (+ WhatsApp Cloud 1.4.0 → 1.5.0) — multi-channel intake
- Deploy Backend and run
php artisan migrate --force(whatsapp_conversations.help_desk_ticket_id+ catalog bumps — do notdb:seed) - Confirm catalog:
help-desk1.16.0,whatsapp-cloud1.5.0 - Deploy Frontend — WhatsApp Escalate + Help Desk source badges
- Staging smoke: entitle both modules → escalate conversation → ticket link + WhatsApp badge on Help Desk
Go-live: Help Desk 1.16.0 production readiness.
Customer Portal 1.2.0 → 1.3.0 (+ Help Desk 1.14.0 → 1.15.0)
- Deploy Backend and run
php artisan migrate --force(portal magic-link + 2FA columns; catalog bumps — do notdb:seed) - Confirm catalog:
customer-portal1.3.0,help-desk1.15.0 - Deploy Frontend (magic-link / Security 2FA / portal KB; Help Desk conversation polish; Settings Help Desk email toggles)
Go-live: Customer Portal 1.3.0 · Help Desk 1.15.0.
Help Desk 1.13.0 → 1.14.0 (+ Customer Portal 1.1.0 → 1.2.0)
- Deploy Backend and run
php artisan migrate --force(help_desk_notes.is_internal+ backfill + catalog bumps — do notdb:seed) - Confirm catalog:
help-desk1.14.0,customer-portal1.2.0 - Deploy Frontend (Conversation vs Internal notes; portal TipTap replies + attachments) and Mobile (visibility toggle)
Go-live: Help Desk public replies 1.14.0 production readiness.
Customer Portal 1.0.0 (+ Help Desk 1.12.0 → 1.13.0)
- Deploy Backend and run
php artisan migrate --force(registerscustomer-portal, permissions,portal_users/ reset tokens, contacts hard dependency, Help Deskportal_user_id+ catalog 1.13.0 — do notdb:seed) - Confirm catalog:
customer-portal1.0.0,help-desk1.13.0 - Deploy the SPA — Operations → Customer Portal +
/#/portal/*guest shell - Staging smoke: install Contacts → Customer Portal → invite Contact → accept invite → login → invoice/ticket smoke when those modules are entitled
Go-live: Customer Portal 1.0.0 production readiness.
Payments 1.6.0 → 1.7.0 — live Stripe refunds
- Deploy Backend and run
php artisan migrate --force(customer_payments.gateway_mode,customer_payment_refunds.stripe_refund_id, catalog 1.7.0 — do notdb:seed) - Confirm catalog: payments 1.7.0
- Deploy the SPA — posted Stripe payments show Refund via Stripe; other methods keep Record refund
- Stripe webhook for the active mode must include
refund.created(Checkout events stay) - Staging smoke: portal Pay now → posted gateway payment → partial Refund via Stripe in sandbox → Stripe refund id on the payment → invoice balance restored
Go-live: Payments Stripe refunds 1.7.0 production readiness.
Payments 1.5.0 → 1.6.0 / Customer Portal 1.3.0 → 1.4.0 — tenant Stripe portal Checkout
- Deploy Backend and run
php artisan migrate --force(tenant_stripe_connections, gateway txn unique index,payments.manage_integrations, catalog bumps — do notdb:seed) - Confirm catalog: payments 1.6.0, customer-portal 1.4.0; admin/manager have
payments.manage_integrations - Deploy the SPA — Payments → Stripe; portal invoice Pay now
- Staging smoke: save sandbox keys → enable → test → configure Stripe webhook → portal Pay now → invoice paid
Go-live: Tenant Stripe portal checkout production readiness.
Calendar 1.9.0 → 1.10.0 — named-calendar provider sync/watches
- Deploy Backend and run
php artisan migrate --force(calendar_provider_links,calendar_event_provider_mappings, bump to 1.10.0 — do notdb:seed) - Confirm catalog version: calendar 1.10.0
- Deploy the SPA — Manage calendars provider badges; Sync panel named-calendar copy
- Existing Google Calendar connections: Disconnect → Connect (full
calendarscope required to create secondary calendars) - Staging smoke: connect provider → create named calendar → synced badge → post event on named calendar → Sync now
Go-live: Calendar named-provider sync 1.10.0 production readiness.
Calendar 1.8.0 → 1.9.0 — named team/department calendars
- Deploy Backend and run
php artisan migrate --force(calendarstable,calendar_events.calendar_id,calendar.manage_calendars, bump to 1.9.0 — do notdb:seed) - Confirm catalog version: calendar 1.9.0; admin/manager have
calendar.manage_calendars - Deploy the SPA — Manage calendars, filter chips, event Calendar picker
- Staging smoke: create named calendar → post event → filter; with Departments entitled, department member sees team events
Go-live: Calendar named calendars 1.9.0 production readiness.
Calendar 1.7.0 → 1.8.0 — webhook-driven inbound sync
- Deploy Backend and run
php artisan migrate --force(2026_10_08_160000_bump_calendar_module_to_1_8_0— catalog only; do notdb:seed) - Confirm catalog version: calendar 1.8.0
- Confirm public
POST /webhooks/calendar-sync/{provider}is reachable; scheduler runscalendar:renew-provider-watchesdaily; Horizoncalendar-sync; hourly pull remains - Deploy the SPA — Sync panel “near real-time” copy / badge
- Staging smoke: Connect → Sync now → provider-side create appears as External without waiting for the hourly job
Go-live: Calendar webhook inbound 1.8.0 production readiness.
Calendar 1.6.0 → 1.7.0 — Project/Contact/Company overlay push
- Deploy Backend and run
php artisan migrate --force(catalog bump to 1.7.0 — do notdb:seed) - Confirm catalog version: calendar 1.7.0
- Deploy the SPA — Sync panel copy lists Project/Contact/Company overlays
- Confirm Horizon
calendar-sync - Staging smoke (OAuth connected): Project dates / Contact or Company follow-up → provider calendar
Go-live: Calendar overlay push 1.7.0 production readiness.
Calendar 1.5.0 → 1.6.0 — two-way inbound sync
- Deploy Backend and run
php artisan migrate --force(2026_10_05_170000_bump_calendar_module_version_to_1_6_0— catalog only; do notdb:seed) - Confirm catalog version: calendar 1.6.0
- Deploy the SPA — Calendar → Sync gains Sync now + two-way copy
- Confirm scheduler:
calendar:pull-provider-eventshourly; Horizoncalendar-sync - Staging smoke: Connect provider → Sync now → External events appear as view-only
Go-live: Calendar two-way inbound 1.6.0 production readiness.
AI Inventory triage tools 1.21.0 → 1.22.0
After migrate (2026_10_17_155210_bump_ai_module_to_1_22_0):
- Confirm catalog
ai.versionis 1.22.0 (migrate-only; do notdb:seed). - No SPA deploy required for confirm UI (tool-agnostic); Frontend e2e covers propose→confirm product note.
- Smoke: entitle
ai+products+warehouses+inventory→ Ask EloSyncget_product/get_low_stock/get_inventory_stats→ propose product note → Confirm.
Go-live: AI Inventory triage production readiness · ops AI deployment.
Inventory 1.4.0 → 1.5.0 — moving-average valuation
- Deploy Backend and run
php artisan migrate --force(unit_costonstock_movements, catalog bump — do notdb:seed) - Confirm catalog version: inventory 1.5.0
- Deploy Frontend after production build; hard-refresh SPA
- Smoke: stock in with unit cost → confirm Avg cost / Value columns and Inventory value KPI; receive a PO and confirm product cost moves toward the line price
Go-live: Inventory moving-average 1.5.0 production readiness.
Inventory 1.3.0 → 1.4.0 / Purchase Orders → 1.7.0 — serial/lot PO receive + transfers
- Deploy Backend and run
php artisan migrate --force(catalog bumps only — do notdb:seed) - Confirm catalog versions: inventory 1.4.0, purchase-orders 1.7.0
- Deploy Frontend after production build; hard-refresh SPA
- Smoke: receive a serial/lot-tracked PO with serials/lot → complete a warehouse transfer with serials/lot
Go-live: Inventory serial/lot receive + transfer 1.4.0 production readiness.
Products → 1.5.0 / Inventory → 1.3.0 — serial + lot tracking MVP
- Deploy Backend and run
php artisan migrate --force(track_serials,track_lots,stock_serials,stock_lots, catalog bumps — do notdb:seed) - Confirm catalog versions: products 1.5.0, inventory 1.3.0
- Deploy Frontend after production build; hard-refresh SPA
- Smoke: enable Track serials or Track lots (zero on-hand) → stock in with serials/lot → confirm set-quantity adjust rejects that SKU
Go-live: Inventory serial/lot 1.3.0 production readiness.
Accounting 1.8.0 → 1.9.0 / Purchase Orders 1.5.0 → 1.6.0 — Pay vendor AP settle
- Deploy Backend and run
php artisan migrate --force(receiptpaid_from_account_id/payment_journal_entry_id,purchase-orders.paygrant, catalog bumps; do notdb:seed) - Confirm catalog versions: accounting 1.9.0, purchase-orders 1.6.0
- Deploy Frontend after production build; hard-refresh SPA
- Smoke: receive a tracked PO → Pay vendor from cash/bank → accounts payable open is zero
Go-live: Accounting vendor AP settle 1.9.0 production readiness.
Accounting 1.7.2 → 1.8.0 — purchase receipts and inventory journals
- Deploy Backend and run
php artisan migrate --force(2026_10_16_224416_add_journal_entry_id_to_purchase_order_receipts_and_stock_movementsand2026_10_16_224417_bump_accounting_module_version_to_1_8_0; do notdb:seed) - Confirm catalog version: accounting 1.8.0
- No SPA deploy is required for this bump
- Staging smoke: with Accounting installed, receive a tracked purchase order and confirm one posted journal (Dr
1200/ Cr2000). Issue stock and confirm Dr5000/ Cr1200. Complete a warehouse transfer and confirm it adds no journal
Go-live: Accounting AP/COGS 1.8.0 production readiness.
Automation 1.8.0 → 1.9.0 — if/else branches
- Deploy Backend and run
php artisan migrate --force(2026_10_16_215505_create_automation_branches_and_link_stepsand2026_10_16_215506_bump_automation_module_to_1_9_0; do notdb:seed) - Confirm catalog version: automation 1.9.0
- Deploy the SPA — workflow builder gains Branches
- Restart Horizon so workers load the branch planner (
automationsqueue) - Staging smoke: save a workflow with an if branch and an otherwise branch; manual run with
priority=hightakes the if branch
Go-live: Automation branching 1.9.0 production readiness.
Automation 1.7.0 → 1.8.0 — generate_order (Purchase Order)
- Deploy Backend and run
php artisan migrate --force(2026_10_08_181000_bump_automation_module_to_1_8_0— catalog only; do notdb:seed) - Confirm catalog version: automation 1.8.0
- Deploy the SPA — new Generate Purchase Order action (
vendor_id, email/WhatsApp auto-send) - Ensure Purchase Orders (+ Vendors) entitled for workspaces that use the action; Horizon
automations/emails/whatsapp-outbound - Staging smoke: Manual or Vendor trigger → draft PO; with
auto_send→ Sent + vendor email
Go-live: Automation generate_order 1.8.0 production readiness.
Automation 1.6.0 → 1.7.0 — WhatsApp document auto-send
- Deploy Backend and run
php artisan migrate --force(2026_10_08_180000_bump_automation_module_to_1_7_0— catalog only; do notdb:seed) - Confirm catalog version: automation 1.7.0
- Deploy the SPA — Generate Quotation / Invoice gain Also send PDF on WhatsApp (gated by WhatsApp Cloud)
- Restart workers including
whatsapp-outbound; WhatsApp Cloud platform connection must be ready - Staging smoke:
auto_send_whatsapp+ open 24h conversation matched by bill-to phone → PDF document queued; closed window → failed run
Go-live: Automation WhatsApp document auto-send 1.7.0 production readiness.
Automation 1.5.0 → 1.6.0 — document auto-send
- Deploy Backend and run
php artisan migrate --force(2026_10_05_160000_bump_automation_module_version_to_1_6_0— catalog only; do notdb:seed) - Confirm catalog version: automation 1.6.0
- Deploy the SPA — Generate Quotation / Invoice actions gain Auto-send checkbox
- Restart queue workers so billed document emails process (
emails/ mail queue) - Staging smoke: workflow with
auto_send+ company email → Sent/Unpaid + mail; without email → failed run
Go-live: Automation document auto-send 1.6.0 production readiness.
Calendar 1.4.0 → 1.5.0 — Meeting/Task/Lead overlay provider push
- Deploy Backend and run
php artisan migrate --force(2026_10_05_153000_bump_calendar_module_version_to_1_5_0— catalog only; do notdb:seed) - Confirm catalog version: calendar 1.5.0
- Deploy the SPA — Calendar → Sync copy mentions Meeting/Task/Lead overlays
- Confirm Horizon workers process the
calendar-syncqueue (php artisan queue:restart) - Staging smoke (with OAuth connected): create Task with due / Lead follow-up / Meeting → provider calendar updates; clear due or cancel meeting → provider event cancelled
Go-live: Calendar overlay provider push 1.5.0 production readiness.
Leads 1.8.0 → 1.9.0 — inactivity manager digest
- Deploy Backend and run
php artisan migrate --force(2026_10_04_193718_bump_leads_module_to_1_9_0— catalog only; do notdb:seed) - Confirm catalog version: leads 1.9.0
- Deploy the SPA — Settings → Leads inactivity controls
- Restart queue workers (
php artisan queue:restart) soleads:notify-inactivemail jobs pick up the digest notification - Confirm the scheduler already runs
leads:notify-inactivedaily (routes/console.php)
Projects 1.7.0 → 1.8.0 — real-time board sync
- Deploy Backend and run
php artisan migrate --force(2026_10_05_031200_bump_projects_module_to_1_8_0— catalog only; do notdb:seed) - Confirm catalog version: projects 1.8.0
- Deploy the SPA after migrate — Projects Kanban board realtime (
useProjectsBoardRealtime; Gantt/Heatmap stay poll-on-navigate) - Confirm Reverb is running (
php artisan reverb:restartif already up) - Staging smoke: two browser sessions on the Projects Board — create, drag status, assign, delete
Go-live: Projects real-time board sync 1.8.0 production readiness.
Help Desk 1.11.0 → 1.12.0 — real-time board sync
- Deploy Backend and run
php artisan migrate --force(2026_10_05_023800_bump_help_desk_module_to_1_12_0— catalog only; do notdb:seed) - Confirm catalog version: help-desk 1.12.0
- Deploy the SPA after migrate — Help Desk Kanban board realtime (
useHelpDeskBoardRealtime) - Confirm Reverb is running (
php artisan reverb:restartif already up) - Staging smoke: two browser sessions on the Help Desk board — create, drag status, assign, delete; the other session’s board + KPIs update without a manual refresh
Go-live: Help Desk real-time board sync 1.12.0 production readiness.
Tasks 1.7.0 → 1.8.0 — real-time board sync
- Deploy Backend and run
php artisan migrate --force(2026_10_04_193500_bump_tasks_module_to_1_8_0— catalog only; do notdb:seed) - Confirm catalog version: tasks 1.8.0
- Deploy the SPA after migrate — Tasks Kanban board realtime (
useTasksBoardRealtime) - Confirm Reverb is running (
php artisan reverb:restartif already up) - Staging smoke: two browser sessions on the Tasks board — create, drag status, assign, delete; the other session’s board + KPIs update without a manual refresh
Go-live: Tasks real-time board sync 1.8.0 production readiness.
Document-field TipTap — announcements 1.2.0 / help-desk 1.11.0 / tasks 1.7.0 / projects 1.7.0 / activities 1.2.0
- Deploy Backend and run
php artisan migrate --force(2026_10_03_182400_bump_document_rich_text_module_versions— catalog only; do notdb:seed) - Confirm catalog versions: announcements 1.2.0, help-desk 1.11.0, tasks 1.7.0, projects 1.7.0, activities 1.2.0
- Deploy the SPA after migrate — TipTap on those document fields; sanitized HTML on view/inbox
- Deploy Mobile (plain-text strip on those views) and Docs
- Staging smoke: published announcement with list/link/color → inbox + record HTML; dashboard snippet without tags; existing plain-text bodies still open
Go-live: Document-field TipTap production readiness.
Workspace record cohesion — contacts 1.6.0 / companies 1.3.0 / documents 1.6.0 / email 1.4.0
- Deploy Backend and run
php artisan migrate --force(2026_09_29_211500_bump_contacts_companies_documents_email_for_workspace_cohesion— catalog only; do notdb:seed) - Confirm catalog versions: contacts 1.6.0, companies 1.3.0, documents 1.6.0, email 1.4.0
- Deploy the SPA after migrate — Contact/Company related hubs, Email CRM links UI, party list chips, Documents
?contact=/?company= - Staging smoke: contact with linked opportunity/ticket/project/document → related sections + View all chips; Email link/unlink Contact;
/documents?contact=filtered list
Go-live: Workspace record cohesion production readiness.
Projects 1.5.0 → 1.6.0 — workload heatmap
- Deploy Backend and run
php artisan migrate --force(catalog bump only — do notdb:seed) - Deploy the SPA after migrate — Projects Heatmap view mode
- Staging smoke: open project with assignee → Heatmap row → week cells reflect schedule overlap; with Tasks entitled, due-this-week project tasks add to cell load; pressure band shows
Go-live: Projects Heatmap 1.6.0 production readiness.
Projects 1.4.0 → 1.5.0 — portfolio Gantt
After migrate (2026_09_28_220000_bump_projects_module_version_to_1_5_0):
- Confirm catalog
projectsversion is1.5.0(migrate-only; do notdb:seed) - Deploy the SPA after migrate — Projects Gantt view mode
- Staging smoke: dated project → Gantt bar → expand milestones/tasks → drag dates (update permission); without Tasks entitled, task markers omitted
Go-live: Projects Gantt 1.5.0 production readiness.
Leads 1.5.0 → 1.6.0 — created_by / updated_by
After migrate (2026_09_26_112037_add_created_by_and_updated_by_to_leads_table, 2026_09_26_112040_bump_leads_module_to_1_6_0, 2026_09_26_133208_remediates_leads_created_by_updated_by_backfill):
- Confirm catalog
leadsversion is1.6.0(migrate-only; do notdb:seed) - Confirm tenant
leadshascreated_by/updated_by(nullable FKs); backfill is batched (chunk 500) - Deploy the SPA after migrate — Created by / Updated by columns and filters
- Staging smoke: create → filter by creator → edit as second user → Updated by changes; add a note → Updated by changes; System filter for null actors
Go-live: Leads 1.6.0 created/updated by production readiness.
Live Chat 1.5.2 → 1.6.0 — department-routed notifications
- Deploy Backend and run
php artisan migrate --force(2026_10_03_223500_add_live_chat_idle_routing_and_bump_to_1_6_0— do notdb:seed) - Confirm catalog
live-chatversion is1.6.0 - Confirm
emailsqueue workers (or sync) process Live Chat notifications and that the scheduler runslive-chat:scan-idleevery minute - Deploy the SPA after migrate — Settings → Live Chat idle minutes; notification types
live-chat.assigned/live-chat.idle - Purge CDN for
public/widgets/live-chat.js(snippet?v=1.6.0) - Staging smoke: department agents get first-chat bell + FCM; Staff outside the department do not; first agent reply claims the chat; idle minutes later alerts other department agents; visitor widget shows the answering agent’s Name
Live Chat 1.5.1 → 1.5.2 — inbound notification broadcast
After migrate (2026_09_25_210000_bump_live_chat_module_version_to_1_5_2):
- Confirm catalog
live-chatversion is1.5.2 - Confirm
emailsqueue workers (or sync) processLiveChatInboundMessageNotification - Staging smoke: visitor send → agent open tab receives bell /
NotificationCreatedwhile Echo is connected
Live Chat 1.5.0 → 1.5.1 — production-readiness remediations
After migrate (2026_09_25_200000_bump_live_chat_module_version_to_1_5_1):
- Confirm catalog
live-chatversion is1.5.1 - Confirm API serves updated
public/widgets/live-chat.js; Settings embed snippet includes?v=1.5.1(purge CDN for unversioned URLs) - Staging smoke: visitor send + open/close without HTTP 500 when automation/Reverb misbehaves; Retry does not duplicate a already-persisted visitor message
Go-live: Live Chat 1.5.0 / 1.5.1 production readiness.
Live Chat 1.4.2 → 1.5.0 — send soft-fail + typing
After migrate (2026_09_25_142200_bump_live_chat_module_version_to_1_5_0):
- Confirm catalog
live-chatversion is at least1.5.0(prefer 1.5.1 if that migration is present) - Confirm API serves the updated static
public/widgets/live-chat.js(purge CDN if used) - Deploy the SPA after Backend — desk typing API +
/canned filter php artisan reverb:restartwhen Reverb is used (typing/live desk); send works even if Reverb is down- Staging smoke: third-party Origin visitor send + agent reply without HTTP 500
Go-live: Live Chat 1.5.0 / 1.5.1 production readiness. Baseline CORS/session audit: Live Chat production readiness.
User security settings (2FA, passkeys, sessions)
Deploy Backend + Frontend + Docs together. Run migrations before serving the SPA build that includes Profile → Security and the login TOTP step.
| Migration | Purpose |
|---|---|
2026_09_01_230027_add_session_metadata_to_personal_access_tokens_table | Session list metadata on Sanctum tokens |
2026_09_01_231207_create_passkeys_table | WebAuthn passkeys |
2026_09_01_231209_add_two_factor_columns_to_users_table | TOTP columns (tenant users) |
2026_09_01_231400_add_two_factor_columns_to_central_users_table | TOTP columns (central users) |
Set PASSKEYS_RELYING_PARTY_ID and PASSKEYS_ALLOWED_ORIGINS before enabling passkeys in production. See User security settings production readiness.
What migrate does for modules & RBAC
| Change type | Mechanism | Safe for existing data? |
|---|---|---|
| New default-included module | Data migration + DefaultModuleRegistrar | Yes — insert-only catalog; install only if workspace never had a subscription row |
| New permissions | Data migration + TenantPermissionSynchronizer | Yes — additive grants only; never resets customized roles |
| Schema | Normal Laravel migrations | Follow usual migration discipline |
Do not run in production upgrades
php artisan db:seedCatalogSeeder/ Central catalog seeders to “pick up” new modules- Role/permission seeders to “sync” RBAC
- Manual SQL that reactivates cancelled module subscriptions
- Any process that expects login to repair missing permissions
Tenant API & Webhooks (Settings → Developers)
Migrate-first platform capability (not a Marketplace module).
- Deploy Backend + Frontend + Docs together.
- Run
php artisan migrate --force— addspersonal_access_tokens.token_type,tenant_webhook_endpoints,tenant_webhook_deliveries, and grantssettings.manage_developersto owner/admin defaults. - Ensure a queue worker processes the
webhooksqueue (DeliverTenantWebhookJob). Includewebhooksin the Forge worker list (see Laravel Forge). - Scheduler runs
webhooks:prune-deliveries --days=90weekly (delivery payload retention). - Smoke: Settings → Developers → create API token → Bearer call → create webhook → Send test.
See Tenant API & Webhooks production readiness.
Short Links 1.1.0 → 1.2.0
Deploy Backend + Frontend + Docs together.
php artisan migrate --force— widensshort_links.codeto 64 chars; bumps catalogshort-linksto 1.2.0 (2026_08_23_231224_widen_short_link_codes_and_bump_version).- Set production env:
SHORT_LINK_BASE_URL(e.g.https://go.elosync.com),SHORT_LINK_MARKETING_URL,SHORT_LINK_BETA_URL. - Point short-domain DNS at the same Laravel app that serves
GET /r/{identifier}. - Confirm queue workers process
RecordShortLinkClickJob(default queue). - Deploy SPA after migrate — vanity slug create field and copy icons require the new frontend build.
- Smoke: create vanity slug → public redirect; pause/delete → branded 404;
npm run test:e2e:short-links.
Go-live: Short Links production readiness · ops Short Links deployment.
Platform polish lanes A, B, C
Deploy Backend + Frontend + Docs together. Frontend PR #143 is already on main; Backend PR #148 and Docs PR #170 must merge before production.
php artisan migrate --force— attachment tables,document_links, catalog version bumps (2026_08_23_*).- Deploy Backend before or with the SPA (receipt upload, document links, credit note / PO PDF+email APIs).
- Confirm
emailsqueue workers and Storage upload disk (Storage production readiness). - Smoke: documents, expenses, help-desk, tenant-dashboard, AI module Playwright scripts (
--workers=1).
Go-live audit: Platform polish A/B/C production readiness — No-Go until Backend/Docs PRs merge.
AI Assistant platform 1.0.0 → 1.0.1
After migrate (2026_08_21_010000–010300):
- Confirm catalog rows
ai(billable 1.0.1),ai-credits-1k,ai-credits-5k,ai-credits-20kare published. - Confirm permissions
ai.use,ai.manage,ai.confirmexist and default admin/manager maps include them. - Confirm scheduler runs
ai:rollover-monthly-credits(daily, overlapping locked, one server). - Set Central Settings → AI (
ai_enabled, provider, encryptedai_api_key, models, monthly included credits). - Deploy the SPA after migrate — Ask EloSync / Settings AI (
ai.manage) / Lead Copilot require the module entitlement. - Smoke: entitle
ai→ wallet grant → Ask EloSync → Lead Copilot; platform mode returns 402 when credits are exhausted or below the pre-provider ceiling.
1.0.1 hardens credit integrity (wallet lockForUpdate, pre-provider credit ceiling, request-path ensurePeriod), enforces ai.manage on Settings AI, and adds throttle:ai on message/copilot routes.
Go-live: AI production readiness · ops notes AI deployment.
AI workspace search 1.2.0 → 1.3.0
After migrate (2026_08_31_200000_bump_ai_module_version_to_1_3_0):
- Confirm catalog
ai.versionis 1.3.0 (migrate-only; do notdb:seed). - Deploy SPA + Mobile after Backend — Search workspace starter + Wave A+B+C citations.
- Smoke: Ask EloSync → Search workspace starter; confirm hits respect module entitlement and
*.view; citations stay same-app.
Go-live: AI workspace search production readiness · ops AI deployment.
AI Help Desk triage tools 1.3.0 → 1.4.0
After migrate (2026_09_15_040000_bump_ai_module_version_to_1_4_0):
- Confirm catalog
ai.versionis 1.4.0 (migrate-only; do notdb:seed). - No SPA/Mobile deploy required for this bump (confirm UI is tool-agnostic).
- Smoke: entitle
ai+help-desk→ Ask EloSync open tickets → propose status/assign/note → Confirm; deny resolve withouthelp-desk.close.
Go-live: AI Help Desk triage production readiness · ops AI deployment.
AI Task triage tools 1.4.0 → 1.5.0
After migrate (2026_09_15_050000_bump_ai_module_version_to_1_5_0):
- Confirm catalog
ai.versionis 1.5.0 (migrate-only; do notdb:seed). - No SPA/Mobile deploy required for this bump (confirm UI is tool-agnostic).
- Smoke: entitle
ai(Tasks is default-included) → Ask EloSync overdue/due-today tasks → propose status/assign/note → Confirm; deny complete withouttasks.complete.
Go-live: AI Task triage production readiness · ops AI deployment.
AI Opportunity triage tools 1.5.0 → 1.6.0
After migrate (2026_09_15_060000_bump_ai_module_version_to_1_6_0):
- Confirm catalog
ai.versionis 1.6.0 (migrate-only; do notdb:seed). - No SPA/Mobile deploy required for this bump (confirm UI is tool-agnostic).
- Smoke: entitle
ai+opportunities→ Ask EloSync list stages / fetch opportunity → propose stage/assign/note → Confirm; deny stage withoutopportunities.update.
Go-live: AI Opportunity triage production readiness · ops AI deployment.
AI Invoice triage tools 1.6.0 → 1.7.0
After migrate (2026_09_15_070000_bump_ai_module_version_to_1_7_0):
- Confirm catalog
ai.versionis 1.7.0 (migrate-only; do notdb:seed). - No SPA/Mobile deploy required for this bump (confirm UI is tool-agnostic).
- Smoke: entitle
ai+invoices→ Ask EloSync fetch invoice / overdue → propose status/assign/note → Confirm; Draft→Unpaid needsinvoices.send; cancel needsinvoices.void.
Go-live: AI Invoice triage production readiness · ops AI deployment.
AI Expense triage tools 1.7.0 → 1.8.0
After migrate (2026_09_15_080000_bump_ai_module_version_to_1_8_0):
- Confirm catalog
ai.versionis 1.8.0 (migrate-only; do notdb:seed). - No SPA/Mobile deploy required for this bump (confirm UI is tool-agnostic).
- Smoke: entitle
ai+expenses→ Ask EloSync fetch expense / pending approval → propose status/assign/note → Confirm; approve needsexpenses.approve; reject needsexpenses.reject; paid via status needsexpenses.pay(andpaid_from_account_idon the expense when Accounting is entitled).
Go-live: AI Expense triage production readiness · ops AI deployment.
AI Project triage tools 1.8.0 → 1.9.0
After migrate (2026_09_15_090000_bump_ai_module_version_to_1_9_0):
- Confirm catalog
ai.versionis 1.9.0 (migrate-only; do notdb:seed). - No SPA/Mobile deploy required for this bump (confirm UI is tool-agnostic).
- Smoke: entitle
ai+projects→ Ask EloSync fetch project → propose status/assign/note → Confirm; status/note needprojects.update; assign needsprojects.assign.
Go-live: AI Project triage production readiness · ops AI deployment.
AI Purchase Order triage tools 1.9.0 → 1.10.0
After migrate (2026_09_15_100000_bump_ai_module_version_to_1_10_0):
- Confirm catalog
ai.versionis 1.10.0 (migrate-only; do notdb:seed). - No SPA/Mobile deploy required for this bump (confirm UI is tool-agnostic).
- Smoke: entitle
ai+purchase-orders→ Ask EloSync fetch PO → propose status/assign/note → Confirm; Draft→Sent needspurchase-orders.send; receive needspurchase-orders.receive; cancel needspurchase-orders.cancel.
Go-live: AI Purchase Order triage production readiness · ops AI deployment.
AI Payment triage tools 1.10.0 → 1.11.0
After migrate (2026_09_15_110000_bump_ai_module_version_to_1_11_0):
- Confirm catalog
ai.versionis 1.11.0 (migrate-only; do notdb:seed). - No SPA/Mobile deploy required for this bump (confirm UI is tool-agnostic).
- Smoke: entitle
ai+payments→ Ask EloSync fetch payment → propose post/void/assign/note → Confirm; Posted confirm callspost()(payments.post); Void confirm callsvoid()(payments.void); Draft target rejected.
Go-live: AI Payment triage production readiness · ops AI deployment.
AI Lead assign + note tools 1.11.0 → 1.12.0
After migrate (2026_09_15_120000_bump_ai_module_version_to_1_12_0):
- Confirm catalog
ai.versionis 1.12.0 (migrate-only; do notdb:seed). - No SPA/Mobile deploy required for this bump (confirm UI is tool-agnostic).
- Smoke: entitle
ai+leads→ Ask EloSync fetch lead → propose assign/note → Confirm; assign needsleads.assign; note needsleads.update.
Go-live: AI Lead assign + note production readiness · ops AI deployment.
AI Estimate triage tools 1.12.0 → 1.13.0
After migrate (2026_09_16_010000_bump_ai_module_version_to_1_13_0):
- Confirm catalog
ai.versionis 1.13.0 (migrate-only; do notdb:seed). - No SPA/Mobile deploy required for this bump (confirm UI is tool-agnostic).
- Smoke: entitle
ai+estimates→ Ask EloSync fetch estimate → propose status/assign/note → Confirm; Sent needsestimates.send; Accepted needsestimates.accept.
Go-live: AI Estimate triage production readiness · ops AI deployment.
AI Quotation triage tools 1.13.0 → 1.14.0
After migrate (2026_09_16_020000_bump_ai_module_version_to_1_14_0):
- Confirm catalog
ai.versionis 1.14.0 (migrate-only; do notdb:seed). - No SPA/Mobile deploy required for this bump (confirm UI is tool-agnostic).
- Smoke: entitle
ai+quotations→ Ask EloSync fetch quotation → propose status/assign/note → Confirm; Sent needsquotations.send; Accepted needsquotations.accept.
Go-live: AI Quotation triage production readiness · ops AI deployment.
AI Credit Note triage tools 1.14.0 → 1.15.0
After migrate (2026_09_16_030000_bump_ai_module_version_to_1_15_0):
- Confirm catalog
ai.versionis 1.15.0 (migrate-only; do notdb:seed). - No SPA/Mobile deploy required for this bump (confirm UI is tool-agnostic).
- Smoke: entitle
ai+credit-notes(Invoices required) → Ask EloSync fetch credit note → propose status/assign/note → Confirm; Issued needscredit-notes.issue; Draft target rejected.
Go-live: AI Credit Note triage production readiness · ops AI deployment.
AI Leave triage tools 1.15.0 → 1.16.0
After migrate (2026_09_16_040000_bump_ai_module_version_to_1_16_0):
- Confirm catalog
ai.versionis 1.16.0 (migrate-only; do notdb:seed). - No SPA/Mobile deploy required for this bump (confirm UI is tool-agnostic).
- Smoke: entitle
ai+employees+leave-management→ Ask EloSync list pending / fetch leave → propose approve or reject → Confirm; both writes needleave-management.approve; reject requires review notes.
Go-live: AI Leave triage production readiness · ops AI deployment.
AI Contract triage tools 1.16.0 → 1.17.0
After migrate (2026_09_27_180000_bump_ai_module_version_to_1_17_0):
- Confirm catalog
ai.versionis 1.17.0 (migrate-only; do notdb:seed). - No SPA/Mobile deploy required for this bump (confirm UI is tool-agnostic).
- Smoke: entitle
ai+opportunities+contracts→ Ask EloSync fetch contract → propose status/assign/note → Confirm; Sent needscontracts.send(issues acceptance token); Active from Sent needscontracts.accept.
Go-live: AI Contract triage production readiness · ops AI deployment.
Sales document invoice conversion (quotations 1.4.1 / contracts 1.2.1 / invoices 1.6.1 / estimates 1.3.3)
After migrate:
- Confirm catalog versions: quotations
1.4.1, contracts1.2.1, invoices1.6.1, estimates1.3.3 - Confirm
customer_invoices.contract_idexists (nullable FK) and unique nullableestimate_id - Confirm
quotations.convertandcontracts.convertare granted to default admin/manager roles - Deploy the SPA after migrate — convert actions 422 until Invoices is entitled; contract re-bills need
acknowledge_repeat_billing
Do not unique-index customer_invoices.quotation_id. Contract billing is repeatable. Quote/estimate one-shot uses QuotationInvoiceGuard plus lockForUpdate (and unique estimate_id).
Go-live: Sales document convert production readiness.
Sales document invoice conversion (quotations 1.4.0 / contracts 1.2.0 / invoices 1.6.0 / estimates 1.3.2)
Superseded by 1.4.1 / 1.2.1 / 1.6.1 / 1.3.3 integrity hardening above. Historical checklist:
- Confirm catalog versions: quotations
1.4.0, contracts1.2.0, invoices1.6.0, estimates1.3.2 - Confirm
customer_invoices.contract_idexists (nullable FK) - Confirm
quotations.convertandcontracts.convertare granted to default admin/manager roles - Deploy the SPA after migrate — convert actions 422 until Invoices is entitled on the workspace
Do not unique-index customer_invoices.quotation_id. Contract billing is repeatable; the quotation/estimate one-shot guard is application-level (QuotationInvoiceGuard).
Calendar invitee ACL 1.1.0 → 1.2.0
After migrate (2026_09_27_190000_bump_calendar_module_version_to_1_2_0):
- Confirm catalog
calendar.versionis 1.2.0 (migrate-only; do notdb:seed). - Deploy Backend before SPA — invitees need list/view ACL +
read_onlyon the resource. - Smoke: create a meeting with an internal invitee → invitee
GET /calendar/eventsincludes the projection withread_only: true;PUTreturns 403.
Go-live: Calendar invitee ACL 1.2.0 production readiness.
Contracts 1.6.0 → 1.7.0 — accept evidence
After migrate (2026_09_24_020619_add_contract_acceptance_evidence_fields_to_contracts_table):
- Confirm catalog
contractsversion is1.7.0 - Confirm nullable columns:
accepted_by_phone,acceptance_user_agent,acceptance_signature_path,acceptance_signature_method,acceptance_id_document_path,acceptance_id_document_type,acceptance_id_document_original_name - Deploy the SPA after migrate — Settings toggles and guest accept multipart fields
- Signature/ID Settings keys require Storage entitlement (phone does not); SPA switches stay disabled without Storage
- Smoke public accept + staff signature/ID downloads + PDF signature embed + force-delete purge on staging
Do not ship the empty stub 2026_09_23_210611_add_contract_acceptance_evidence_fields_to_contracts_table if it appears in a branch — only the 2026_09_24_020619_… migration is valid.
Go-live: Contracts 1.7.0 accept evidence production readiness.
Contracts auto-renew 1.7.0 → 1.8.0
After migrate (2026_09_27_142116_add_auto_renew_to_contracts_table + 2026_09_27_142147_bump_contracts_module_version_to_1_8_0):
- Confirm catalog
contracts.versionis 1.8.0 (migrate-only; do notdb:seed). - Confirm
contracts.auto_renewexists (boolean, default false). - Confirm scheduler runs
contracts:process-auto-renewalsdaily (Forge/Cloud). - Deploy SPA after migrate — Auto-renew checkbox/Switch and validation.
Go-live: Contracts auto-renew 1.8.0 production readiness.
Contracts 1.1.0 — auto-fill and HTML memos
After migrate:
- Confirm catalog
contractsversion is1.1.0 - Confirm
contracts.descriptionexists (nullable text) - Deploy the SPA after migrate — posting
descriptionbefore the column exists will 500 - Store allows the creating actor as
assigned_to. The SPA copies assignee only when that user is in the eligible picker; omittedassigned_tostill defaults to the actor.
See Contracts 1.1.0 production readiness.
Founding Beta invites
After migrate (2026_08_16_232506_add_founding_beta_invites_to_beta_applications_table):
- Confirm
founding_beta_enabled,founding_beta_apply_url, andfounding_beta_invite_ttl_daysexist (seeded viaupdateOrInsertin that migration). - Ensure a queue worker listens to
emails(Founding Beta invite notification). - Set
FRONTEND_URLto the SPA that serves/#/register?invite=…. - Keep marketing origins off
SANCTUM_STATEFUL_DOMAINS(public apply/resend use Bearer-less JSON + CSRF except).
Go-live checklist: Founding Beta invite production readiness.
Invoices 1.2.0 (status model)
After migrate:
- Confirm catalog
invoicesversion is1.2.0 - Confirm existing invoice rows remapped (
sent/partial→unpaid,void→cancelled)
Invoices 1.1.1 (branded PDF settings)
After migrate:
- Confirm catalog
invoicesversion is1.1.1 - Operators can fill Settings → Branding → Invoice company profile / payment details for PDF chrome
Invoices 1.1.0 (recurring + PDF)
After migrate:
- Confirm catalog
invoicesversion is at least1.1.0(prefer1.1.1after the branded PDF polish migrate) - Confirm scheduler includes
invoices:generate-recurring(daily,withoutOverlapping(120),onOneServer) composer installmust includedompdf/dompdffor PDF download- Optional env (defaults are fine):
INVOICES_RECURRING_CATCHUP_CAP(52),INVOICES_RECURRING_CHUNK_SIZE(100),INVOICES_RECURRING_TIME_BUDGET_SECONDS(45),INVOICES_PDF_CACHE_SECONDS(300),INVOICES_PDF_PER_MINUTE(30) - Treat a non-zero
invoices:generate-recurringexit as a tenant-series failure — see logsinvoices.generate-recurring.tenant_failed
See Invoices 1.1.0 production readiness.
Billing product line picker (quotations / estimates / invoices + products)
After migrate (Backend before SPA):
php artisan migrate --force
# includes:
# 2026_08_18_000658_bump_products_module_version_to_1_1_0
# 2026_08_18_001042_add_product_id_to_billing_document_lines_tables
# 2026_08_18_001043_bump_billing_document_modules_for_product_line_picker
# 2026_08_18_063000_bump_modules_for_product_line_picker_hardening- Confirm catalog versions: products
1.1.1, quotations1.3.1, estimates1.3.1, invoices1.5.1 - Existing entitled workspaces keep entitlements; catalog bump does not auto-install modules
- Smoke: create a line with
product_idon a draft quotation/estimate/invoice; convert estimate → invoice; generate a recurring occurrence
See Billing product line picker production readiness.
Storage module (2026-08-13)
After migrating Storage:
- Map gateway prices for each billable pack (
storage-10…storage-1000) × monthly/yearly - Confirm
FILESYSTEM_BRANDING_DISK=publicand uploads on S3/Wasabi - Workspaces that already had Team Chat receive free Storage automatically (grandfather migration)
- New workspaces install free Storage from Marketplace when they need content uploads
See Storage deployment.
New workspaces after upgrade
TenantProvisioningService continues to:
- Install every published
is_default_includedmodule - Provision default roles/permissions via
TenantAuthorizationProvisioningService - Create the owner via
TenantAuthBootstrapService(no RBAC mutation on later logins)
Multi-Provider Email Delivery
After pulling a release that includes multi-provider email:
composer install --no-dev --optimize-autoloader # pulls symfony/postmark-mailer + mailgun-mailer
php artisan migrate --force # email_logs tables + email-logs.* permission grants
php artisan email:migrate-tenant-mail-modes # optional; --dry-run first. Backfills mail_mode from legacy mail_host
php artisan queue:restart # required — workers cache mailer configNotes:
- Legacy tenants with a filled
mail_hoststill behave as custom SMTP until the migrate command runs (recommended). - Configure Central Settings → Mail (SMTP / Postmark / Mailgun). Env
MAIL_*remains bootstrap fallback only. - After changing mail credentials in Settings, always run
php artisan queue:restart. - Smoke: Central + Tenant Send test, then open Email logs.
See Multi-Provider Email.
Verification
php artisan test --compact tests/Feature/ProductionModuleDeploymentTest.phpSmoke:
- Existing workspace receives the new module in nav only if it never had that subscription (or already had it active)
- Customized role permission sets are unchanged except for explicitly migrated additive grants
- New registration still gets all default-included modules + full owner permissions
Expenses categories 1.1.0 (first-party SPA contract)
Ship Backend migrate before the SPA. Expense resources no longer return category as a string; the SPA expects category_id and embedded { id, name, slug }.
php artisan migrate --force # expense_categories + backfill + catalog bump 1.0.0 → 1.1.0
# then deploy Frontend, then DocsDo not run db:seed. Starter categories (Travel / Office / Software / Utilities / Other) lazy-seed on first list/create/PO convert. Other cannot be deleted; starter slugs stay stable if renamed.
See Expenses production.
Help Desk module v1.0.0
After migrate, existing workspaces do not auto-install Help Desk. Operators enable help-desk from Marketplace. Registration is migrate-only via DefaultModuleRegistrar — do not run db:seed. Permissions ship additively via TenantPermissionSynchronizer.
php artisan migrate --force # help_desk_* tables + catalog registration + help-desk.* permissions
# then deploy Frontend, then DocsSee Help Desk production.
Projects 1.0.0 + Tasks project_id (1.2.0)
php artisan migrate --force # projects tables + permissions + catalog + tasks.project_id + tasks 1.2.0
# then deploy Frontend (Projects nav + optional task project picker), then DocsDo not run db:seed. Projects is free Marketplace opt-in (not default-included). See Projects production.
Automation module (billable add-on)
After migrate, existing workspaces do not auto-install Automation. Operators install automation from Marketplace. Include the automations queue on workers and confirm automation:dispatch-schedules is on the scheduler. Optional env: AUTOMATION_WEBHOOK_SECRET. See Automation production.
Storage module + capacity packs
After migrate, free storage and billable packs are catalog-only except: workspaces that already have Team Chat entitled receive free Storage via the grandfather migration (and new Team Chat installs companion-install Storage). Map Stripe/Creem prices for each pack × cycle before selling packs. See Storage deployment.
Knowledge Base module (free Operations opt-in)
After migrate, existing workspaces do not auto-install Knowledge Base. Operators install knowledge-base from Marketplace (internal articles only; not billable). See Knowledge Base production.
Assets module v1.0.0
After migrate, existing workspaces do not auto-install Assets. Operators enable assets from Marketplace. Registration is migrate-only via DefaultModuleRegistrar — do not run db:seed. Permissions ship additively via TenantPermissionSynchronizer. No hard module dependencies.
php artisan migrate --force # assets / asset_notes / asset_activities + catalog registration + assets.* permissions
# then deploy Frontend, then DocsSee Assets production.