0Executive Summary
OrafolController.php, routes/orafol.php, and the menu in resources/views/sections/menus/store.blade.php already gate ORAFOL features behind GetCompanyId() == 100. There are 25+ orafol routes (group catalog, group assignments, parent accounts, integration hub, payment controls, regional reports, sales automation, KPI dashboard, 11 reports). Most are UI scaffolds without backend logic — views exist, models/migrations/business-logic do not. This is a major head-start.
Verdict
Missio is a mature multi-tenant Laravel SaaS with strong payments (Stripe, PayPal, Square, Authorize.Net, Razorpay, Mollie, Flutterwave, PayFast, Paystack), abandoned-cart recovery, multi-guard auth, and a theme engine. Three areas blocking ORAFOL UAT: (1) parent/child company hierarchy (only customer-groups have parent_id), (2) ORAFOL BE ERP connector (does not exist), (3) multi-location inventory (single stock field today). The 25+ ORAFOL skeleton routes need their backend logic written.
1Current System Architecture
1.1 Stack & Structure
| Layer | Technology | Notes |
|---|---|---|
| Framework | Laravel 10 (worksuite-saas fork) | Multi-tenant via company_id scoping |
| Database | MySQL | Tables prefixed mixed: tbl_* for commerce, default Laravel for users/roles |
| Auth | Laravel Sanctum + Socialite + custom 2FA | 4 guards: web/admin/customer/api |
| Frontend | Blade + jQuery + Vue partials + 29 themes | Theme manager: hexadog/laravel-themes-manager |
| Module system | nWidart/laravel-modules | Modules: Event, RestAPI, Recruit (etc.) |
| Queue | Laravel Queue (DB driver assumed) | Jobs: ProcessInboundEmailJob, abandoned-cart reminders |
| DOMPDF + barryvdh/laravel-dompdf | Invoices, proposals | |
| Excel I/O | maatwebsite/excel | Used; available for product/order import |
1.2 Modules & Responsibilities
- Product CRUD + variants + attributes
- Categories (recursive)
- Orders + order items
- Customer groups + tiered % discount
- FrontProductController
- MemberController (customer area)
- Api/Shop: Catalog, Cart, Checkout, Payment
- Stripe, PayPal, Square, Authorize.Net
- Razorpay, Mollie, Flutterwave
- PayFast, Paystack
- Per-company credentials in DB
- Pages, Menus, Post Types
- Blogs, Settings
- Group catalog/assignments
- Parent accounts, customer rules
- Integration hub, KPI dashboard
- 11 stub reports
- Non-commerce verticals (worksuite legacy)
- Bloat — consider hiding for ORAFOL tenant
1.3 Tightly Coupled Components & Custom Logic
GetCompanyId() == 100hardcoded instore.blade.php— tenant-specific UI gating in views. Should be a feature flag.Product::getPriceAttribute()queriesAuth::guard('customer')->user()->customer_group_idinside the model accessor — couples model to auth/session and prevents background-job pricing.- Stripe modes read
company.stripe_mode,company.test_stripe_secret,company.live_stripe_secretdirectly — should go throughPaymentGatewayCredentialsuniformly (other gateways do). - Theme switching tied to company config but no abstraction layer; theme upgrades require manual file copy across 29 directories.
OrderCartmixestype='item'andtype='discount'rows — clever but fragile (forgettingwhere type=itemin totals breaks math).
1.4 Data Flow — Current Order Lifecycle
2Feature Mapping — Magento → Missio
2.1 Account & User
| Feature | Status | Where | Action |
|---|---|---|---|
| Multi-user per company | EXISTS AS-IS | users.company_id + role_user | Reuse |
| Role-based permissions (Entrust) | EXISTS AS-IS | EntrustUserTrait, permission_role | Reuse |
| Customer-group hierarchy | EXISTS AS-IS | customer_groups.parent_id (mig 2025_09_10) | Reuse |
| Parent / child company hierarchy | MISSING | — | BUILD: companies.parent_company_id + scopes |
| Multi-role single login | NEEDS REFACTOR | Pivot supports it; UI doesn't | Add role-switcher dropdown |
| Self-service sub-account UI | STUB ONLY | orafol/parent_accounts.blade.php | Implement invite flow + middleware scoping |
| Sales rep visibility by region | MISSING | — | BUILD: sales_rep_regions table + dashboard scope |
| 2FA / MFA | EXISTS AS-IS | LoginController::checkCode() | Reuse for admin; extend to customer guard if requested |
| Social login | EXISTS AS-IS | Google, Facebook, Twitter via Socialite | Reuse (admin); extended to customer in MemberController |
| SSO / OKTA / SAML | MISSING | — | BUILD if ORAFOL needs employee SSO |
2.2 Catalog & Pricing
| Feature | Status | Where | Action |
|---|---|---|---|
| Simple products | EXISTS AS-IS | Product.type | Reuse |
| Configurable products (variants) | EXISTS AS-IS | ProductVariant + values | Reuse |
| Grouped / bundle products | MISSING | — | BUILD product_groups pivot |
| Downloadable / virtual | PARTIAL | ProductFiles | Wire to Issuu |
| Product attributes (size/color/series) | EXISTS AS-IS | Full schema | Reuse |
| Group-based product visibility | EXISTS AS-IS | customer_group_product pivot | Reuse |
| Tiered pricing (qty breaks) | PARTIAL | Group % discount only | BUILD price_tiers table |
| Catalog price rules | MISSING | Coupons cover cart-rules only | BUILD rule engine |
| Cart price rules / coupons | EXISTS AS-IS | Coupons + CouponUsage | Reuse |
| 7,000+ SKU scale | NEEDS REFACTOR | No search index | Add Meilisearch / Algolia / Scout |
| Layered / faceted nav | PARTIAL | Filter widgets exist | Refactor against search index |
| Product reviews & ratings | MISSING | — | BUILD module |
| Wishlists | EXISTS AS-IS | MemberController::store_wishlist | Reuse |
| Compare products | MISSING | — | BUILD (low priority) |
| Recently viewed | MISSING | — | BUILD (low priority) |
| Quick order / SKU pad | PARTIAL | Inquiry modal only | BUILD true CSV-paste pad |
| Quote request / RFQ | PARTIAL | Inquiry modal | BUILD quote → order conversion + sales-rep approval |
| Requisition lists / saved carts | MISSING | — | BUILD (Magento B2B has it; high B2B value) |
| Issuu literature | PARTIAL | Files exist | Embed widget per product |
2.3 Inventory
| Feature | Status | Where | Action |
|---|---|---|---|
| Single-stock tracking | EXISTS AS-IS | Product.stock, ProductVariant.stock | Reuse for fallback |
| Multi-warehouse inventory | MISSING | — | BUILD warehouses + inventory_locations |
| Stock reservations (during checkout) | MISSING | — | BUILD (prevents over-sell) |
| Backorder / pre-order | MISSING | — | BUILD per-product flag |
| Low-stock alerts | STUB ONLY | orafol/reports/low-stock view | Wire query + email job |
| ORAFOL BE ERP sync (in/out) | MISSING | — | BUILD — XL |
| Kathy's facility 2-way connector | MISSING | — | BUILD — spec TBD |
| Inventory audit trail | MISSING | — | BUILD inventory_movements ledger |
2.4 Payments & Credits
| Feature | Status | Where | Action |
|---|---|---|---|
| Stripe / PayPal / 7 others | EXISTS AS-IS | 9 controllers in Payment/ | Reuse |
| Per-company gateway credentials | EXISTS AS-IS | PaymentGatewayCredentials | Reuse + standardize Stripe path |
| Webhook handling per gateway | EXISTS AS-IS | verify-webhook/{hash} | Reuse |
| PayPal subscriptions / recurring | EXISTS AS-IS | PaypalController | Reuse |
| Offline payment methods | EXISTS AS-IS | OfflinePaymentMethod | Reuse |
| Purchase Order workflow | PARTIAL | Generic offline only | BUILD: PO upload, PO #, approval state |
| Net-30 / Net-60 terms | MISSING | Invoice has no terms field | BUILD per-customer-group terms + AR aging |
| Credit limit enforcement | MISSING | — | BUILD on customer group |
| Store credits | PARTIAL | CompanyAddonCredit + credit notes (invoice-side) | BUILD customer-side ledger usable at checkout |
| Rewards / loyalty points | MISSING | — | BUILD points ledger + earn/redeem rules |
| Gift cards | MISSING | — | BUILD (Magento parity) |
| Refunds & partial refunds | STUB ONLY | orafol/reports/refunds view | Wire to gateway refund APIs |
| Multi-currency | MISSING | — | BUILD if Canada operations need CAD |
2.5 Shipping & Fulfillment
| Feature | Status | Where | Action |
|---|---|---|---|
| Shippo (multi-carrier aggregator) | EXISTS AS-IS | app/Helper/Shippo.php | Reuse for rates/labels |
| UPS direct API | PARTIAL | ShippingMethodCredentials + UPS view | Implement rate + label calls |
| USPS / FedEx direct | PARTIAL | Enums in credentials table | Implement; OR use Shippo umbrella |
| Freight (LTL) carriers | MISSING | — | BUILD or use Shippo Freight |
| Group-based shipping rules | STUB ONLY | orafol/shipping_restrictions.blade.php | BUILD rule engine: zone, weight, group, total |
| Shipping zones | MISSING | — | BUILD (Magento has zones & methods OOTB) |
| Bulk UPS tracking import | MISSING | — | BUILD CSV importer + queued attach |
| Customer-provided shipping labels | MISSING | — | BUILD checkout step + storage |
| Fulfillment dashboard (pick/pack/ship) | MISSING | — | BUILD module — biggest fulfillment gap |
| Automated order routing | MISSING | — | BUILD: by location, SKU, group → warehouse |
| Drop-ship workflow | MISSING | — | BUILD if vendor drop-ship needed |
| Tax engine (Avalara / TaxJar) | MISSING | — | BUILD: SOW silent; US+CA tax is non-trivial |
2.6 Integrations & Operations
| Feature | Status | Where | Action |
|---|---|---|---|
| ORAFOL BE (US & CA) | MISSING | — | BUILD — XL connector |
| HubSpot CRM | MISSING | — | BUILD contact/deal sync |
| Constant Contact | MISSING | — | BUILD readiness hooks (SOW says “future”) |
| QuickBooks | EXISTS AS-IS | quickbooks/v3-php-sdk | Verify wired up; available |
| SendGrid (email + webhook) | EXISTS AS-IS | app/Helper/Sendgrid.php | Reuse |
| Twilio SMS | EXISTS AS-IS | composer dep | Reuse |
| OpenAI / Mira AI | EXISTS AS-IS | app/Helper/OpenAi.php | Reuse for product descriptions, search suggestions |
| Zoom / Google Calendar | EXISTS AS-IS | Composer deps | Out of scope for ORAFOL |
| Issuu | MISSING | — | BUILD embed integration |
| Sentry error tracking | EXISTS AS-IS | config/sentry.php | Verify enabled in prod |
3Frontend Features & Login Architecture
3.1 Frontend Shop — What customers see
| Page / Feature | URL / View | Status | Notes |
|---|---|---|---|
| Storefront home | /shop → front/shop/index.blade.php | HAVE | Theme-driven |
| Product detail | /shop/product/{slug} → details.blade.php | HAVE | Variant selector, wishlist, inquiry |
| Category browse | Category routes → _widget-store-category | HAVE | Recursive nesting |
| Search + filter | Sidebar widgets (price, color, attribute) | PARTIAL | No search index; client-side filter only |
| Cart | cart.blade.php + _sidebar-cart | HAVE | Guest + logged-in supported |
| Checkout | checkout.blade.php (34 KB) | HAVE | Comprehensive; all 9 gateways selectable |
| Order confirmation | order.blade.php | HAVE | |
| My orders | my_orders.blade.php | STUB | 297 bytes — needs full implementation |
| Customer dashboard | /member/dashboard | HAVE | MemberController |
| Customer addresses | Member area | HAVE | |
| Wishlist | Member area | HAVE | product_wishlists table |
| Inquiry / quote modal | _inquiry-modal.blade.php | PARTIAL | Captures interest; no quote → order conversion |
| Abandoned cart recovery | Background job | HAVE | Full state machine: abandoned→email_sent→recovered |
| Quick reorder | — | MISSING | Build “reorder this” on order detail |
| Requisition lists | — | MISSING | Build (B2B essential) |
| SKU paste pad (bulk add) | — | MISSING | Build (B2B essential) |
| Sub-account self-service | orafol scaffold | STUB | UI exists, no logic |
| Order approval queue | orafol scaffold | STUB | UI exists, no logic |
| Reviews & ratings | — | MISSING | Build module |
| Compare products | — | MISSING | Build (low priority) |
3.2 Login Types on Frontend — CRITICAL
The platform has 4 distinct authentication guards. Mapping them and clarifying the ORAFOL deployment use is essential before kickoff.
| Guard | Login URL | Model / Table | Purpose | Status |
|---|---|---|---|---|
web | /login | UserAuth / users | Internal staff (NH employees, ORAFOL admins) | ACTIVE |
admin | /login | UserAuth / users | Same as web — explicit admin guard | ACTIVE |
customer | /signin | Customer / tbl_customers | Storefront / distributors / B2B — this is what ORAFOL distributors will use | ACTIVE |
api | Sanctum bearer | RestAPI\UserAuth / users | Headless API consumers | ACTIVE |
What ORAFOL distributors will need
- Single login URL —
portal.orafol.com/signingoes tocustomerguard - Username OR email login — already supported in
MemberController::authentication() - 2FA on customer guard — currently only on
web/admin guard. EXTEND - Email verification — supported via
email_verified_at+ token route - Password reset —
/member/forget-passwordexists - Magic link / OTP — not present, build if requested
- SSO / OKTA — not present; ORAFOL employees may want this for admin login
- Invite-only signup —
/invitation/{code}exists; needs sub-account flow on top - Role/account switcher after login — if a single user belongs to multiple ORAFOL distributors, they need a context picker. BUILD
3.3 Theme System
29 themes under themes/frontend/. ORAFOL will need either a custom theme or a fork of shop / radiant. Theme is selected per-company. Customizable: header, product cards, checkout form fields, color scheme, language files (54+ via laravel-lang/lang).
4Payment Integrations — All Gateways
Missio already has 9 production-grade payment gateways, far more than most Magento installs run. The PDF requirement (PayPal + purchase orders + bank transfers) is fully covered by what exists.
| Gateway | Controller | Modes | Webhooks | Recurring | SOW Match |
|---|---|---|---|---|---|
| Stripe | Payment/StripeController.php | live / test | YES | Indirect (via cart) | — |
| PayPal | Payment/PaypalController.php | live / sandbox | YES | YES | Required by SOW |
| Square | Payment/SquareController.php | sandbox / prod | YES | — | — |
| Authorize.Net | Payment/AuthorizeController.php | sandbox / live | (direct) | YES | — |
| Razorpay | Payment/RazorPayController.php | live / test | YES | YES | India only |
| Mollie | Payment/MollieController.php | live / test | YES | — | EU |
| Flutterwave | Payment/FlutterwaveController.php | live / test | YES | — | Africa |
| PayFast | Payment/PayfastController.php | live / test | YES | — | South Africa |
| Paystack | Payment/PaystackController.php | live / test | YES | — | Africa |
| Offline (PO / bank transfer) | OfflinePaymentMethod | — | n/a | — | Required by SOW |
4.1 Magento gateways NOT in Missio (parity check)
| Magento gateway | Status in Missio | Recommendation |
|---|---|---|
| Braintree | MISSING | Skip — PayPal covers (Braintree owned by PayPal) |
| Adyen | MISSING | Skip unless ORAFOL EU subsidiary requests |
| Klarna / Affirm (BNPL) | MISSING | BUILD if consumer-facing; not needed for B2B distributors |
| Apple Pay / Google Pay | MISSING | Stripe wrappers can add; low priority for B2B |
| Amazon Pay | MISSING | Skip |
| Worldpay / CyberSource | MISSING | Skip unless explicitly required |
| ACH / Plaid | MISSING | BUILD if direct-debit needed for distributor net-terms collection |
4.2 ORAFOL-specific payment requirements (from SOW)
- Rewards point programs — BUILD
- Store credits — EXTEND (have invoice-side, need customer-side)
- PayPal payments — HAVE
- Purchase orders / bank transfers — EXTEND (offline method exists; add PO upload + PO# + approval)
- Charge-to-account invoicing with payment terms — BUILD (Net-30/60, credit limits, AR aging)
53rd-Party Integrations — Complete Inventory
5.1 What's installed (composer.json + helpers)
5.2 Integration risk profile
| Integration | Type | Coupling | Risk |
|---|---|---|---|
| 9 payment gateways | API + webhook | Loose — per-company creds | Low |
| Shippo | API only | Helper class | Low |
| SendGrid | API + inbound webhook | Helper | Low |
| ORAFOL BE | Bi-directional API + cron | Will be tight (orders/inventory critical path) | HIGH — spec unknown |
| Kathy's facility | Bi-directional | Tight (inventory truth source) | HIGH — system unknown |
| HubSpot | API + webhook | New build | Medium |
| QuickBooks | OAuth + API | Loose | Low (already installed) |
6Technical Debt Analysis
6.1 Fragile / hardcoded logic
| Issue | Where | Impact |
|---|---|---|
| Tenant-specific UI gating | store.blade.php — GetCompanyId() == 100 | Hardcodes ORAFOL ID. Replace with features('orafol_b2b') flag. |
| Auth in model accessors | Product::getPriceAttribute() — reads Auth::guard('customer') | Breaks background jobs, API context, sales-rep impersonation. Refactor to pricing service. |
| Stripe creds split paths | company.stripe_mode direct fields vs. PaymentGatewayCredentials | Dual sources of truth. Standardize on credentials table. |
| Type-overloaded OrderCart | type='item' + type='discount' in same table | Easy to forget filter. Consider separate cart_adjustments table. |
| 29 themes | themes/frontend/* | Maintenance surface for security patches; many for unrelated verticals |
| Mixed table prefixes | tbl_customers vs users | Indicates fork merge history; cosmetic but confusing |
Stub my_orders.blade.php | 297 bytes | Customer order history feature is missing on storefront |
6.2 Performance bottlenecks & scaling risks
- No search index. 7,000 SKU target needs Meilisearch or Algolia (Laravel Scout). Current LIKE-based queries will not scale.
- No DB indexes confirmed on
OrderCart.cart_id,products.sku,customer_groups.parent_id. Audit indexes during Phase 1. - Pricing accessor on every product render reads auth guard. Hydrating a 50-product page = 50 auth calls. Cache or batch.
- No HTTP caching layer (Cloudflare / Varnish). Magento has built-in FPC. Plan CDN + cache for catalog pages.
- Single-stock field = race conditions on concurrent checkout. Move to reservation pattern with row-level locks or Redis counters.
- Job queue unclear. No Horizon visible; check if abandoned-cart job runs on supervisor or cron+work.
6.3 Duplicate logic
- Pricing logic duplicated between
Product::getPriceAttribute()andProductVariant::getPriceAttribute(). - Three contact-route files:
contacts.php,contacts_old.php— legacy not yet removed. - Multiple mail providers configured (SendGrid, Mailgun, Postmark, SES) — pick one and remove others or document tenant choice.
7Migration Strategy — Magento → Missio
7.1 What we REUSE from Missio
| Multi-guard auth, 2FA, social login | REUSE |
| Product / Variant / Attribute CRUD | REUSE |
| Customer groups + group-product visibility | REUSE |
| Cart + Checkout API (CartController, CheckoutController) | REUSE |
| 9 payment gateways + webhook framework | REUSE |
| Coupons + abandoned-cart recovery | REUSE |
| Wishlist, addresses, member dashboard | REUSE |
| SendGrid, Twilio, OpenAI, Sentry, S3, QuickBooks | REUSE |
| Theme system (one custom ORAFOL theme) | REUSE + EXTEND |
| 25+ ORAFOL stub routes/views | UI READY — WIRE BACKEND |
7.2 What we REBUILD (in Missio)
| Parent/child company hierarchy | BUILD |
| Multi-warehouse inventory | BUILD |
| Tiered pricing (qty breaks) + catalog price rules | BUILD |
| Net-terms invoicing + AR aging + credit limits | BUILD |
| Fulfillment dashboard + automated routing | BUILD |
| Group-based shipping rules | BUILD |
| Quote / RFQ → Order conversion | BUILD |
| Requisition lists / saved carts | BUILD |
| Quick-order SKU pad | BUILD |
| Rewards points + customer-side store credit | BUILD |
| Bulk UPS tracking import | BUILD |
| Customer-provided shipping label workflow | BUILD |
| Sub-account self-service (invite, manage children) | BUILD |
| Sales-rep regional dashboard scoping | BUILD |
7.3 What we REPLACE with SaaS / 3rd-party
| Capability | Replace with | Why |
|---|---|---|
| Magento search | Meilisearch (self-host) or Algolia | 7K SKU faceted search at scale; Laravel Scout integration |
| US + Canada sales tax | Avalara or TaxJar | Multi-state/province compliance — not worth building |
| Multi-carrier shipping | Shippo (already installed) or EasyPost | One API for UPS/USPS/FedEx/freight + label printing |
| Magento email templates | SendGrid Dynamic Templates | Editable in SendGrid UI; no code deploy for copy changes |
| Magento CMS pages | Existing Missio CMS module | Already in code (CMS Pages API) |
| Magento product reviews | Yotpo / TrustPilot widget | SaaS solves moderation, photo reviews, Google snippets |
| Issuu literature | Issuu embed widget | Per requirement |
| Error tracking | Sentry (already installed) | — |
7.4 What we REMOVE / hide for ORAFOL tenant
- Donations, donors, donation-pages, P2P, pledges, grants, RFPs, video interviews, donation events — HIDE via tenant module flags
- Recruitment module, gallery, forum, channels — HIDE
- 27 of 29 themes (keep ORAFOL custom +
shopbase) — PRUNE from tenant contacts_old.phproute file — DELETE
8Recommended Target Architecture
Per the SOW, Missio is delivered as three layers. Here's how to align the Laravel codebase to that model.
Layer 1 Experience Layer
Customer-facing storefront, admin UI, mobile API.
- Storefront: One ORAFOL custom theme under
themes/frontend/orafol/. Distributor portal, catalog browse, cart, checkout, account. - Admin: Existing Bootstrap admin under
/account/*. Orders, products, customers, reports. - Mobile-ready: SOW says “mobile-first.” Reuse existing API/Shop endpoints for future native app.
- Auth:
customerguard for distributors,web/adminfor ORAFOL staff. Add SSO if requested.
Layer 2 Core Business Logic Layer
Pricing, catalog, orders, inventory, customers — tenant-isolated services.
- Pricing Service: Extract from Product accessors. Inputs: product, variant, customer, qty, group. Output: unit price + applied rules. Reusable from background jobs.
- Catalog Service: Product, variant, attribute, category. Backed by Meilisearch index for facet search.
- Order Service: Cart → Order → Fulfillment lifecycle. State machine. Hooks for ERP sync.
- Inventory Service: Multi-location.
warehouses,inventory_locations,inventory_movements. Reservation API. - Customer Hierarchy Service: Companies (parent/child), users, customer groups, role scoping. Single source of truth for “what can this user see?”
- Pricing & Discount Engine: Group tiers + catalog price rules + cart price rules + coupons composed in defined order.
- Fulfillment Service: Pick/pack/ship state machine. Order routing rules. Carrier label generation via Shippo.
Layer 3 Integration Layer
External system connectors. Idempotent, observable, retryable.
- ERP Connector Framework: Generic base class. Concrete implementations: ORAFOL BE (US), ORAFOL BE (Canada), Kathy's facility.
- Outbound: Order created, inventory adjusted, customer updated → queued job → ERP. With retries + dead-letter queue.
- Inbound: Webhook + scheduled poll. Inventory deltas, invoice paid, shipment confirmed.
- HubSpot Connector: Customer → Contact, Order → Deal sync. Webhook on contact updates.
- Tax Connector: Avalara/TaxJar at cart total time.
- Shipping Connector: Shippo for rates + labels + tracking.
- Payment Connectors: 9 existing gateways. Standardize creds path.
- Observability: Every external call logged to
integration_logstable + Sentry breadcrumbs. Build a /account/integration-hub page (orafol stub already exists).
8.1 Event-driven design
Use Laravel events for cross-layer hooks. Examples:
OrderPlaced → ERP outbound + HubSpot deal + email + inventory reserve
OrderShipped → Customer email + ERP update + tracking webhook
InventoryAdjusted → ERP outbound + low-stock alert if threshold
CustomerCreated → HubSpot contact + welcome email
PaymentCaptured → QuickBooks invoice + gateway webhook log
8.2 Data ownership
| Entity | Owner | Sync direction |
|---|---|---|
| Products (master) | ORAFOL BE | Inbound to Missio |
| Products (storefront content: descriptions, images) | Missio admin | Local only |
| Customers / Distributors | Missio (with HubSpot mirror) | Bi-directional with HubSpot |
| Orders | Missio | Outbound to ORAFOL BE |
| Inventory levels | ORAFOL BE / Kathy's facility | Inbound to Missio |
| Invoices & AR | ORAFOL BE | Inbound (status to Missio for AR display) |
| Reward points | Missio | Local |
9Gap Analysis — Master Table
| Feature | Current State | Target State | Gap | Action | Effort |
|---|---|---|---|---|---|
| Parent/child company | customer_groups have parent_id only | Full company hierarchy with cascade scopes | companies.parent_company_id missing | Build migration + Eloquent scopes + dashboard rollup | L |
| Self-service sub-accounts | UI scaffold in orafol/parent_accounts | Parent invites & manages children | No backend logic | Wire invite flow + permissions middleware | L |
| Sales-rep regional scoping | None | Reps see only assigned region/group | No region model, no scope | Build sales_rep_regions + dashboard scope | L |
| Tiered pricing (qty) | Group % discount | Qty 1-9, 10-49, 50+ pricing per group | No price_tiers | New table + price service hook | M |
| Catalog search index | SQL LIKE | Faceted, sub-100ms at 7K SKUs | No index | Add Meilisearch + Scout | L |
| Grouped products | None | Bundle/grouped product type | No model | Build product_groups pivot | M |
| Issuu literature | ProductFiles only | Issuu embed per product | No embed | Add field + render widget | S |
| Multi-warehouse inventory | Single stock field | Per-location stock + reservation | No location tables | warehouses, inventory_locations, inventory_movements | L |
| ORAFOL BE ERP sync | None | Bi-directional inventory/orders/invoices | No connector | Build connector framework + 2 implementations (US/CA) | XL |
| Kathy's facility connector | None | Two-way inventory + orders | Spec unknown | Discovery call + custom connector | L |
| Net-30/60 invoicing | Invoice has no terms | Per-customer-group payment terms | No terms field, no AR aging | Schema + AR dashboard | L |
| Credit limits | None | Per-customer-group cap with checkout enforcement | No field | Schema + checkout guard | M |
| Customer-side store credit | Invoice-side only | Apply at checkout | No customer ledger | customer_credits + checkout step | M |
| Rewards points | None | Earn / redeem with rules | No ledger | customer_points + earn rules + checkout redeem | L |
| PO upload & workflow | Generic offline payment | PO #, file upload, approval state | No PO fields | Extend OfflinePaymentMethod | M |
| Group-based shipping rules | UI scaffold | Rule engine: zone+weight+group+total | No engine | shipping_rules table + evaluator | M |
| UPS / USPS / FedEx full | Credentials only | Live rate quote + label print | No API calls | Use Shippo umbrella OR direct APIs | L |
| Bulk tracking import | None | CSV upload → attach to orders | No importer | Maatwebsite/excel job | S |
| Customer-provided labels | None | Customer uploads label/account at checkout | No checkout step | Add step + storage | M |
| Fulfillment dashboard | None | Pending/picked/packed/shipped queue | No module | Build module with role-scoped views | L |
| Automated order routing | None | Rules: by SKU/group/location → warehouse | No rule engine | routing_rules + listener on OrderPlaced | M |
| HubSpot CRM | None | Contact + Deal bidirectional | No connector | HubSpot SDK + sync jobs + webhooks | M |
| Constant Contact | None | Future-ready hooks (per SOW) | No event hooks | Expose customer-created event with API key field | S |
| Tax engine (Avalara/TaxJar) | None | Live tax calc at checkout | No connector | Add at cart total step | M |
| Quote / RFQ workflow | Inquiry modal | Distributor requests → rep approves → converts to order | No state machine | quotes table + approval UI | M |
| Requisition lists | None | Multiple named saved carts per buyer | No model | requisition_lists + items | M |
| Quick-order SKU pad | None | Paste SKU+qty → cart | No UI | Page + bulk-validate API | S |
| Reorder from past order | None (my_orders is stub) | One-click reorder | Stub view | Implement my_orders + reorder action | S |
| Product reviews | None | Reviews + ratings + moderation | No module | Build OR integrate Yotpo | M |
| 2FA on customer guard | Admin only | Optional 2FA for distributors | Customer guard lacks 2FA | Port from LoginController to MemberController | S |
| SSO / OKTA | None | Optional ORAFOL employee SSO | No SAML | laravel-saml2 if requested | M |
| Customer order history | my_orders.blade.php stub | Full order history with reorder/track | Stub | Build view + controller | S |
| Pruning unused modules | 29 themes, donation/event modules visible | Clean ORAFOL tenant view | Tenant feature flags loose | Module visibility per company | S |
10Risk Assessment
10.1 Migration risks
| Risk | Severity | Likelihood | Mitigation |
|---|---|---|---|
| ORAFOL BE API spec poorly documented | Critical | High | Request docs in kickoff week 1; build mock layer; budget contingency |
| Kathy's facility unknown system | Critical | High | Discovery call week 1–2; bring connector spec back to scope |
| Magento data export quality | High | Medium | Sample 100 SKUs week 2; validate images, attributes, prices |
| Tax engine omitted from SOW | High | High | Confirm Avalara/TaxJar with ORAFOL week 1; price as change order if needed |
| Catalog at 7K SKU scale | Medium | Medium | Add Meilisearch by week 4; load-test with synthetic data |
| Theme/UI sign-off delay | Medium | High | Lock design in week 2; iterate inside ORAFOL theme only |
| 10% contingency too tight | Medium | High | Strict change-order discipline; weekly scope review |
10.2 Data risks
- Customer data dual-source. If HubSpot and Missio both let users edit a customer, conflict resolution rules must be defined.
- Inventory truth source. ORAFOL BE is master, but during outage the portal must show last-known with timestamp + degraded indicator.
- Pricing drift. If catalog prices are master in BE but admins also edit in Missio, customers see inconsistencies.
- PII handling. Distributor company info, addresses, payment methods. Confirm SOC 2 / GDPR posture for ORAFOL legal review.
10.3 Integration risks
- Cascading failures. ERP outage should not block checkout. Build queue-and-retry pattern; never sync orders inline.
- Webhook replay attacks. Audit all 9 payment-gateway webhook signature verifications.
- Rate limits. HubSpot, Shippo, Avalara all rate-limit. Design batch + backoff.
10.4 Business continuity
- Cutover strategy. Hard cutover or parallel-run with Magento? Recommend 2-week parallel run with traffic split.
- Rollback plan. Keep Magento read-only for 90 days post-launch.
- SLA target 99.9% per SOW = 43 min downtime/month. Realistic with Sentry + uptime monitoring + Horizon.
- Distributor training. 14–16 weeks is tight for a 7K SKU catalog launch. Schedule training weeks 12–14 with at least 2 sessions.
11Prioritized Execution Plan
11.1 First 2 weeks (foundation + de-risk)
- Day 1–3: Replace
GetCompanyId() == 100with feature flagfeatures('orafol_b2b'). Hide unused modules for ORAFOL tenant. Standardize Stripe creds path. - Day 3–5: Kickoff calls — ORAFOL BE API docs request, Kathy's facility discovery, tax engine decision (Avalara vs. TaxJar vs. zone), Magento export audit.
- Week 2: Add
companies.parent_company_idmigration. Build multi-warehouse schema. Spike Meilisearch + Scout with 100 SKUs. Build ERP connector base class with mock implementation.
11.2 Phased plan vs. SOW timeline
| Phase | Weeks | Deliverables |
|---|---|---|
| Foundation | 1–3 | Feature flag, parent/child company, multi-warehouse schema, payment-creds standardization, search index spike |
| ERP & Integrations | 3–7 | ORAFOL BE connector (US + CA), Kathy's facility, HubSpot, Avalara/TaxJar, Shippo full |
| Catalog & Portal | 6–10 | Meilisearch live with 7K SKUs, tiered pricing, Issuu, sub-account UI, sales-rep scoping, ORAFOL theme |
| Order & Fulfillment | 9–12 | Net-terms, PO workflow, fulfillment dashboard, group shipping rules, bulk tracking import, customer labels, automated routing |
| B2B Niceties | 10–13 | Quote/RFQ, requisition lists, quick-order pad, reorder, customer order history, store credits, rewards |
| Testing / UAT | 12–14 | Load test, ERP failure scenarios, security review, performance audit |
| Training & Launch | 14–16 | Admin training, distributor training, parallel run with Magento, hypercare |
11.3 Highest-risk items (start earliest)
- ORAFOL BE connector — XL, spec unknown, blocks order flow
- Kathy's facility connector — L, spec entirely unknown
- Multi-warehouse inventory — L, blocks Kathy + BE inventory sync
- 7K SKU catalog import + search — L, performance unknown
- Tax engine decision — M, may need change order
11.4 Fastest ROI items (quick wins)
- Replace tenant ID hardcode with feature flag — S
- Implement
my_orders.blade.php+ reorder — S - 2FA on customer guard — S
- Quick-order SKU pad — S — high distributor delight
- Bulk UPS tracking import — S — immediate ops time savings
- Issuu embed — S
routes/orafol.php as a spec that the client has implicitly approved. Wiring the backend behind those scaffolds is the fastest visible-progress path. Don't refactor the views; build the services and controllers behind them.