Files
website/CLAUDE.md
Claude Dev 45d25d61ba 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>
2026-02-10 06:30:57 -05:00

16 KiB

CLAUDE.md - EZSCALE Site

Project

EZSCALE Site — Laravel 12 application replacing WHMCS for VPS/Dedicated Server hosting management (billing, subscriptions, provisioning, customer management, SSO).

Phase Tracking (MANDATORY)

All work MUST be tracked against GitHub issues and TASKS.md:

  1. Before starting any phase work: Check the relevant GitHub issue (see gh issue list) and TASKS.md for current status.
  2. While working: Update the GitHub issue with progress comments as significant milestones are completed (e.g., gh issue comment <number> --body "Completed X").
  3. After completing work: Update TASKS.md to check off completed items and close/update the corresponding GitHub issue.
  4. New tasks discovered during work: Create sub-issues or add items to TASKS.md immediately.
  5. Commit messages: Reference the GitHub issue number (e.g., Fix checkout validation (#3)).

GitHub issues: https://github.com/EZSCALE/accounting/issues

Documentation Updates (MANDATORY)

When a phase is completed or a significant task within a phase is finished:

  1. Update TASKS.md — Check off completed items, add new items discovered during work
  2. Update GitHub issues — Add progress comments (gh issue comment <number> --body "...") and close completed issues
  3. Update CLAUDE.md — Reflect any new tech stack changes, directory structure changes, or convention updates
  4. Update memory files — Record key patterns, gotchas, and environment details learned during the work
  5. Update PROJECT_DEVELOPMENT.md — If architectural decisions changed or new integrations were added

Visual Verification (MANDATORY)

After every successful npm run build:

  1. Take headless Chrome screenshots of affected pages
  2. Compare layout and design against the Vuexy demo at: https://demos.pixinvent.com/vuexy-vuejs-laravel-admin-template/demo-6/
  3. Fix any visual discrepancies before considering the task complete
  4. Key demo pages for reference:
    • Login: .../demo-6/pages/authentication/login-v2
    • Register: .../demo-6/pages/authentication/register-v2
    • Forgot Password: .../demo-6/pages/authentication/forgot-password-v2
    • Dashboard: .../demo-6/dashboards/analytics
    • Account Settings: .../demo-6/pages/account-settings/account
    • Pricing: .../demo-6/pages/pricing

Laravel App Location

The Laravel application is in website/. All artisan, composer, and npm commands run from there.

website/
├── app/
│   ├── Models/              # 14 Eloquent models (Service uses SoftDeletes)
│   ├── Http/Controllers/    # Account/ and Admin/ controllers
│   ├── Services/Billing/    # BillingServiceInterface, Stripe, PayPal, Dunning
│   ├── Events/              # PaymentSucceeded/Failed, SubscriptionCreated/Cancelled
│   ├── Listeners/           # HandlePaymentSucceeded/Failed
│   ├── Console/Commands/      # RetryProvisioningCommand, SyncStripePrices
│   └── Providers/           # AppServiceProvider, FortifyServiceProvider
├── bootstrap/app.php        # Middleware, exceptions, routing (Laravel 12 style)
├── config/                  # App, auth, fortify, passport, cashier, paypal, permission
├── database/
│   ├── migrations/          # 44 migrations
│   ├── factories/           # 8 factories
│   └── seeders/             # Roles, plans, admin user
├── resources/
│   ├── ts/                    # TypeScript source (migrated from js/)
│   │   ├── app.ts             # Entry point with Vuetify + Pinia
│   │   ├── bootstrap.ts
│   │   ├── types/             # TypeScript interfaces
│   │   ├── utils/             # Resolvers, formatters
│   │   ├── navigation/        # account.ts, admin.ts, marketing.ts
│   │   ├── plugins/vuetify/   # theme.ts, defaults.ts, icons.ts, index.ts
│   │   ├── @layouts/          # Layout SCSS stubs for Vuexy compatibility
│   │   ├── Layouts/           # AccountLayout, AdminLayout, AuthLayout, MarketingLayout
│   │   ├── Components/        # FlashMessages, StatCard, StatusChip, ThemeSwitcher, app-form-elements/
│   │   └── Pages/             # Auth/ (7), Profile/ (2), Plans/ (1), Checkout/ (1), Subscriptions/ (2), Billing/ (3), Services/ (2), Tickets/ (3), Admin/ (25+), Marketing/ (13), Dashboard
│   ├── styles/                # SCSS with Vuexy @core overrides
│   │   ├── @core/             # Copied from Vuexy: base + template SCSS overrides
│   │   ├── variables/         # _vuetify.scss, _template.scss
│   │   └── styles.scss        # Main entry — imports @core SCSS chain
│   ├── images/
│   └── views/app.blade.php    # Inertia root template
├── routes/                  # web.php, account.php, admin.php, marketing.php, webhooks.php, api.php
├── tests/                   # 252 Pest tests passing (1310 assertions)
├── composer.json
├── package.json
└── vite.config.js

Tech Stack

  • Framework: Laravel 12 (PHP 8.3), Laravel 12 slim structure (no Kernel files)
  • Frontend: Vue 3 + Inertia.js v2 + TypeScript (REQUIRED) + Vuetify 3 (Vuexy design system) + Vite 7
  • UI Theme: Vuexy Vue + Laravel Admin Dashboard — SCSS overrides from @core integrated, AppTextField/AppSelect/AppTextarea wrapper components, purple primary (#7367F0)
  • Testing: Pest 4 + PHPUnit 12 (252 tests, 1310 assertions)
  • Formatting: Laravel Pint
  • Payments: Laravel Cashier (Stripe) + srmklive/paypal (PayPal)
  • Database: MySQL 8.x, Redis for cache/queue/sessions
  • Auth: Laravel Fortify (login, register, 2FA, password reset, email verify) + Passport (OAuth2/SSO)
  • Roles: spatie/laravel-permission (admin, customer)
  • Queue: Laravel Horizon for queue management

Commands

cd website
composer run dev               # Start all dev servers (artisan serve + queue + pail + vite)
php artisan serve              # Laravel dev server only
php artisan test --compact     # Run Pest tests
php artisan migrate            # Run migrations
npm run dev                    # Vite dev server only
npm run build                  # Production build
vendor/bin/pint --dirty --format agent  # Format changed files

TypeScript Requirement (MANDATORY)

All frontend code MUST use TypeScript. This applies to all Vue components, composables, utilities, and type definitions.

Rules

  • All .vue files must use <script setup lang="ts"> (never plain <script setup>)
  • Define component props with interface Props and withDefaults(defineProps<Props>(), {...})
  • Define emits with typed defineEmits<{ event: [payload: Type] }>()
  • Use explicit types for ref<Type>(), computed<Type>(), and function return types
  • No any type — use proper interfaces or type aliases
  • Shared types go in resources/js/types/ (e.g., models.ts, billing.ts)
  • Inertia page props should be typed with interfaces

Example Component Pattern

<script setup lang="ts">
import { Link } from '@inertiajs/vue3'
import AppLayout from '@/Layouts/AppLayout.vue'

interface Props {
  title: string
  items: Item[]
  count?: number
}

interface Item {
  id: number
  name: string
  status: 'active' | 'inactive'
}

defineOptions({ layout: AppLayout })

const props = withDefaults(defineProps<Props>(), {
  count: 0,
})

const isActive = computed<boolean>(() => props.count > 0)
</script>

Migration Note

Existing .vue files in resources/js/ were written in plain JavaScript during Phase 1-2. They must be migrated to TypeScript as they are touched. When working on a page, convert it to TypeScript as part of the work.

Vuexy Theme Reference

The Vuexy theme is at ../vuexy-theme-vue-laravel-full-example-typescript/. Use it as a reference for UI patterns, component design, and styling conventions.

Key Vuexy Patterns to Follow

  • Component structure: <script lang="ts" setup> → props interface → state → computed → methods → watchers
  • Vuetify components: VCard, VBtn, VTextField, VIcon, VAvatar, VChip, VDataTable, etc.
  • Layout system: Vertical nav with collapsible sidebar, sticky navbar, configurable footer
  • Theme system: Light/dark/system modes with skin variants (default, bordered)
  • Navigation types: NavLink, NavGroup, NavSectionTitle (see resources/ts/@layouts/types.ts)
  • Composables: Reusable logic in composables/ directory (e.g., useApi.ts)
  • State management: Pinia stores for shared state
  • Icons: Tabler icons via @iconify/vue (e.g., tabler-smart-home, tabler-chart-bar)

Vuexy Directory Reference

vuexy-theme-vue-laravel-full-example-typescript/
├── resources/ts/              # TypeScript source
│   ├── @core/                 # Core utilities, composables, components
│   ├── @layouts/              # Layout system (vertical/horizontal nav)
│   ├── layouts/               # Page layout templates (default, blank)
│   ├── pages/                 # File-based routing pages
│   ├── plugins/               # Vue plugins (router, pinia, vuetify, i18n, casl)
│   ├── navigation/            # Nav item definitions (vertical/, horizontal/)
│   └── composables/           # App-level composables
├── resources/styles/          # SCSS with Vuetify variable overrides
├── themeConfig.ts             # Global theme configuration
├── vite.config.ts             # Vite with auto-import, file-based routing
└── tsconfig.json              # Strict TypeScript config

Agent Usage (MANDATORY)

Always maximize use of subagents (Task tool) to reduce context usage in the main conversation. This keeps the main terminal fast and avoids running out of context on large tasks.

Rules

  • Parallel agents: When multiple independent tasks exist (e.g., reading several files, researching different topics, building separate components), launch them as parallel agents in a single message rather than doing them sequentially in the main context.
  • Delegate research: Use Explore agents for codebase exploration, file searches, and understanding existing patterns. Do not manually grep/read dozens of files in the main context.
  • Delegate implementation: Use general-purpose agents for self-contained implementation tasks (e.g., "create this component", "write this migration", "update these 5 files with this pattern").
  • Delegate reviews: Use feature-dev:code-reviewer agents to review code after writing it.
  • Delegate architecture: Use feature-dev:code-architect or Plan agents for designing features before implementing.
  • Keep main context for orchestration: The main conversation should coordinate agents, communicate with the user, and handle simple/quick edits. Heavy lifting goes to agents.
  • Background agents: Use run_in_background: true for long-running tasks that don't block other work. Check results later with the Read tool on the output file.
  • Batch similar work: If updating 10+ files with the same pattern, send them to an agent rather than editing each one in the main context.

Frontend Design Skill

When using the frontend-design skill, ALWAYS run it in the background using run_in_background: true. Never run it in the main context window — it consumes significant context and produces large outputs. Check its output file when complete using the Read tool.

Headless Chrome

Chrome is available for visual testing and screenshot comparison. Use it to verify UI matches design references.

google-chrome --headless=new --disable-gpu --no-sandbox --screenshot=/tmp/screenshot.png --window-size=1920,1080 --virtual-time-budget=15000 "URL"
  • Must use --headless=new (not just --headless) for modern headless mode
  • Must use --virtual-time-budget=15000 (or higher) to wait for SPA JavaScript to render before capturing
  • Must use --no-sandbox in this environment
  • Vuexy demo base URL: https://demos.pixinvent.com/vuexy-vuejs-laravel-admin-template/demo-6/
  • dbus errors in output are harmless — ignore them
  • Use for comparing our pages against the Vuexy demo visually
  • After every successful npm run build, screenshot key pages and compare layout/design against the Vuexy demo to ensure visual parity
  • Use for verifying layout, spacing, and component rendering
  • Can be delegated to agents for parallel screenshot capture
  • Read the resulting PNG with the Read tool to view it

Examples of When to Use Agents

  • Exploring how a feature works across multiple files → Explore agent
  • Creating multiple Vue pages/components → parallel general-purpose agents
  • Writing tests for new code → general-purpose agent
  • Researching Vuexy theme patterns → Explore agent
  • Building a new API endpoint (controller + request + test) → general-purpose agent
  • Reviewing changes before committing → feature-dev:code-reviewer agent

Code Conventions

PHP

  • PSR-12 coding standards, enforced by Pint
  • declare(strict_types=1); in all PHP files
  • Explicit return types and parameter type hints on all methods
  • PHP 8 constructor property promotion
  • Form Request classes for validation (not inline in controllers)
  • Service classes for business logic (controllers stay thin)
  • Policies for authorization
  • Events/Listeners for side effects (email, provisioning, etc.)
  • Eloquent models and relationships over raw DB queries; avoid DB::, prefer Model::query()
  • Eager loading to prevent N+1 queries
  • config() helper only, never env() outside config files
  • Named routes with route() helper for URL generation
  • Feature and Unit tests (Pest) for all new functionality
  • Database transactions for multi-step operations
  • Check sibling files for conventions before creating new files
  • Run vendor/bin/pint --dirty --format agent before finalizing changes

Frontend (Vue/TypeScript)

  • All components use <script setup lang="ts">
  • Props defined via interface Props + defineProps<Props>()
  • Dark mode is the default UI theme via Vuetify theme system
  • Use Vuetify components (VCard, VBtn, VTextField via AppTextField wrapper, VChip, etc.) — not raw HTML
  • Use AppTextField, AppSelect, AppTextarea wrappers (in Components/app-form-elements/) instead of VTextField/VSelect/VTextarea directly
  • Use Inertia Link component for navigation (not <a> tags for internal links)
  • Use useForm() from @inertiajs/vue3 for form submissions
  • Status badges use VChip with color prop and resolveStatusColor() utilities
  • Refer to Vuexy theme components and patterns when building new UI

Security

  • All API endpoints require authentication
  • Admin routes protected by role-based middleware
  • CSRF protection on all forms (webhooks exempted via bootstrap/app.php)
  • Rate limiting on auth and API endpoints
  • Encrypted storage for sensitive data (API keys, credentials)
  • Audit logging for admin actions and billing events

Domains

  • ezscale.devezscale.cloud (marketing site) — dev uses .dev, production will use .cloud
  • account.ezscale.devaccount.ezscale.cloud (customer dashboard)
  • admin.ezscale.devadmin.ezscale.cloud (admin panel, Cloudflare Zero Trust)
  • Subdomain routing configured in bootstrap/app.php via Route::domain()

Key Business Domains

  1. Billing — Subscriptions, invoices, payments (Stripe + PayPal), dunning, coupons
  2. Provisioning — VirtFusion (VPS), Pterodactyl (Game), SynergyCP (Dedicated), Enhance (Hosting) — idempotent provisioning with retry
  3. Customer Management — Profiles, support tickets, notifications
  4. Admin Panel — Dashboard, analytics, user/service management
  5. SSO — Single sign-on via Laravel Passport

Reference Docs

  • TASKS.md — Task list and progress tracking (update after each phase)
  • PROJECT_DEVELOPMENT.md — Architecture decisions, database schema, API integrations
  • FEATURES.md — Feature specifications (35+ features)
  • ADVANCED_FEATURES.md — Advanced feature specs (28 features)
  • KASM_AND_MULTITENANCY.md — Kasm Workspaces + reseller multi-tenancy
  • GETTING_STARTED.md — Development setup guide
  • IDEAS.md — Future feature ideas
  • website/CLAUDE.md — Laravel Boost guidelines (auto-generated, Laravel/Pest/Pint conventions)
  • vuexy-theme-vue-laravel-full-example-typescript/ — Vuexy theme reference (TypeScript, Vuetify, layouts)