# ECStores — Project Changelog

All notable changes to the ECStores platform are documented here.

---

## [Unreleased]

### Pending
- ECW ↔ ECStores portal integration (My Store card, magic link, provisioning on payment)
- Wildcard SSL for `*.ecstores.ca`
- DNS cutover from `widget.eastcoastweb.ca` to `ecstores.ca`
- Live Stripe keys and webhook registration

---

## [0.2.0] — 2026-05-14 — Audit Fix Pass

### Fixed
- **AccountController::orders()** — was not passing `$settings` to the view; customers viewing order history got a crash on `$settings->currency`
- **Currency architecture** — three-way mismatch resolved: `currency` now stores lowercase ISO code (`cad`/`usd`/`eur`/`gbp`) for Stripe; `currency_symbol` stores display prefix (`$`/`€`/`£`) for views. Previously the provisioning seeded a symbol while the settings form saved ISO codes.
- **Refund max validation** — admin could enter any refund amount; Stripe rejected it with an unhelpful error. Now has server-side `maxValue()` validation before the API call.
- **Sale price validation** — no rule prevented setting a sale price higher than the regular price. Now validated in the product form.
- **View composer coverage** — auth views (login, forgot-password, reset-password) were not covered by the `$settings` view composer; fixed by extending coverage to `['storefront.*', 'auth.*']`.

### Added
- **Password reset flow** — full forgot-password / reset-password flow using Laravel's `Password` facade. Routes, controller, views, and "Forgot your password?" link on the login page.
- **Featured products section** — dedicated section on the storefront homepage above the main grid, shown only when not filtering.
- **Out-of-stock badge** — red "Out of stock" badge on product listing cards for products with `track_inventory = ON` and `units_in_stock = 0`.
- **Wishlist link in header** — authenticated customers now have a direct Wishlist link in the main navigation header.
- **Tax rate** — configurable `tax_rate` field in Site Settings. Tax calculated at checkout (display, Stripe PaymentIntent total, and order record). Tax line shown in order summary when > 0.
- **Admin profile / password change** — Filament's built-in profile page (`/admin/profile`) enabled. Admins can change name, email, and password without leaving the panel.
- **Welcome email on provisioning** — `StoreWelcomeMail` sent after tenant provisioning with store URL, admin URL, and temporary credentials.
- **Drag-to-reorder** — drag handles added to Products, Categories, and Shipping Methods tables in admin.
- **Out-of-stock admin filter** — ternary filter added to the Products admin table to quickly show only in-stock or out-of-stock products.
- **Soft deletes on products** — `deleted_at` column added to products table; hard-deleting from admin soft-deletes instead, preserving order history integrity.
- **Category deletion warning** — bulk delete confirmation modal now lists the affected category names and warns that products will become uncategorized.
- **ECW setup file removal** — `_setup/install.php` and `_setup/upgrade.php` deleted from production server (both were publicly accessible and printed credentials).

### Changed
- Filament money columns now use dynamic currency (`->money(fn () => strtoupper(SiteSettings::current()->currency ?? 'cad'))`) instead of hardcoded `'CAD'`
- `TenantProvisioningService` seeds `currency = 'cad'`, `currency_symbol = '$'`, `tax_rate = 0` (was seeding `currency = '$'`)

---

## [0.1.0] — 2026-05-13 — Initial Build

### Added
- Multi-tenant architecture (stancl/tenancy v3) — central DB + per-tenant isolated databases
- **Super-admin panel** (`/super`) — Denis's platform panel; tenant provisioning, suspension/reactivation, plan management, Platform Overview widget
- **Tenant admin panel** (`/admin`, Filament v5) — full merchant dashboard
  - Products: CRUD, images (Spatie MediaLibrary), sale price, featured/discontinued flags, inventory tracking, bulk actions (assign category/supplier, featured, on sale, discontinued)
  - Product variants: variant groups, options, combination matrix generator, per-combination SKU/price/stock
  - Categories: CRUD, slug auto-generation, sort order
  - Suppliers: CRUD, contact info, notes; product filtering by supplier
  - Orders: list with status/date filters, detail view, status update (with shipped date enforcement), buyer note, partial/full Stripe refunds
  - Shipping methods: CRUD, active flag, price, sort order
  - Site Settings: company name, contact, currency, return policy, social links
  - Branding Studio: primary colour, heading/body fonts, button style, logo, favicon, homepage banner, custom CSS
  - Stripe Connect: guided onboarding, status display (charges/payouts enabled), Express Dashboard link
  - Dashboard widget: monthly revenue, orders this month, awaiting fulfilment, total customers
- **Storefront (customer-facing)**
  - Product catalogue with search, category filter, wishlist toggle
  - Product detail with image gallery, variant selector (reactive price/stock), wishlist toggle
  - Cart (session-based, Livewire reactive)
  - Multi-step checkout wizard: contact/billing → shipping → review → Stripe payment (Connect destination charges)
  - Order confirmation page with payment status display
  - Customer registration, login, logout, remember me
  - Account area: profile (name, email, address, password), order history, wishlist
- **ECW ↔ ECStores API** (HMAC-SHA256 authenticated)
  - `POST /api/v1/provision` — create tenant
  - `GET /api/v1/tenant/{slug}/status` — tenant status
  - `POST /api/v1/tenant/{slug}/suspend` — suspend
  - `POST /api/v1/tenant/{slug}/reactivate` — reactivate
  - `POST /api/v1/magic-link` — generate signed admin login URL
  - `GET /admin/external-login` — magic link receiver (creates Filament session)
- Shared hosting compatibility (`SharedHostingMySQLDatabaseManager`, manual DB pre-creation in cPanel)
- Deployment to inMotion shared hosting under `widget.eastcoastweb.ca` (test domain)
