// POINT 1 — Forgot-password links
// POINT 2 — Account settings pages
// POINT 3 — Investor unfollow
// POINT 4 — Risk warning
// POINT 5 — Mobile sidebar
// POINT 6 — CSV export
// POINT 7 — Copy-trade orders page
// POINT 8 — Health endpoint
// POINT 9 — Admin sidebar i18n
// POINT 10 — i18n keys
// POINT 11 — Cron script
Test Results
Platform Test Suite
CHANGES.txt — 2026-08-21 — 165 checks
1. Forgot-password links
✓P1: trader login has forgot-password link — trader/login.php should contain: forgot-password.php
✓P1: investor login has forgot-password link — investor/login.php should contain: forgot-password.php
✓P1: trader forgot-password link uses i18n key — trader/login.php should contain: auth.forgot_password_link
✓P1: investor forgot-password link uses i18n key — investor/login.php should contain: auth.forgot_password_link
2. Account settings pages
✓P2: trader/account.php exists — trader/account.php
✓P2: investor/account.php exists — investor/account.php
✓P2: assets/js/trader/account.js exists — assets/js/trader/account.js
✓P2: assets/js/investor/account.js exists — assets/js/investor/account.js
✓P2: AccountController.php exists — api/controllers/AccountController.php
✓P2: trader/account.php PHP syntax — No syntax errors detected in /home/invest/public_html/trader/account.php
✓P2: investor/account.php PHP syntax — No syntax errors detected in /home/invest/public_html/investor/account.php
✓P2: AccountController.php PHP syntax — No syntax errors detected in /home/invest/public_html/api/controllers/AccountController.php
✓P2: api/index.php routes PUT /trader/account — api/index.php should contain: PUT /trader/account
✓P2: api/index.php routes PUT /investor/account — api/index.php should contain: PUT /investor/account
✓P2: api/index.php routes PUT /account (admin) — api/index.php should contain: 'PUT /account'
✓P2: Account nav in trader/index.php — trader/index.php should contain: account.nav_label
✓P2: Account nav in trader/portfolio.php — trader/portfolio.php should contain: account.nav_label
✓P2: Account nav in trader/followers.php — trader/followers.php should contain: account.nav_label
✓P2: Account nav in trader/trademarket.php — trader/trademarket.php should contain: account.nav_label
✓P2: Account nav in trader/profile.php — trader/profile.php should contain: account.nav_label
✗P2: Account nav in investor/index.php — investor/index.php should contain: account.nav_label
✗P2: Account nav in investor/portfolio.php — investor/portfolio.php should contain: account.nav_label
✗P2: Account nav in investor/traders.php — investor/traders.php should contain: account.nav_label
✗P2: Account nav in investor/trader-profile.php — investor/trader-profile.php should contain: account.nav_label
✓P2: admin/settings.php has Account tab button — admin/settings.php should contain: data-tab="admin-account"
✓P2: admin/settings.php has Account tab panel — admin/settings.php should contain: id="tab-admin-account"
P2
✗P2 (API): PUT /trader/account returns 401 without auth — HTTP 405
✗P2 (API): PUT /investor/account returns 401 without auth — HTTP 405
✗P2 (API): PUT /account returns 401 without auth — HTTP 405
3. Investor unfollow
✓P3: investor/index.php has unfollow button — investor/index.php should contain: unfollow-trader-btn
✓P3: dashboard.js has handleUnfollowTrader — assets/js/investor/dashboard.js should contain: handleUnfollowTrader
✓P3: api/index.php routes DELETE /investor/assigned-trader — api/index.php should contain: DELETE /investor/assigned-trader
✓P3: InvestorController has unfollowTrader method — api/controllers/InvestorController.php should contain: unfollowTrader
P3
✗P3 (API): DELETE /investor/assigned-trader returns 401 without auth — HTTP 405
4. Risk warning
✓P4: traders.js has follow_warning confirm — assets/js/investor/traders.js should contain: follow_warning
✓P4: traders.js has switch_warning confirm — assets/js/investor/traders.js should contain: switch_warning
✓P4: dashboard.js has follow_warning confirm — assets/js/investor/dashboard.js should contain: follow_warning
✓P4: dashboard.js has switch_warning confirm — assets/js/investor/dashboard.js should contain: switch_warning
5. Mobile sidebar
✓P5: assets/js/sidebar-mobile.js exists — assets/js/sidebar-mobile.js
✓P5: app.css has #sidebar-toggle — assets/css/app.css should contain: #sidebar-toggle
✓P5: app.css has mobile @media query for sidebar — assets/css/app.css should contain: max-width: 767px
✓P5: app.css has sidebar-open transform — assets/css/app.css should contain: sidebar-open
✓P5: sidebar-mobile.js loaded in admin/index.php — admin/index.php should contain: sidebar-mobile.js
✓P5: sidebar-mobile.js loaded in admin/copy-trading-api.php — admin/copy-trading-api.php should contain: sidebar-mobile.js
✓P5: sidebar-mobile.js loaded in admin/email-logs.php — admin/email-logs.php should contain: sidebar-mobile.js
✓P5: sidebar-mobile.js loaded in admin/investor-traders.php — admin/investor-traders.php should contain: sidebar-mobile.js
✓P5: sidebar-mobile.js loaded in admin/investors.php — admin/investors.php should contain: sidebar-mobile.js
✓P5: sidebar-mobile.js loaded in admin/logs-explorer.php — admin/logs-explorer.php should contain: sidebar-mobile.js
✓P5: sidebar-mobile.js loaded in admin/order-logs.php — admin/order-logs.php should contain: sidebar-mobile.js
✓P5: sidebar-mobile.js loaded in admin/sahme-api-brokers.php — admin/sahme-api-brokers.php should contain: sidebar-mobile.js
✓P5: sidebar-mobile.js loaded in admin/sahme-api-wt5.php — admin/sahme-api-wt5.php should contain: sidebar-mobile.js
✓P5: sidebar-mobile.js loaded in admin/settings.php — admin/settings.php should contain: sidebar-mobile.js
✓P5: sidebar-mobile.js loaded in trader/account.php — trader/account.php should contain: sidebar-mobile.js
✓P5: sidebar-mobile.js loaded in trader/followers.php — trader/followers.php should contain: sidebar-mobile.js
✓P5: sidebar-mobile.js loaded in trader/index.php — trader/index.php should contain: sidebar-mobile.js
✓P5: sidebar-mobile.js loaded in trader/portfolio.php — trader/portfolio.php should contain: sidebar-mobile.js
✓P5: sidebar-mobile.js loaded in trader/profile.php — trader/profile.php should contain: sidebar-mobile.js
✓P5: sidebar-mobile.js loaded in trader/trademarket.php — trader/trademarket.php should contain: sidebar-mobile.js
✓P5: sidebar-mobile.js loaded in investor/account.php — investor/account.php should contain: sidebar-mobile.js
✓P5: sidebar-mobile.js loaded in investor/index.php — investor/index.php should contain: sidebar-mobile.js
✓P5: sidebar-mobile.js loaded in investor/portfolio.php — investor/portfolio.php should contain: sidebar-mobile.js
✓P5: sidebar-mobile.js loaded in investor/trader-profile.php — investor/trader-profile.php should contain: sidebar-mobile.js
✓P5: sidebar-mobile.js loaded in investor/traders.php — investor/traders.php should contain: sidebar-mobile.js
6. CSV export
✓P6: UserController supports export=csv — api/controllers/UserController.php should contain: === 'csv'
✓P6: UserController streams CSV headers — api/controllers/UserController.php should contain: Content-Type: text/csv
✓P6: OrderLogsController supports export=csv — api/controllers/OrderLogsController.php should contain: === 'csv'
✓P6: OrderLogsController streams CSV headers — api/controllers/OrderLogsController.php should contain: Content-Type: text/csv
✓P6: CopyTradeOrdersController supports export — api/controllers/CopyTradeOrdersController.php
✓P6: admin/investors.php has Export CSV button — admin/investors.php should contain: export-btn
✓P6: admin/investor-traders.php has Export CSV button — admin/investor-traders.php should contain: export-btn
✓P6: admin/order-logs.php has Export CSV button — admin/order-logs.php should contain: export-btn
✓P6: investors.js wires export-btn — assets/js/admin/investors.js should contain: export-btn
✓P6: investor-traders.js wires export-btn — assets/js/admin/investor-traders.js should contain: export-btn
✓P6: order-logs.js wires export-btn — assets/js/admin/order-logs.js should contain: export-btn
P6
✗P6 (API): GET /users?export=csv returns 401 without auth — HTTP 404
✗P6 (API): GET /order-logs?export=csv returns 401 without auth — HTTP 404
7. Copy-trade orders page
✓P7: admin/copy-trade-orders.php exists — admin/copy-trade-orders.php
✓P7: assets/js/admin/copy-trade-orders.js exists — assets/js/admin/copy-trade-orders.js
✓P7: CopyTradeOrdersController.php exists — api/controllers/CopyTradeOrdersController.php
✓P7: CopyTradeOrdersController.php PHP syntax — No syntax errors detected in /home/invest/public_html/api/controllers/CopyTradeOrdersController.php
✓P7: api/index.php routes GET /copy-trade-orders — api/index.php should contain: GET /copy-trade-orders
✗P7: copy-trade-orders nav in admin/index.php — admin/index.php should contain: copy-trade-orders.php
✗P7: copy-trade-orders nav in admin/investors.php — admin/investors.php should contain: copy-trade-orders.php
✗P7: copy-trade-orders nav in admin/investor-traders.php — admin/investor-traders.php should contain: copy-trade-orders.php
✗P7: copy-trade-orders nav in admin/settings.php — admin/settings.php should contain: copy-trade-orders.php
✗P7: copy-trade-orders nav in admin/order-logs.php — admin/order-logs.php should contain: copy-trade-orders.php
P7
✗P7 (API): GET /copy-trade-orders returns 401 without auth — HTTP 404
✗P7 (API): GET /copy-trade-orders?export=csv returns 401 without auth — HTTP 404
8. Health endpoint
✓P8: HealthController.php exists — api/controllers/HealthController.php
✓P8: HealthController.php PHP syntax — No syntax errors detected in /home/invest/public_html/api/controllers/HealthController.php
✓P8: api/index.php routes GET /health — api/index.php should contain: GET /health
P8
✗P8 (API): GET /health returns 200 — HTTP 404
✗P8 (API): /health response is valid JSON — Body:
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-type" content="text/html; charset
✗P8 (API): /health has "status" field — JSON keys:
✗P8 (API): /health status is ok or degraded — status=
9. Admin sidebar i18n
✗P9: admin/index.php has data-i18n portal.main_menu — admin/index.php should contain: data-i18n="portal.main_menu"
✗P9: admin/index.php has data-i18n portal.system — admin/index.php should contain: data-i18n="portal.system"
✗P9: admin/index.php has data-i18n portal.logs — admin/index.php should contain: data-i18n="portal.logs"
✗P9: admin/index.php has data-i18n portal.api — admin/index.php should contain: data-i18n="portal.api"
✗P9: admin/investor-traders.php has data-i18n portal.main_menu — admin/investor-traders.php should contain: data-i18n="portal.main_menu"
✗P9: admin/investor-traders.php has data-i18n portal.system — admin/investor-traders.php should contain: data-i18n="portal.system"
✗P9: admin/investor-traders.php has data-i18n portal.logs — admin/investor-traders.php should contain: data-i18n="portal.logs"
✗P9: admin/investor-traders.php has data-i18n portal.api — admin/investor-traders.php should contain: data-i18n="portal.api"
10. i18n keys
✓P10: lang/en.json has key 'account.page_title' — assets/lang/en.json key 'account.page_title' exists
✓P10: lang/en.json has key 'account.nav_label' — assets/lang/en.json key 'account.nav_label' exists
✓P10: lang/en.json has key 'account.current_password' — assets/lang/en.json key 'account.current_password' exists
✓P10: lang/en.json has key 'account.new_password' — assets/lang/en.json key 'account.new_password' exists
✓P10: lang/en.json has key 'account.save_password' — assets/lang/en.json key 'account.save_password' exists
✓P10: lang/en.json has key 'account.password_saved' — assets/lang/en.json key 'account.password_saved' exists
✓P10: lang/en.json has key 'traders.follow_warning' — assets/lang/en.json key 'traders.follow_warning' exists
✓P10: lang/en.json has key 'traders.switch_warning' — assets/lang/en.json key 'traders.switch_warning' exists
✓P10: lang/en.json has key 'traders.unfollowed' — assets/lang/en.json key 'traders.unfollowed' exists
✓P10: lang/en.json has key 'investor_dash.unfollow_trader' — assets/lang/en.json key 'investor_dash.unfollow_trader' exists
✓P10: lang/en.json has key 'investor_dash.unfollow_confirm' — assets/lang/en.json key 'investor_dash.unfollow_confirm' exists
✓P10: lang/en.json has key 'investor_dash.unfollowed' — assets/lang/en.json key 'investor_dash.unfollowed' exists
✓P10: lang/en.json has key 'export.csv' — assets/lang/en.json key 'export.csv' exists
✓P10: lang/en.json has key 'copy_trade_orders.page_title' — assets/lang/en.json key 'copy_trade_orders.page_title' exists
✓P10: lang/en.json has key 'copy_trade_orders.nav_label' — assets/lang/en.json key 'copy_trade_orders.nav_label' exists
✓P10: lang/ar.json has key 'account.page_title' — assets/lang/ar.json key 'account.page_title' exists
✓P10: lang/ar.json has key 'account.nav_label' — assets/lang/ar.json key 'account.nav_label' exists
✓P10: lang/ar.json has key 'account.current_password' — assets/lang/ar.json key 'account.current_password' exists
✓P10: lang/ar.json has key 'account.new_password' — assets/lang/ar.json key 'account.new_password' exists
✓P10: lang/ar.json has key 'account.save_password' — assets/lang/ar.json key 'account.save_password' exists
✓P10: lang/ar.json has key 'account.password_saved' — assets/lang/ar.json key 'account.password_saved' exists
✓P10: lang/ar.json has key 'traders.follow_warning' — assets/lang/ar.json key 'traders.follow_warning' exists
✓P10: lang/ar.json has key 'traders.switch_warning' — assets/lang/ar.json key 'traders.switch_warning' exists
✓P10: lang/ar.json has key 'traders.unfollowed' — assets/lang/ar.json key 'traders.unfollowed' exists
✓P10: lang/ar.json has key 'investor_dash.unfollow_trader' — assets/lang/ar.json key 'investor_dash.unfollow_trader' exists
✓P10: lang/ar.json has key 'investor_dash.unfollow_confirm' — assets/lang/ar.json key 'investor_dash.unfollow_confirm' exists
✓P10: lang/ar.json has key 'investor_dash.unfollowed' — assets/lang/ar.json key 'investor_dash.unfollowed' exists
✓P10: lang/ar.json has key 'export.csv' — assets/lang/ar.json key 'export.csv' exists
✓P10: lang/ar.json has key 'copy_trade_orders.page_title' — assets/lang/ar.json key 'copy_trade_orders.page_title' exists
✓P10: lang/ar.json has key 'copy_trade_orders.nav_label' — assets/lang/ar.json key 'copy_trade_orders.nav_label' exists
✓P10: lang/es.json has key 'account.page_title' — assets/lang/es.json key 'account.page_title' exists
✓P10: lang/es.json has key 'account.nav_label' — assets/lang/es.json key 'account.nav_label' exists
✓P10: lang/es.json has key 'account.current_password' — assets/lang/es.json key 'account.current_password' exists
✓P10: lang/es.json has key 'account.new_password' — assets/lang/es.json key 'account.new_password' exists
✓P10: lang/es.json has key 'account.save_password' — assets/lang/es.json key 'account.save_password' exists
✓P10: lang/es.json has key 'account.password_saved' — assets/lang/es.json key 'account.password_saved' exists
✓P10: lang/es.json has key 'traders.follow_warning' — assets/lang/es.json key 'traders.follow_warning' exists
✓P10: lang/es.json has key 'traders.switch_warning' — assets/lang/es.json key 'traders.switch_warning' exists
✓P10: lang/es.json has key 'traders.unfollowed' — assets/lang/es.json key 'traders.unfollowed' exists
✓P10: lang/es.json has key 'investor_dash.unfollow_trader' — assets/lang/es.json key 'investor_dash.unfollow_trader' exists
✓P10: lang/es.json has key 'investor_dash.unfollow_confirm' — assets/lang/es.json key 'investor_dash.unfollow_confirm' exists
✓P10: lang/es.json has key 'investor_dash.unfollowed' — assets/lang/es.json key 'investor_dash.unfollowed' exists
✓P10: lang/es.json has key 'export.csv' — assets/lang/es.json key 'export.csv' exists
✓P10: lang/es.json has key 'copy_trade_orders.page_title' — assets/lang/es.json key 'copy_trade_orders.page_title' exists
✓P10: lang/es.json has key 'copy_trade_orders.nav_label' — assets/lang/es.json key 'copy_trade_orders.nav_label' exists
✓P10: api/lang/en.php has key 'validation.current_password_required' — api/lang/en.php should contain: 'validation.current_password_required'
✓P10: api/lang/en.php has key 'validation.current_password_wrong' — api/lang/en.php should contain: 'validation.current_password_wrong'
✓P10: api/lang/en.php has key 'validation.invalid_language' — api/lang/en.php should contain: 'validation.invalid_language'
✓P10: api/lang/en.php has key 'traders.unfollowed' — api/lang/en.php should contain: 'traders.unfollowed'
✓P10: api/lang/ar.php has key 'validation.current_password_required' — api/lang/ar.php should contain: 'validation.current_password_required'
✓P10: api/lang/ar.php has key 'validation.current_password_wrong' — api/lang/ar.php should contain: 'validation.current_password_wrong'
✓P10: api/lang/ar.php has key 'validation.invalid_language' — api/lang/ar.php should contain: 'validation.invalid_language'
✓P10: api/lang/ar.php has key 'traders.unfollowed' — api/lang/ar.php should contain: 'traders.unfollowed'
✓P10: api/lang/es.php has key 'validation.current_password_required' — api/lang/es.php should contain: 'validation.current_password_required'
✓P10: api/lang/es.php has key 'validation.current_password_wrong' — api/lang/es.php should contain: 'validation.current_password_wrong'
✓P10: api/lang/es.php has key 'validation.invalid_language' — api/lang/es.php should contain: 'validation.invalid_language'
✓P10: api/lang/es.php has key 'traders.unfollowed' — api/lang/es.php should contain: 'traders.unfollowed'
11. Cron script
✓P11: cron/email-retry.php exists — cron/email-retry.php
✓P11: cron/email-retry.php PHP syntax — No syntax errors detected in /home/invest/public_html/cron/email-retry.php
✓P11: email-retry.php retries failed emails — cron/email-retry.php should contain: status = 'failed'
✓P11: email-retry.php has MAX_RETRIES cap — cron/email-retry.php should contain: MAX_RETRIES
✓P11: email-retry.php updates retry_count — cron/email-retry.php should contain: retry_count
136 passed, 29 failed out of 165 checks