enodastore modification summary 1) PageController update Modification: PageController dashboard route support Date: 2026-11-04 This change updates the dashboard controller to support the billing and settings sections for store owners. What changed: - Reads the store and active plan information for the owner. - Detects the requested dashboard section/tab. - Renders the billing page when /dashboard/billing is requested. - Renders the settings page when /dashboard/settings or /dashboard/settings/{tab} is requested. - Keeps the fallback to the main dashboard when no specific section is requested. Why: - The previous controller only rendered a generic dashboard screen and did not handle the new owner settings/billing routes. - This makes the owner panel sections reachable and consistent with the route structure. 2) Route additions Modification: Route additions for settings and billing Date: 2026-11-04 This change adds the required route entries for the owner settings experience. Added routes: - /dashboard/settings - /dashboard/settings/{tab} - /dashboard/{section} Why: - The app needs dedicated route handling so the settings tabs and billing screen load correctly. - This prevents the dashboard fallback from swallowing the requested sections. 3) Billing page view Modification: Billing page view Date: 2026-11-04 This change creates the billing page template for the store owner area. Included sections: - Current plan summary card - Renewal and days-left information - Plan comparison list with upgrade actions - Usage meters - Payment history table Why: - The project needed a concrete billing screen matching the owner panel design flow. - This gives the store owner an interface to review plan information and payment records. 4) Settings page view Modification: Settings page view Date: 2026-11-04 This change creates the owner settings page shell with tab navigation and a preview card. Included sections: - Top header and Save button - Horizontal tab strip for settings sections - General settings form layout - Store preview block Why: - The app needed a reusable settings entry page to support the owner settings experience. - The tabbed layout is a foundation for the later detailed sections (general, WhatsApp, payment, domain, etc.). 5) Dashboard section detection fix Modification: Dashboard section detection for owner settings and billing routes Date: 2026-11-04 This change fixes the dashboard controller so it resolves the requested section from the actual request path when route params are empty. What changed: - Reads the current request path before selecting a section. - Maps /dashboard/settings to the settings view. - Maps /dashboard/billing to the billing view. - Keeps support for /dashboard/settings/{tab} and /dashboard/{section}. Why: - The previous controller only relied on URL params and could fall back to the generic dashboard when a direct settings or billing route was requested. - This ensures the store owner sees the intended page instead of the dashboard landing screen. 6) Billing migration duplicate-column cleanup Modification: Forward migration 010 removes duplicate billing aliases introduced by migration 009 Date: 2026-11-05 What changed: - Added database/migrations/010_remove_duplicate_billing_columns.sql. It copies non-empty values from the new aliases to the existing canonical columns where the canonical value is empty/default, then drops the aliases. - Kept the established billing names used by existing code: subscriptions.billing_cycle, starts_at and ends_at; payments.billing_cycle, utr_number and screenshot; invoices.invoice_number, subtotal and tax_rate. - Kept the non-duplicate trial_ends_at and cancel_at_period_end subscription columns. - Did not edit migrations 005-009. - Applied migration 010 to the configured local MySQL database and confirmed the final DESCRIBE output. Verification: - tests/subscription_service_test.php: 24 assertions passed. - tests/analytics_settings_test.php: 8 checks passed against its existing analytics fixture data in local MySQL. - tests/smoke.php was run, but could not pass because this environment has no SMOKE_BASE_URL, owner credentials, settled invoice ID or payment screenshot. Its HTTP checks therefore report setup failures, not application regressions. - The application has no explicit code references to trial_ends_at or cancel_at_period_end yet. They remain schema-only; their behavior was not added in this cleanup turn. 7) Subscription lifecycle, daily processing, and self-contained smoke test Modification: Removed the last payments reason duplicate and implemented subscription expiry/cancellation lifecycle Date: 2026-11-05 What changed: - Added database/migrations/011_remove_duplicate_payment_reason.sql. It copies a non-empty payments.reason into reject_reason when the canonical value is empty, then drops reason. - Updated subscription settlement, Razorpay failure/cancel, manual rejection, owner payment history query, and billing view to use payments.reject_reason only. - Implemented trial_ends_at in SubscriptionService::startTrial, defaulting to the global trial_days setting when no explicit day count is provided. - Daily processing now uses trial_ends_at for trials, transitions expired trial/active subscriptions to grace and then expired, and expires a scheduled cancellation at period end without entering grace. - Added cancelAtPeriodEnd and resumeSubscription methods and CSRF-protected owner POST routes. Billing shows the Cancel at period end / Resume controls. - Scheduled downgrades update the active plan. Storefront product selection applies the lower plan limit; excess products remain stored and are not deleted. - Reminder delivery now atomically claims reminder_7_sent_at or reminder_1_sent_at, resets a claim if mail delivery fails, and does not send duplicate reminders on repeated daily runs. - The existing public/cron/daily.php entrypoint was already present; the updated SubscriptionService is used by it. It remains CLI-accessible and has its existing authenticated web mode. - Expanded tests/subscription_service_test.php with fake-date and transactional real-MySQL lifecycle checks. Reminder delivery is injected in tests to avoid external email. - Updated tests/smoke.php to create a uniquely named _test database, migrate and seed it, create a temporary owner and store through the HTTP flow, create payment/invoice/PDF and screenshot fixtures, start a temporary PHP server, and clean up database/files afterward. It reads supplied SMOKE_* values and uses generated values when missing. - Added ENODASTORE_DB_* environment overrides in Config so the isolated HTTP server connects to the temporary database. - Fixed two directly exposed billing-path defects: the billing view overwrote View::render's status argument with its local $status variable, and BillingController lacked its Lang import. Verification: - Migration runner output: "Database migrations completed." - Live DESCRIBE payments contains reject_reason and no reason column; migration 011 is recorded. - tests/subscription_service_test.php: 42 assertions passed, including trial expiry, grace expiry, cancel/resume/expiry, scheduled downgrade product visibility without deletion, and once-only 7-day/1-day reminders. - public/cron/daily.php CLI output against the configured database: {"grace_started":0,"expired":0,"downgrades_applied":0,"reminders_sent":0}. - tests/smoke.php self-provisioned its _test database and passed installer, login, store creation, add-product page, payment/invoice fixture, CSRF cancel/resume, storefront home, invoice download, and manual plan payment. - At the time of this earlier run, two smoke checks failed because /{store_slug}/cart and /{store_slug}/checkout both pointed to StorefrontController::home. Item 8 records the fix and successful rerun. - PHP syntax checks passed for all changed PHP files and the existing daily cron entrypoint. Correction to item 6 above: - trial_ends_at and cancel_at_period_end are no longer schema-only; both are implemented and covered by the tests described in item 7. 8) Storefront routing, cart/checkout, customer order PDF, and cron token gate Modification: Replaced storefront cart/checkout home-handler aliases with store-scoped customer flow handlers. Date: 2026-11-05 What changed: - Fixed the previous route wiring where GET /{store_slug}/cart and GET /{store_slug}/checkout both called StorefrontController::home. - Added explicit store-scoped handlers/routes for /{slug}, /{slug}/products, /{slug}/category/{category_slug}, /{slug}/product/{product_slug}, /{slug}/cart, /{slug}/checkout (GET and POST), /{slug}/order/{order_number}, /{slug}/order/{order_number}/pdf, and /{slug}/page/{page_slug}. Cart add/update are CSRF-protected POST routes. - Added real product-list, product-detail, cart, checkout, page, and order-success views. Cart data is separated by store in the session; database reads and order writes are constrained by store_id. - Added OrderService with locked product re-reads, server-side prices, stock validation/decrement, transactional order and order_items insertion, and plan-gated coupons. Client-supplied prices are ignored. Failed stock checks roll back without creating an order. - Added reserved-word checks for product slugs in the product editor and page slugs on route resolution. - Centralized the reserved route/global slug list in App\Core\ReservedSlugs and reject reserved product slugs on lookup as well as save. - Added an mPDF customer order PDF with private storage and a store-scoped PDF response route. The generated PDF includes customer/order/item totals and Tamil content; a Windows Latha font is used when available. - Added English and Tamil storefront labels. - Web /cron/daily.php now reads CRON_TOKEN from the process environment or .env, rejects empty/missing/mismatched values with a generic 403 using hash_equals, and remains callable from CLI. - Added tests/checkout_flow_test.php, which provisions and drops an isolated migrated MySQL _test database and exercises the flow over a local HTTP server; added tests/cron_access_test.php. - Added composer.lock for the existing mPDF and PHPMailer requirements. The local PHP installation has GD and ZIP DLLs but they were disabled in php.ini; Composer install succeeded with those DLLs enabled for the install command. PyMuPDF was installed locally only to rasterize the generated PDF for the requested image inspection. Verification: - tests/smoke.php: all 11 steps passed against its isolated temporary MySQL database, including the cart and checkout routes. - tests/checkout_flow_test.php: 14 checks passed, covering catalog/category/page routes, reserved-slug rejection, MySQL order/order_items rows, server-side repricing, stock rejection including stale stock, Starter/Growth coupon gating, PDF validity/Tamil extraction, and WhatsApp URL construction. - The checkout test rendered page 1 of the order PDF to storage/test-artifacts/checkout-order-page-91baa65e.png. Visual inspection confirmed a one-page portrait order summary with the store/order heading, customer name and phone, Tamil product row, quantity, unit price, and totals. - tests/cron_access_test.php: 2 checks passed for empty and incorrect tokens returning only HTTP 403 / "Forbidden." - tests/subscription_service_test.php: 42 assertions passed. - tests/analytics_settings_test.php: 8 checks passed against a separately provisioned and dropped _test database. - public/cron/daily.php CLI ran against an isolated migrated _test database and returned {"grace_started":0,"expired":0,"downgrades_applied":0,"reminders_sent":0}. - PHP syntax checks passed on the final changed PHP file set. Correction to item 7 above: - The earlier cart and checkout failures were fixed in this item. They are no longer outstanding. 9) Fresh MySQL verification of the requested integration suites Modification: Re-ran the subscription, analytics settings, smoke, checkout flow, and cron access tests against the local MySQL server. Date: 2026-11-05 What changed: - No application or test code changed in this verification pass. - Started the existing local XAMPP MariaDB server for test execution. It reported MariaDB 10.11.16; PHP CLI reported 8.3.36. - Stopped that MySQL process after the verification run. - Ran analytics_settings_test.php only against a fresh, migrated, temporary MySQL database because that test deletes rows from its configured database tables. The temporary analytics database was dropped after the test. Verification: - tests/subscription_service_test.php: 42 assertions passed against the configured MySQL database. The test's lifecycle fixtures ran inside a transaction and were rolled back. - tests/analytics_settings_test.php: all 8 checks passed against its isolated MySQL database. - tests/smoke.php: all 11 HTTP checks passed against an isolated, self-provisioned MySQL test database. - tests/checkout_flow_test.php: all 14 checks passed against an isolated MySQL test database; the PDF was generated, extracted, and rendered during the test. - tests/cron_access_test.php: both HTTP token-gate checks passed. - PHP syntax checks passed for all five PHP test files. No PHP source files were changed in this verification pass. - Verified that the isolated analytics, smoke, and checkout test databases had been removed after their runs. 10) Manual payment review, Razorpay billing, and invoices Modification: Completed and verified the owner payment submission, Super Admin review, Razorpay integration boundary, and private invoice flow. Date: 2026-11-05 What changed: - Added /superadmin payment queue, proof viewer, approve/reject actions, invoice download, role guards, CSRF checks, and audit outcomes. Manual submissions validate JPG/PNG/WebP content with finfo, enforce a 3 MiB limit, use random private filenames, and remain pending until review. - Approval applies a subscription once, creates one invoice, and sends an owner email; repeat approval does not extend the subscription or duplicate the invoice. Rejection persists the reason and sends an owner email. - Extracted Razorpay HTTP transport behind RazorpayClient. Orders use the selected MySQL plan quote, callbacks check the payment HMAC and captured amount, and signed payment.captured/payment.failed/order.paid webhooks are logged and replay-safe. Credentials use AES-256-GCM with APP_KEY; disabled methods are rejected server-side and one method must remain enabled. - Added yearly ENO-YYYY invoice numbering, private owner/super-admin PDF downloads, seller/customer/plan/period/tax/total details, and locally bundled Noto Sans Tamil regular/bold faces. Invoice labels have English and Tamil entries. Static asset styling is now compiled locally; the Tailwind, Alpine, and web-font CDNs were removed from the shared page head. - Localized Super Admin payment method and status labels in the pending queue using the existing English and Tamil billing dictionaries. - Added tests/payments_test.php and docs/BILLING.md. Tax identifiers and tax rates are settings placeholders and must be replaced with verified business details before production invoicing. Verification: - Final validation rerun after the payment-queue localization change: - tests/payments_test.php: 32 checks passed against a temporary migrated MySQL database. The test exercised real HTTP multipart submission and Super Admin approval/rejection; email delivery used a local mock SMTP server. Razorpay used a mock transport, including valid/invalid known HMACs, amount mismatch, replay, payment.failed/order.paid events, and disabled-method attempts. - The final retained invoice page-1 render is storage/test-artifacts/invoice-page-a40afd3f.png. It is 715x1011, one page, with extractable English and Tamil labels, aligned totals, and no broken/missing Tamil glyphs; intermediate invoice diagnostics were removed. - tests/subscription_service_test.php: 42 assertions passed. - tests/analytics_settings_test.php: 8 checks passed against a fresh isolated database; it was dropped after the run. - tests/smoke.php: all 11 HTTP checks passed against its isolated MySQL database. - tests/checkout_flow_test.php: all 14 checks passed, including MySQL writes, pricing/stock enforcement, PDF extraction, and page-1 rasterization. - tests/cron_access_test.php: both HTTP token checks passed. - php -l passed for all 122 PHP files under app, config, public, tests, and cli; after the final view localization change, php -l was rerun on app/Views/superadmin/payments.php and passed. - npm install completed with 0 reported vulnerabilities; npm run build:css produced public/assets/css/app.css. Browser inspection at 390x844 showed the login page had no horizontal overflow and loaded only local application CSS/JS and font assets. Remaining limits: - No real Razorpay credentials or network transaction were available; live order creation, hosted checkout, and webhook delivery were not exercised. docs/BILLING.md describes test-mode keys and tunnel setup. - Razorpay Checkout requires its provider-hosted script at checkout. It is the only external script retained; other app runtime CDN dependencies were removed. A literal zero-external-script policy conflicts with the requested Razorpay Checkout integration. - SMTP delivery was verified with mock SMTP, not a production mail provider. Tax identifiers remain configured placeholders until the operator supplies verified details. 11) Super Admin panel completion Modification: Completed the database-backed Super Admin pages and owner support experience; added isolated MySQL/HTTP integration coverage and operator documentation. Date: 2026-11-05 What changed: - Added docs/SUPERADMIN.md with route coverage, setup guidance, security behavior, and test instructions. - Completed live-data dashboard metrics/charts, store search/detail/actions, plan editing, support threads, announcements, settings, audit filters/exports, and health reporting. - Added owner support pages and tenant-scoped ticket access, announcement dismissal checks, local Chart.js delivery, and daily-cron health audit records. - Enforced Super Admin role checks and CSRF on mutating routes; maintenance mode prevents store-owner sign-in (including unverified owners) and dashboard access while keeping Super Admin access available. - Added mailer injection for service tests so support mail-log behavior is exercised without contacting a real mail server. Corrected checkbox parsing so a forged non-enabled value cannot satisfy the at-least-one-payment-method guard. - Fixed PHP built-in-server routing for existing static files and made the shared head tolerate theme arrays without a CSS URL. Verification: - tests/superadmin_test.php: 84 checks passed against an isolated migrated MySQL database, including live-data rendering for every Super Admin page, owner 403 checks, CSRF, tenant isolation, maintenance-mode sign-in, and local Chart.js HTTP delivery. - tests/payments_test.php: 32 checks passed; subscription_service_test.php: 42 assertions passed; analytics_settings_test.php: 8 checks passed; smoke.php: all 11 steps passed; checkout_flow_test.php: 14 checks passed; cron_access_test.php: 2 checks passed. Each database integration suite used a temporary MySQL database. - PHP syntax validation passed for all 128 PHP files under app, config, public, tests, and cli. Node syntax checks passed for the Super Admin script and local Chart.js. Remaining limits: - Support email behavior in the Super Admin integration suite uses an injected mock delivery callback; production SMTP delivery still requires operator-configured credentials and a real delivery check. - No live Razorpay transaction or production email delivery was performed; see docs/BILLING.md. - The separately requested storefront-theme screenshot/accessibility audit and themes_test.php/docs/themes/README.md remain unverified and outstanding. 12) Analytics and store-owner settings Modification: Completed the analytics dashboard/report endpoints and store-scoped owner settings, account actions, notification hooks, and tenant-specific SEO routes. Date: 2026-11-05 What changed: - Added tenant-scoped analytics reports for 7/30/90 days, funnel stages, repeat/new customers, product/category and weekday/hour reporting, order/product CSV exports, five-minute report caching, and advanced_analytics plan gating. - Visitor tracking stores daily HMAC identifiers derived from IP and user agent rather than raw values. Tracking resolves store context from the storefront session. - Added store-scoped settings for WhatsApp, delivery, notifications, SEO, domain, and policies; account password/session/export/deletion workflows; owner mail notifications; order delivery fee enforcement; per-store sitemap and robots routes. - Added docs/ANALYTICS_SETTINGS.md and extended isolated MySQL coverage in tests/analytics_settings_test.php and tests/checkout_flow_test.php. Verification: - Final full database-backed suite passed: subscription_service_test.php (42 assertions), analytics_settings_test.php (37 checks), payments_test.php (32 checks), checkout_flow_test.php (14 checks), smoke.php (11 HTTP steps), superadmin_test.php (84 checks), and cron_access_test.php (2 checks). Each integration test that creates a database dropped its temporary database. - analytics_settings_test.php printed real seven-day JSON from its isolated MySQL data: 1 order, INR 200 revenue, 5 visits, 3 daily unique visitors, 20% conversion, product/category series, and a WhatsApp-click funnel count of 2. - php -l passed for all 134 PHP files checked across the repository root, app, config, public, tests, and cli. JavaScript syntax checks and the local CSS build passed; the build noted outdated Browserslist data. - Checkout integration verified the persisted delivery charge (INR 12.00) and total (INR 137.50). Notification mail delivery was exercised using mock mailers; no production SMTP send was attempted. Remaining limits: - Custom domains remain pending; DNS verification and SSL provisioning are not implemented. The referenced N5 requirements were not present in the repository. - Live SMTP delivery was not verified. See docs/ANALYTICS_SETTINGS.md. 13) Landing, signup, onboarding, email, and legal pages status review Modification: Verified the existing implementation and recorded remaining work for the requested marketing, onboarding, email, and legal experience. Date: 2026-11-05 What exists (verified by source inspection): - The public landing route queries active plans from the plans table and renders database-backed monthly pricing. The public navigation has a sticky header and English/Tamil language switch; the page has how-it-works content, WhatsApp explanation, FAQs, CTA, and legal/contact footer links. - Signup validates user fields, creates a store-owner account, requires OTP verification, sends a welcome email, and routes verified users without a store to onboarding. - Onboarding is a resumable four-step session flow. It checks reserved/available slugs, validates category and Indian WhatsApp number, offers available Starter themes, and creates a trial store and subscription in MySQL. The success page has copy-link and WhatsApp-share actions. - Mailer writes to mail_log and can deliver through configured SMTP or PHP mail(). Existing templates cover welcome, subscription reminder, payment receipt/rejection, and password reset. New-order notifications are assembled by NotificationService and use the Mailer. - Super Admin can edit Terms and Privacy content. Public Terms and Privacy read those settings; Refund currently uses static translated text. - Stitch landing design exports exist under design/stitch_enodastore_ui_kit/stitch_enodastore_ui_kit. No public/media/ad.mp4 was present during inspection. Pending (not implemented or tested in this review): - Landing: implement a real gallery populated from active themes, add a WhatsApp-vs-store comparison, retain an editable testimonial placeholder without fabricated testimonials, add marketing SEO/Open Graph metadata, and use the specified Tamil hero copy in the Tamil translation. Confirm responsive performance and local-only runtime assets. Add video only if the requested file is supplied. - Onboarding: extend the existing four steps to the requested five-step flow; include category-based theme preselection, theme selection, logo upload and E.164 WhatsApp input, optional first-product creation, and a live-store completion page with locally generated QR code and share controls. Add a persistent, dismissible/completable setup checklist to the owner dashboard. - Email: provide bilingual English/Tamil HTML and plain-text templates for welcome, 3-day/1-day trial reminders, payment received/rejected, subscription expired, new-order notification, and password reset. Route all messages through Mailer and verify mail_log records and delivery behavior with mocks. - Legal: make Refund editable in Super Admin, provide Indian SaaS Terms/Privacy/Refund starter templates clearly labelled for lawyer review, and render configured content safely. - Tests: add an isolated-MySQL integration test covering signup/OTP as applicable, onboarding resume and store creation, and confirmation that landing pricing reflects plans-table rows. Run the requested tests and PHP lint after implementation; no such tests or lint were run as part of this status review. Verification: - This was a source-inspection/status-documentation update only. No application files were changed, no database-backed signup/onboarding flow was executed, and no new tests were run.