// SYSTEM PANEL //
[ROOT]
/
home
/
csender
/
newsmsapp.csender.net
[ PARENT ]
EDIT :: MIGRATION_PLAN.md
# Laravel to Spring Boot + Go Microservices Migration Plan ## Executive Summary This is a **like-for-like migration plan** for a multi-tenant SaaS email/SMS campaign management system. The plan extracts messaging services into a shared Go microservice while migrating the dashboard to Spring Boot + Kotlin, using the **strangler pattern** with per-tenant rollout and instant rollback capabilities. --- ## 1. Current System Analysis ### 1.1 What the System Does This is a **multi-tenant SaaS platform** for email and SMS campaign management. Core capabilities: - **Email Campaigns**: Create, schedule, and send bulk emails with templates, attachments, tracking (opens/clicks), bounce detection - **SMS Campaigns**: Send bulk SMS via multiple providers (Twilio, Vonage/Nexmo, Plivo, Infobip, etc.) - **Template Management**: Visual email template builder, SMS template builder - **Contact Management**: Import contacts, group management, unsubscribe handling - **Multi-tenancy**: Per-tenant usage limits, billing, subscription plans - **Provider Management**: Configure multiple SMTP servers, SMS gateways per tenant - **Scheduling**: Cron-based scheduled campaigns for both email and SMS - **Tracking & Analytics**: Email open/click tracking, delivery status, bounce management - **API Access**: REST API for programmatic campaign management **Evidence:** - Routes: `routes/campaign.php` (155 lines), `routes/sms.php` (119 lines), `routes/email.php` (4020 bytes) - Controllers: `SmsController.php` (135,892 bytes - largest controller), `CampaignController.php` (57,967 bytes) - Models: `Campaign`, `CampaignEmail`, `Sms`, `SmsLog`, `EmailTracker`, `ScheduleEmail`, `ScheduleSms` - Commands: `SendSMS.php`, `SendEmails.php` (cron jobs) ### 1.2 Architecture Overview **Current Stack:** - **Framework**: Laravel 8.x (PHP 8.0+) - **Database**: MySQL (inferred from migrations) - **Queue**: Laravel Queue system (config/queue.php) - **Cron**: Laravel Scheduler (`app/Console/Kernel.php`) - **Email**: SwiftMailer with multi-SMTP support - **SMS**: Direct SDK integrations (Twilio, Vonage, Plivo, etc.) **Request Flow:** ``` User → Laravel Routes → Controllers → Models → Database ↓ Queue Jobs (SendEmailJob) ↓ Cron Commands (SendSMS, SendEmails) ↓ External APIs (SMTP, Twilio, Vonage, etc.) ``` **Key Components:** | Component | Location | Purpose | Lines/Size | |-----------|----------|---------|------------| | Campaign Controller | `app/Http/Controllers/CampaignController.php` | Email campaign CRUD, scheduling | 57,967 bytes | | SMS Controller | `app/Http/Controllers/SmsController.php` | SMS sending, provider config | 135,892 bytes | | Send Emails Command | `app/Console/Commands/SendEmails.php` | Cron job for scheduled emails | 324 lines | | Send SMS Command | `app/Console/Commands/SendSMS.php` | Cron job for scheduled SMS | 67 lines | | Email Tracker | `app/Models/EmailTracker.php` | Track opens/clicks | Model | | SMS Log | `app/Models/SmsLog.php` | SMS delivery logs | Model | | User Rate Limit | `app/Models/EmailSMSLimitRate.php` | Usage quota tracking | Model | **Data Model (Critical Tables):** Evidence from `database/migrations/`: - `users` - Multi-tenant users - `campaigns` - Email/SMS campaigns - `campaign_emails` - Email recipients per campaign - `sms_logs` - SMS delivery records - `email_trackers` - Email open/click tracking - `schedule_emails` - Scheduled email campaigns - `schedule_sms` - Scheduled SMS campaigns - `email_s_m_s_limit_rates` - Per-tenant usage quotas - `user_sent_records` - Historical send counts - `subscription_plans` - Tenant billing plans - `plan_purchaseds` - Active subscriptions - `email_services` - SMTP server configurations - `sms_services` - SMS provider configurations - `smtp_servers` - SMTP credentials (per tenant) - `sms_sender_ids` - SMS sender IDs (per tenant) - `bounced_emails` - Bounce tracking ### 1.3 Critical Flows #### Email Campaign Flow **Evidence:** `app/Console/Commands/SendEmails.php` (lines 62-241) ``` 1. Fetch pending scheduled emails (ScheduleEmail model) 2. For each campaign: a. Load SMTP config (EmailService model) b. Load sender identity (SenderEmailId model) c. Load template (TemplateBuilder model) d. Load recipients (CampaignEmail model) e. Check tenant quota (EmailSMSLimitRate model) f. For each recipient: - Create tracker UUID (EmailTracker model) - Send via SwiftMailer - Decrement quota - Verify email (bounce check) - Log send (UserSentRecord model) g. Update campaign log (CampaignLog model) ``` #### SMS Campaign Flow **Evidence:** `app/Console/Commands/SendSMS.php` (lines 41-65), `app/Http/Controllers/SmsController.php` ``` 1. Fetch pending scheduled SMS (ScheduleSms model) 2. For each campaign: a. Load SMS provider config (SmsService model) b. Load template (SmsBuilder model) c. Call SmsController->campaignSendSms() d. Provider-specific SDK call (Twilio/Vonage/Plivo/etc.) e. Log delivery (SmsLog model) f. Decrement quota (EmailSMSLimitRate model) g. Update status ``` #### Quota Management **Evidence:** `app/Models/EmailSMSLimitRate.php`, `SendEmails.php` lines 138-189, 289-309 ``` - Check: user_email_limit_check(domain) - Decrement: user_email_limit_decrement(domain) - Reconciliation: EmailSMSLimitRate table tracks email/sms counts - Reset: Handled by subscription renewal (PlanPurchased model) ``` --- ## 2. Target Architecture ### 2.1 Component Mapping | Legacy Component | New Component | Technology | Responsibility | |------------------|---------------|------------|----------------| | Laravel Dashboard | Spring Boot Dashboard | Kotlin + Spring Boot 3.x | Campaign management, UI, billing, user management | | SMS/Email Sending | Messaging Microservice | Go 1.21+ | Message delivery, provider abstraction, retry logic | | MySQL Database | PostgreSQL (recommended) | PostgreSQL 15+ | Shared data store (multi-tenant schema) | | Laravel Queue | RabbitMQ/Kafka | RabbitMQ 3.12+ | Message queue for async sends | | Laravel Scheduler | Kubernetes CronJobs | K8s CronJobs | Scheduled campaign execution | | SwiftMailer | Go SMTP Client | Go stdlib `net/smtp` | Email delivery | | Twilio/Vonage SDKs | Go HTTP Client | Go `net/http` | SMS provider abstraction | ### 2.2 Target Architecture Diagram ``` ┌─────────────────────────────────────────────────────────────┐ │ Spring Boot Dashboard │ │ (Kotlin + Spring Boot) │ │ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │ │ │ Campaign API │ │ Billing API │ │ User Mgmt │ │ │ └──────┬───────┘ └──────┬───────┘ └──────┬───────┘ │ │ │ │ │ │ └─────────┼──────────────────┼──────────────────┼──────────────┘ │ │ │ ▼ ▼ ▼ ┌─────────────────────────────────────────────┐ │ PostgreSQL (Multi-tenant) │ │ campaigns | users | quotas | templates │ └─────────────────────────────────────────────┘ │ ▲ │ Publish Send Request │ Update Status ▼ │ ┌─────────────────────────────────────────────┐ │ RabbitMQ / Kafka Queue │ └─────────────────────────────────────────────┘ │ │ Consume ▼ ┌─────────────────────────────────────────────────────────────┐ │ Messaging Microservice (Go) │ │ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │ │ │ Email Worker │ │ SMS Worker │ │ Retry Engine │ │ │ └──────┬───────┘ └──────┬───────┘ └──────────────┘ │ │ │ │ │ │ ▼ ▼ │ │ ┌──────────────┐ ┌──────────────┐ │ │ │ SMTP Client │ │ SMS Providers│ │ │ │ (Go stdlib) │ │ (Twilio/etc) │ │ │ └──────────────┘ └──────────────┘ │ └─────────────────────────────────────────────────────────────┘ │ │ ▼ ▼ External APIs (SMTP, Twilio, Vonage, Plivo, etc.) ``` ### 2.3 Multi-Tenancy Strategy **Shared Database with Tenant ID:** - All tables have `owner_id` (tenant identifier) - Row-level security (RLS) in PostgreSQL - Spring Boot: Hibernate filters for tenant isolation - Go: Middleware injects tenant context **Evidence:** Existing `owner_id` column in all major tables (users, campaigns, email_s_m_s_limit_rates, etc.) --- ## 3. Phased Migration Plan ### Phase 0: Foundation (Weeks 1-2) **Goal:** Set up infrastructure and compatibility layer #### Tasks: - [ ] Provision PostgreSQL cluster (multi-tenant schema) - [ ] Set up RabbitMQ cluster (3 nodes, HA) - [ ] Create Kubernetes namespace (`messaging-platform`) - [ ] Deploy monitoring stack (Prometheus, Grafana, Jaeger) - [ ] Set up CI/CD pipelines (GitHub Actions / GitLab CI) #### Acceptance Criteria: - PostgreSQL accessible from both Laravel and new services - RabbitMQ exchanges/queues created (`email.send`, `sms.send`, `status.update`) - Monitoring dashboards operational - CI/CD can build and deploy to staging #### Rollback: - N/A (infrastructure only) --- ### Phase 1: Extract Messaging Microservice (Weeks 3-6) **Goal:** Build Go messaging service in parallel, no production traffic yet #### Tasks: **1.1 Go Service Skeleton** - [ ] Initialize Go project (`go mod init messaging-service`) - [ ] Implement provider abstraction layer: ```go type MessageProvider interface { SendEmail(ctx context.Context, req EmailRequest) (*SendResult, error) SendSMS(ctx context.Context, req SMSRequest) (*SendResult, error) } ``` - [ ] Implement providers: - SMTP client (Go stdlib) - Twilio SDK - Vonage SDK - Plivo SDK - Infobip SDK **Evidence:** Current providers in `composer.json`: `twilio/sdk`, `vonage/client`, `plivo/plivo-php` **1.2 Queue Consumers** - [ ] RabbitMQ consumer for `email.send` queue - [ ] RabbitMQ consumer for `sms.send` queue - [ ] Message schema validation (Protobuf or JSON Schema) **1.3 Idempotency & Deduplication** - [ ] Redis-based deduplication cache (TTL: 24h) - [ ] Idempotency key: `SHA256(tenant_id + campaign_id + recipient + timestamp_hour)` - [ ] Check cache before sending, store result after send **1.4 Retry Logic** - [ ] Exponential backoff: 1s, 5s, 30s, 5m, 30m - [ ] Dead letter queue after 5 retries - [ ] Persist retry state in PostgreSQL (`message_retries` table) **1.5 Status Tracking** - [ ] Publish delivery status to `status.update` queue - [ ] Laravel consumer updates `email_trackers` / `sms_logs` **1.6 Quota Enforcement** - [ ] Read quota from PostgreSQL (`email_s_m_s_limit_rates`) - [ ] Atomic decrement with optimistic locking - [ ] Reject send if quota exceeded, publish failure event #### Acceptance Criteria: - Go service can send test email via SMTP - Go service can send test SMS via Twilio - Idempotency prevents duplicate sends (test with same message twice) - Retry logic tested with failing provider - Status updates flow back to Laravel #### Monitoring Signals: - Message processing latency (p50, p95, p99) - Provider success rate (per provider) - Retry queue depth - Deduplication cache hit rate #### Rollback: - Stop Go service, no production impact (Laravel still handles all sends) --- ### Phase 2: Compatibility Layer in Laravel (Weeks 7-8) **Goal:** Add feature flag to route sends through Go service #### Tasks: **2.1 Feature Flag System** - [ ] Add `messaging_service_enabled` column to `users` table - [ ] Admin UI to enable/disable per tenant - [ ] Default: `false` (all tenants use legacy Laravel) **2.2 Dual-Write Adapter** - [ ] Create `MessagingServiceAdapter` class in Laravel: ```php class MessagingServiceAdapter { public function sendEmail(Campaign $campaign, EmailContact $contact) { if ($this->isEnabled($campaign->owner_id)) { // Publish to RabbitMQ $this->publishToQueue('email.send', $payload); } else { // Legacy SwiftMailer $this->sendViaSwiftMailer($campaign, $contact); } } } ``` - [ ] Inject adapter into `SendEmails` command - [ ] Inject adapter into `CampaignController` **2.3 Status Sync Consumer** - [ ] Laravel consumer for `status.update` queue - [ ] Update `email_trackers` / `sms_logs` tables - [ ] Ensure quota decrements match Go service #### Acceptance Criteria: - Feature flag toggles between Laravel and Go service - Test tenant with flag enabled sends via Go service - Status updates flow back correctly - Quota decrements are consistent #### Rollback: - Set `messaging_service_enabled = false` for all tenants - Traffic reverts to Laravel immediately --- ### Phase 3: Gradual Tenant Migration (Weeks 9-12) **Goal:** Migrate tenants to Go service in waves #### Migration Waves: **Wave 1: Internal/Test Tenants (Week 9)** - [ ] Enable flag for 3-5 internal test accounts - [ ] Monitor for 1 week - [ ] Validate: - Send success rate matches legacy - Quota tracking accurate - No duplicate sends - Latency acceptable **Wave 2: Low-Volume Tenants (Week 10)** - [ ] Enable flag for tenants with <1000 sends/day - [ ] Monitor for 1 week - [ ] Compare metrics: success rate, latency, errors **Wave 3: Medium-Volume Tenants (Week 11)** - [ ] Enable flag for tenants with 1000-10,000 sends/day - [ ] Monitor for 1 week **Wave 4: High-Volume Tenants (Week 12)** - [ ] Enable flag for tenants with >10,000 sends/day - [ ] Monitor for 1 week - [ ] Ensure Go service scales (add replicas if needed) #### Per-Tenant Rollback: - [ ] Disable feature flag for specific tenant - [ ] Traffic reverts to Laravel within 1 minute - [ ] No data loss (dual-write ensures consistency) #### Acceptance Criteria: - 100% of tenants migrated to Go service - No increase in error rate - Latency p95 <500ms - Zero duplicate sends detected #### Monitoring Signals: - Per-tenant send success rate - Per-tenant quota accuracy (reconciliation check) - Provider-level error rates - Queue lag (RabbitMQ) --- ### Phase 4: Spring Boot Dashboard (Weeks 13-18) **Goal:** Migrate Laravel dashboard to Spring Boot + Kotlin #### Tasks: **4.1 Spring Boot Skeleton** - [ ] Initialize Spring Boot 3.x project (Kotlin) - [ ] Configure multi-tenancy (Hibernate filters) - [ ] Set up PostgreSQL connection - [ ] Implement authentication (JWT, same as Laravel) **4.2 API Parity** - [ ] Campaign CRUD endpoints - [ ] Template management endpoints - [ ] Contact management endpoints - [ ] Billing/subscription endpoints - [ ] User management endpoints **Evidence:** Existing routes in `routes/campaign.php`, `routes/email.php`, `routes/sms.php` **4.3 Frontend Migration** - [ ] Option A: Keep Laravel Blade views, proxy to Spring Boot API - [ ] Option B: Migrate to React/Vue SPA (out of scope for like-for-like) - [ ] **Recommended:** Option A for like-for-like migration **4.4 Dual-Run Period** - [ ] Deploy Spring Boot alongside Laravel - [ ] Route 10% of dashboard traffic to Spring Boot (load balancer) - [ ] Monitor for errors, latency, data consistency **4.5 Gradual Traffic Shift** - [ ] Week 14: 25% traffic to Spring Boot - [ ] Week 15: 50% traffic to Spring Boot - [ ] Week 16: 75% traffic to Spring Boot - [ ] Week 17: 100% traffic to Spring Boot #### Acceptance Criteria: - All dashboard features work in Spring Boot - API response times match Laravel (±10%) - No data inconsistencies - Authentication works (JWT tokens valid) #### Rollback: - Route 100% traffic back to Laravel (load balancer config) - No data loss (shared PostgreSQL) --- ### Phase 5: Decommission Laravel (Weeks 19-20) **Goal:** Remove Laravel codebase #### Tasks: - [ ] Verify 100% traffic on Spring Boot + Go - [ ] Run final reconciliation checks (quota, send counts) - [ ] Archive Laravel codebase - [ ] Remove Laravel deployments - [ ] Update DNS/load balancer (remove Laravel endpoints) #### Acceptance Criteria: - Zero traffic to Laravel for 1 week - All monitoring green - No customer complaints --- ## 4. Migration Safety Mechanisms ### 4.1 Per-Tenant Feature Flags **Implementation:** - Database column: `users.messaging_service_enabled` (boolean, default false) - Admin UI: Toggle per tenant - Middleware: Check flag on every send request **Rollback:** ```sql -- Instant rollback for specific tenant UPDATE users SET messaging_service_enabled = false WHERE id = <tenant_id>; -- Instant rollback for all tenants UPDATE users SET messaging_service_enabled = false; ``` ### 4.2 Dual-Write Pattern **Email Send Flow:** ``` 1. Check feature flag 2. If enabled: a. Publish to RabbitMQ (Go service) b. Log to PostgreSQL (audit trail) 3. If disabled: a. Send via Laravel (legacy) b. Log to PostgreSQL ``` **Consistency Guarantee:** - Both paths write to same PostgreSQL tables - Idempotency key prevents duplicates - Status updates reconcile via queue ### 4.3 Idempotency Strategy **Deduplication Key:** ``` key = SHA256(tenant_id + campaign_id + recipient + timestamp_hour) ``` **Implementation:** - Redis cache with 24h TTL - Check before send: `GET idempotency:{key}` - If exists: return cached result (skip send) - If not exists: send, then `SET idempotency:{key} {result} EX 86400` **Evidence:** Current system lacks idempotency (risk of duplicates on retry) ### 4.4 Quota Reconciliation **Hourly Reconciliation Job:** ```sql -- Compare quota decrements between Laravel and Go service SELECT u.id AS tenant_id, u.email AS tenant_email, l.email_count AS laravel_count, g.email_count AS go_count, ABS(l.email_count - g.email_count) AS diff FROM users u LEFT JOIN email_s_m_s_limit_rates l ON u.id = l.owner_id LEFT JOIN go_service_quota_log g ON u.id = g.tenant_id WHERE ABS(l.email_count - g.email_count) > 10; ``` **Alert:** If diff >10, trigger manual review ### 4.5 Monitoring & Alerts **Critical Metrics:** - Send success rate (target: >99%) - Latency p95 (target: <500ms) - Queue lag (target: <100 messages) - Duplicate send rate (target: 0%) - Quota accuracy (target: 100%) **Alerts:** - PagerDuty for success rate <98% - Slack for queue lag >1000 - Email for quota discrepancies --- ## 5. Compatibility Layer Design ### 5.1 Laravel → Go Service Bridge **RabbitMQ Message Schema (JSON):** ```json { "message_id": "uuid-v4", "tenant_id": 123, "campaign_id": 456, "type": "email", "recipient": { "email": "user@example.com", "name": "John Doe" }, "content": { "subject": "Campaign Subject", "body_html": "<html>...</html>", "body_text": "Plain text...", "from_email": "sender@example.com", "from_name": "Sender Name", "reply_to": "reply@example.com", "attachments": [ {"filename": "doc.pdf", "url": "https://..."} ] }, "provider_config": { "smtp_host": "smtp.example.com", "smtp_port": 587, "smtp_username": "user", "smtp_password": "encrypted", "smtp_encryption": "tls" }, "tracking": { "tracker_uuid": "uuid-v4", "open_tracking": true, "click_tracking": true }, "idempotency_key": "sha256-hash", "created_at": "2026-02-07T01:00:00Z" } ``` ### 5.2 Go Service → Laravel Status Updates **RabbitMQ Status Message (JSON):** ```json { "message_id": "uuid-v4", "tenant_id": 123, "campaign_id": 456, "status": "delivered", "provider_response": { "provider": "twilio", "message_sid": "SM123...", "status_code": 200, "error_message": null }, "delivered_at": "2026-02-07T01:00:05Z", "retry_count": 0 } ``` **Laravel Consumer:** ```php // app/Console/Commands/ConsumeStatusUpdates.php public function handle() { $this->rabbitMQ->consume('status.update', function($message) { $data = json_decode($message->body, true); if ($data['type'] === 'email') { EmailTracker::where('tracker', $data['tracker_uuid']) ->update(['status' => $data['status']]); } else { SmsLog::where('message_id', $data['message_id']) ->update(['status' => $data['status']]); } // Decrement quota if not already done $this->decrementQuota($data['tenant_id'], $data['type']); }); } ``` ### 5.3 Webhook Migration **Current:** Laravel handles provider webhooks (Twilio delivery status, etc.) **Migration:** - Go service exposes webhook endpoints: `/webhooks/twilio`, `/webhooks/vonage` - Update provider webhook URLs to point to Go service - Go service publishes status to `status.update` queue - Laravel consumer updates database **Rollback:** - Revert webhook URLs to Laravel endpoints --- ## 6. Testing Strategy ### 6.1 Unit Tests - Go service: 80% coverage (providers, retry logic, idempotency) - Spring Boot: 80% coverage (API endpoints, multi-tenancy) ### 6.2 Integration Tests - End-to-end: Laravel → RabbitMQ → Go → Provider → Status Update → Laravel - Test all providers (Twilio, Vonage, Plivo, SMTP) - Test quota enforcement - Test idempotency (send same message twice, verify only one send) ### 6.3 Load Tests - Simulate 10,000 sends/sec - Verify Go service scales horizontally - Verify queue doesn't lag ### 6.4 Chaos Testing - Kill Go service pod (verify retry logic) - Kill RabbitMQ node (verify HA) - Simulate provider outage (verify dead letter queue) --- ## 7. Evidence Appendix ### 7.1 Key Composer Dependencies **Evidence:** `composer.json` lines 10-50 | Dependency | Version | Purpose | |------------|---------|---------| | `laravel/framework` | ^8.14.0 | Core framework | | `twilio/sdk` | ^6.16.0 | Twilio SMS | | `vonage/client` | 2.4.0 | Vonage SMS | | `plivo/plivo-php` | ^4.17 | Plivo SMS | | `guzzlehttp/guzzle` | ^7.2 | HTTP client | | `maatwebsite/excel` | ^3.1 | Contact import | | `jdavidbakr/mail-tracker` | ^4.0 | Email tracking | | `stripe/stripe-php` | ^7.67 | Billing | | `razorpay/razorpay` | ^2.8 | Billing | ### 7.2 Largest Files (Hotspots) | File | Size | Purpose | |------|------|---------| | `app/Http/Controllers/SmsController.php` | 135,892 bytes | SMS sending logic | | `app/Http/Controllers/CampaignController.php` | 57,967 bytes | Campaign management | | `app/Helpers.php` | 105,612 bytes | Helper functions | | `routes/web.php` | 442,798 bytes | Main routes (includes embedded template HTML) | ### 7.3 Main Routes (Messaging) **Evidence:** `routes/campaign.php`, `routes/sms.php` **Email:** - `GET /campaign/send-email/campaign-{id}/template-{id}` - Send email campaign - `POST /campaign/schedule-email/.../store` - Schedule email - `GET /campaign/schedule-emails` - List scheduled emails **SMS:** - `GET /campaign/send-sms/campaign-{id}/{template}/{gateway}` - Send SMS campaign - `POST /campaign/schedule-sms/.../store` - Schedule SMS - `GET /campaign/schedule-sms` - List scheduled SMS ### 7.4 Provider Implementations **Evidence:** `app/Http/Controllers/SmsController.php` (135KB file) **Confirmed Providers:** - Twilio (SDK: `twilio/sdk`) - Vonage/Nexmo (SDK: `vonage/client`) - Plivo (SDK: `plivo/plivo-php`) - Infobip (custom HTTP client) - Custom SMTP (SwiftMailer) **Provider Config Storage:** - Table: `sms_services` (migration: `2022_04_28_131810_create_sms_services_table.php`) - Table: `email_services` (migration: `2021_03_08_102104_create_email_services_table.php`) ### 7.5 Secrets/Credentials Storage **Evidence:** Migrations and models **Current Storage:** - SMTP credentials: `smtp_servers` table (columns: `host`, `port`, `username`, `password`, `encryption`) - SMS credentials: `sms_services` table (columns: `api_key`, `api_secret`, `sender_id`) - Encryption: Laravel's `encrypt()` helper (AES-256-CBC) **Migration Strategy:** - Move to Kubernetes Secrets or HashiCorp Vault - Go service reads from secrets manager - Spring Boot reads from secrets manager - Rotate credentials post-migration ### 7.6 Usage/Quota Tracking **Evidence:** `app/Models/EmailSMSLimitRate.php`, `SendEmails.php` lines 289-309 **Tables:** - `email_s_m_s_limit_rates` (columns: `owner_id`, `email`, `sms`) - `user_sent_records` (columns: `owner_id`, `type`, `created_at`) - `subscription_plans` (columns: `email_limit`, `sms_limit`) **Quota Logic:** 1. Check: `EmailSMSLimitRate::where('owner_id', $id)->first()->email` 2. Decrement: `EmailSMSLimitRate::where('owner_id', $id)->decrement('email', 1)` 3. Reset: On subscription renewal (cron job) **Parity Requirement:** - Go service must decrement same table atomically - Reconciliation job to detect discrepancies ### 7.7 Webhook/Callback Handling **Evidence:** `routes/api.php` (inferred from provider docs) **Current Webhooks:** - Twilio: `/api/webhooks/twilio/status` (delivery status) - Vonage: `/api/webhooks/vonage/dlr` (delivery receipt) - Email tracking: `/tracker/{uuid}/open`, `/tracker/{uuid}/click` **Migration:** - Go service exposes same endpoints - Update provider webhook URLs - Publish status to `status.update` queue - Laravel consumer updates database --- ## 8. Risk Mitigation | Risk | Likelihood | Impact | Mitigation | |------|------------|--------|------------| | Duplicate sends during migration | Medium | High | Idempotency key + Redis cache | | Quota discrepancies | Medium | High | Hourly reconciliation job + alerts | | Provider API changes | Low | Medium | Version pin SDKs, test before upgrade | | Data loss during cutover | Low | Critical | Dual-write + shared PostgreSQL | | Performance regression | Medium | High | Load testing + gradual rollout | | Tenant-specific bugs | High | Medium | Per-tenant feature flags + instant rollback | --- ## 9. Success Criteria - [ ] 100% of tenants migrated to Go messaging service - [ ] 100% of dashboard traffic on Spring Boot - [ ] Zero data loss - [ ] Zero duplicate sends - [ ] Quota accuracy: 100% (reconciliation checks pass) - [ ] Send success rate: >99% (matches legacy) - [ ] Latency p95: <500ms - [ ] Zero customer complaints - [ ] Laravel codebase decommissioned --- ## 10. Timeline Summary | Phase | Duration | Deliverable | |-------|----------|-------------| | Phase 0: Foundation | 2 weeks | Infrastructure ready | | Phase 1: Go Service | 4 weeks | Messaging service operational | | Phase 2: Compatibility Layer | 2 weeks | Feature flags + dual-write | | Phase 3: Tenant Migration | 4 weeks | 100% tenants on Go service | | Phase 4: Spring Boot Dashboard | 6 weeks | Dashboard migrated | | Phase 5: Decommission | 2 weeks | Laravel removed | | **Total** | **20 weeks** | **Full migration complete** | --- ## 11. Rollback Plan (Per Phase) | Phase | Rollback Action | Recovery Time | Data Loss Risk | |-------|-----------------|---------------|----------------| | Phase 1 | Stop Go service | Immediate | None (no prod traffic) | | Phase 2 | Disable feature flags | <1 minute | None (dual-write) | | Phase 3 | Disable per-tenant flags | <1 minute | None (dual-write) | | Phase 4 | Route traffic to Laravel | <5 minutes | None (shared DB) | | Phase 5 | Redeploy Laravel | <30 minutes | None (archived code) | --- **END OF MIGRATION PLAN** **Generated:** 2026-02-07 **Author:** Senior Software Architect **Status:** DRAFT - Requires stakeholder review
SAVE
CANCEL