Corporate Portals: CRM, ERP, LMS, Intranet, HR
A corporate portal is not a website. It's an internal system with hundreds of business rules, role-based access matrices, integration with authentication systems, and users who work in it eight hours a day. If the application is slow or inconvenient — productivity measurably drops.
Where Real Complexity Begins
Public sites can launch without detailed planning — iteratively fix by feedback. With corporate portal this doesn't work: cost of fixing architectural decisions after launch to 200 users is incomparable.
Three zones where poor decisions most often happen:
Access rights model. "Manager sees only their clients, department head — whole department, director — entire company, but financial data — only finance director and higher." This is not three roles — it's matrix of roles, permissions, organizational units, and record ownership. If implemented via if ($user->role === 'manager') scattered in controllers — code becomes unmaintainable in six months.
Right approach: Spatie Laravel Permission for basic role model + Policy classes for object-level permission (can('view', $deal) checks not just role, but ownership). For complex hierarchical structures — ABAC (Attribute-Based Access Control) instead of RBAC.
Performance on large data. CRM with 500,000 contacts, filtering by 10 fields, sorting by activity — task where naive implementation returns 15-second queries. Composite indexes, denormalized aggregates (last_activity_at on record itself instead of MAX on related table), Elasticsearch for full-text contact search.
Real-time updates. Multiple employees work with one document or task. Without WebSocket — constant setInterval polling every 5 seconds, extra load, update delay. Laravel Broadcasting + Pusher/Soketi or custom WebSocket server on Node.js — for notifications and real-time changes.
CRM Systems
Typical set: contacts, companies, deals, activities, sales funnel, reports. Technically simple. Complexity — in details.
Pipeline with custom stages. Every company wants their own funnel. Stages should be customizable without deploy. Table pipeline_stages with position, color, is_final, probability — and drag-and-drop for order change on UI (React DnD or dnd-kit).
Change history. Who and when changed deal status, reassigned, added note. Audit log via Observer or spatie/laravel-activitylog. On UI — timeline with activity type filtering.
Email integration. IMAP/SMTP to connect corporate mailbox, auto-bind incoming emails to contacts by email address. This only works reliably with proper bounce, spam, autoreply handling — need filtering.
ERP Systems
ERP is when CRM, warehouse, production, accounting, and HR combined into one system. Full ERP from scratch — rare task (usually integrate with existing), but modular systems for specific business — regular.
Key principle: financial operations must be immutable. Not UPDATE orders SET status = 'cancelled' — but create new record order_cancellations with link to original. This immutable ledger principle simplifies audit and reconciliation.
1С integration — almost always part of ERP project. Bidirectional sync: from 1С to portal (references, balances, prices) and from portal to 1С (orders, documents). RabbitMQ as message bus is more reliable than direct HTTP — if 1С unavailable, messages wait in queue.
LMS: Learning Platforms
Learning Management System — courses, modules, lessons, tests, certificates, user progress.
Video content — most loaded LMS part. Storing video on own server and serving via Nginx — bad idea: expensive, slow, no adaptive bitrate. Right way: upload to S3/Cloudflare R2, transcode via AWS Elemental MediaConvert or Mux, HLS playlist for adaptive streaming via Video.js or Plyr.
Watch progress — via periodic watch_position sends from frontend (every 10–30 seconds), storage in Redis with periodic PostgreSQL sync. Don't save every second to DB — kills performance.
SCORM compatibility — if integration with corporate training materials needed. Separate module, ready libraries exist (scorm-again).
Intranet and HR Portals
Corporate intranet: news, documents, org structure, HR processes (vacations, requests, KPI).
Org structure in database — hierarchical structure. Adjacency list (parent_id on each record) simple to implement, slow for recursive queries. Nested Sets or Closure Table faster for reading hierarchy, complex for changes. In PostgreSQL — recursive CTE (WITH RECURSIVE) with adjacency list — balance between simplicity and performance.
Document and request approval — workflow engine. Simple linear approvals (employee → manager → HR → accountant) can be done without special engine. Non-linear (parallel branches, conditional transitions, delegation) — consider ready solutions: Temporal.io for workflow orchestration or custom finite state machine based on state-machine pattern.
Tech Stack for Portals
| Layer | Tools |
|---|---|
| Backend | Laravel 10/11 + PostgreSQL |
| Frontend | React + TypeScript (Inertia.js or separate SPA) |
| Real-time | Laravel Echo + Soketi / Pusher |
| Search | Meilisearch (quick start) or Elasticsearch (volume) |
| Queues | Laravel Queue + Redis |
| Files | S3-compatible (MinIO self-hosted or AWS S3) |
| Monitoring | Sentry + Telescope (dev) |
Timeline Guidelines
| Portal Type | Timeline |
|---|---|
| CRM (basic) | 10–16 weeks |
| LMS (courses + video + tests) | 14–22 weeks |
| HR portal (vacations, KPI, org structure) | 12–20 weeks |
| Corporate ERP (modular) | 24–52 weeks |
Cost depends on number of roles, external integrations, and volume of business rules. Always calculated after detailed requirements analysis.







