Idempotent provisioning, service soft-delete, Plans page redesign, doc updates

Part A: Fix duplicate Service creation on provisioning retry
- All 4 provisioning services use Service::firstOrCreate() keyed on
  subscription_id+service_type to prevent duplicates on queue retries
- HandleSubscriptionCreated sends notification before provisioning,
  no longer re-throws on failure
- RetryProvisioningCommand simplified to reuse existing Service records

Part B: Plans/Pricing page complete redesign
- Service type tabs (VPS, Dedicated, Web Hosting, MySQL)
- Billing cycle segmented toggle (monthly/quarterly/semi-annual/annual)
- Feature icons per service type, Popular/Best Value badges
- Stock indicators, effective monthly price calculations

Part C: Admin service soft-delete/archive
- Service model uses SoftDeletes trait
- Admin can archive and restore services
- Show archived toggle on services list
- Migration adds deleted_at column

Docs: Updated TASKS.md, CLAUDE.md, PROJECT_DEVELOPMENT.md, MEMORY.md
- Phase 3 marked complete, test counts updated (252 passing)
- SupportPal references replaced with standalone ticket system
- Frontend design skill background rule added
- Closed GitHub issues #3, #6, #7, #8, #9

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Claude Dev
2026-02-10 06:30:57 -05:00
parent bf4f5f97c0
commit 45d25d61ba
101 changed files with 13225 additions and 1888 deletions

View File

@@ -12,7 +12,7 @@ Replace WHMCS with a custom Laravel 12 application for managing EZSCALE Hosting'
- **Dedicated Servers:** SynergyCP
- **Web Hosting:** Enhance (https://enhance.com/)
- **Container Management:** Portainer (for BFACP deployment)
- **Support System:** SupportPal (ticketing)
- **Support System:** Standalone ticket system (built-in, replaced SupportPal)
- **Network:** Juniper switches with VLANs (dedicated customers, corporate, hypervisors)
- **Bandwidth Monitoring:** ElastiFlow (NetFlow/sFlow collector)
@@ -55,9 +55,9 @@ Replace WHMCS with a custom Laravel 12 application for managing EZSCALE Hosting'
│ │ │ │ │ │ Enhance │ │ │ │
│ └──────────┘ └──────────┘ └──────────────┘ └───────────────────┘ │
│ ┌──────────┐ ┌──────────┐ ┌──────────────┐ ┌───────────────────┐ │
│ │SupportPal│ │Analytics │ │ Customer │ │ Admin Tools │ │
│ │Integration│ │Dashboard │ │ API │ │ Full Control │ │
│ │SSO+Tickets│ │MRR/Churn │ │ │ │ │ │
│ │ Tickets │ │Analytics │ │ Customer │ │ Admin Tools │ │
│ │ System │ │Dashboard │ │ API │ │ Full Control │ │
│ │Standalone│ │MRR/Churn │ │ │ │ │ │
│ └──────────┘ └──────────┘ └──────────────┘ └───────────────────┘ │
├─────────────────────────────────────────────────────────────────────┤
│ MySQL 8.x (Multi-region) │ Redis (Queue/Cache/Session) │
@@ -65,8 +65,8 @@ Replace WHMCS with a custom Laravel 12 application for managing EZSCALE Hosting'
│ │
┌────┴────────┬──────────┬───────────┬───┴────┬─────────────┐
│ │ │ │ │ │
VirtFusion Pterodactyl SynergyCP Enhance SupportPal ElastiFlow
API API API API API API
VirtFusion Pterodactyl SynergyCP Enhance ElastiFlow
API API API API API
```
## 4. Key Design Decisions
@@ -82,7 +82,7 @@ VirtFusion Pterodactyl SynergyCP Enhance SupportPal ElastiFlow
- **Billing Architecture:** `BillingServiceInterface` abstracts Stripe and PayPal for gateway-agnostic code
### Frontend & Auth (DECIDED)
- **Stack:** Vue 3 + Inertia.js + Tailwind CSS (Laravel 12 Vue starter kit)
- **Stack:** Vue 3 + Inertia.js v2 + TypeScript + Vuetify 3 (Vuexy design system)
- **UI Theme:** **Vuexy** VueJS + Laravel Admin Dashboard Template
- Purchase: https://themeforest.net/item/vuexy-vuejs-html-laravel-admin-dashboard-template/23328599
- Demo: https://pixinvent.com/vuexy-vuejs-laravel-admin-template/
@@ -123,12 +123,13 @@ All service provisioning is **fully automated** via API on successful payment:
- **No Add-ons:** Automatic overage billing only (no one-time bandwidth add-ons)
### Support Integration (DECIDED)
- **System:** SupportPal (external ticketing system)
- **Integration Level:** Full integration
- SSO for seamless access
- View recent tickets in billing dashboard
- Create tickets from billing panel via SupportPal API
- Full ticket history accessible to customers
- **System:** Standalone ticket system (built-in, no external dependencies)
- **Features:**
- Full ticket CRUD with replies for customers and admins
- Email integration (IMAP polling via webklex/php-imap)
- Ticket references: [EZSCALE-{id}] format with email threading
- Departments, priorities, statuses
- 42 Pest tests for ticket system
- **Discord:** Admin notifications via webhook (new orders, failures, cancellations, high revenue)
### Customer Features (DECIDED)
@@ -295,20 +296,21 @@ bandwidth_usage
├── timestamps
```
### Support (SupportPal Integration)
### Support (Standalone Ticket System)
```
support_tickets (mirrored from SupportPal via webhooks)
support_tickets
├── id, user_id
├── supportpal_ticket_id
├── subject, status (open, closed, pending)
├── reference (e.g., EZSCALE-001)
├── subject, status (open, closed, pending, in_progress)
├── priority (low, medium, high, urgent)
├── department
├── last_reply_at
├── timestamps
announcements
├── id, title, content (HTML)
├── type (maintenance, feature, outage)
├── published_at, expires_at
ticket_replies
├── id, ticket_id, user_id
├── body (text)
├── is_staff_reply (boolean)
├── timestamps
```
@@ -364,17 +366,13 @@ announcements
**Service:** `App\Services\Monitoring\BandwidthService`
### 6.6 SupportPal API (Ticket System)
**Endpoints needed:**
- `GET /api/ticket/{id}` - Get ticket details
- `GET /api/ticket/user/{user_id}` - Get user's tickets
- `POST /api/ticket` - Create new ticket
- `POST /api/ticket/{id}/reply` - Reply to ticket
- `GET /api/ticket/{id}/replies` - Get ticket thread
**SSO Implementation:** SupportPal supports SAML or custom SSO - use Laravel Passport tokens
**Service:** `App\Services\Support\SupportPalService`
### 6.6 Standalone Ticket System (Built-in)
**No external integration needed.** Tickets are managed natively:
- Customer and Admin controllers with full CRUD
- Email integration via IMAP polling (webklex/php-imap)
- Email threading with Message-ID, In-Reply-To, References headers
- Ticket reference format: [EZSCALE-{id}]
- Scheduled: `tickets:process-emails` runs every 2 minutes
### 6.7 Email Notifications (Mailgun/SendGrid)
**Laravel Notifications for:**
@@ -494,12 +492,12 @@ announcements
- Automatic overage billing
- Admin bandwidth reports
### Phase 7: SupportPal Integration
- SSO implementation (Laravel Passport + SupportPal)
- Ticket viewing in customer dashboard
- Ticket creation via SupportPal API
- Webhook handlers for ticket updates
- Discord notifications for new tickets
### Phase 7: Support Ticket System ✓
- Standalone ticket system with TicketReply model (no external dependencies)
- Customer and admin Vue pages (5 pages total)
- Email integration via IMAP polling (webklex/php-imap)
- Email threading with ticket references [EZSCALE-{id}]
- 42 Pest tests
### Phase 8: Marketing Frontend (ezscale.cloud)
- Product catalog pages (VPS, Dedicated, Hosting, Game Servers)
@@ -561,7 +559,7 @@ announcements
- [x] Frontend stack: Vue 3 + Inertia.js
- [x] Infrastructure: VirtFusion, Pterodactyl, SynergyCP, Enhance
- [x] Bandwidth monitoring: ElastiFlow (NetFlow/sFlow)
- [x] Support system: SupportPal with full integration
- [x] Support system: Standalone ticket system (built-in)
- [x] Domain structure: ezscale.cloud / account / admin
- [x] Hosting: Own infrastructure with full DB redundancy
- [x] CI/CD: GitHub Actions with staging environment
@@ -578,7 +576,6 @@ announcements
- [ ] Tax calculation approach: TaxJar/Avalara integration vs manual tax rates?
- [ ] Email service final choice: Mailgun or SendGrid?
- [ ] Admin panel subdomain: admin.ezscale.cloud or something less obvious for security?
- [ ] Dedicated server semi-automation: How to handle limited hardware inventory (waitlist, manual approval)?
- [ ] NetFlow/sFlow deployment: Timeline for switching Juniper to flow exports?
- [x] ~~Customer portal theme/branding~~ **DECIDED: Vuexy VueJS + Laravel Admin Dashboard Template**
@@ -586,9 +583,9 @@ announcements
| Layer | Technology |
|-------|------------|
| **Framework** | Laravel 12 (PHP 8.2+) |
| **Frontend** | Vue 3 + Inertia.js + Tailwind CSS |
| **UI Theme** | Vuexy VueJS + Laravel Admin Dashboard |
| **Framework** | Laravel 12 (PHP 8.3) |
| **Frontend** | Vue 3 + Inertia.js v2 + TypeScript + Vuetify 3 |
| **UI Theme** | Vuexy design system (SCSS overrides + Vuetify components) |
| **Database** | MySQL 8.x (multi-region replication) |
| **Cache/Queue** | Redis |
| **Payments** | Laravel Cashier Stripe v16 + srmklive/laravel-paypal |
@@ -600,5 +597,5 @@ announcements
| **CI/CD** | GitHub Actions |
| **Monitoring** | ElastiFlow (bandwidth), Laravel Telescope (debugging) |
| **Provisioning APIs** | VirtFusion, Pterodactyl, SynergyCP, Enhance |
| **Support** | SupportPal (external integration) |
| **Support** | Standalone ticket system (built-in) |
| **Notifications** | Laravel Notifications + Discord webhooks |