Commit Graph
43 Commits
Author SHA1 Message Date
Hamza-Ayed b76eccb763 إصلاح أخطاء شاشة الكباتن من تحديث الذكاء الاصطناعي 2026-07-27 00:25:02 +03:00
Hamza-Ayed e269cb9b70 إصلاح أخطاء شاشة الكباتن من تحديث الذكاء الاصطناعي 2026-07-26 13:44:07 +03:00
Hamza-Ayed 330dfc6dba إصلاح أخطاء شاشة الكباتن من تحديث الذكاء الاصطناعي 2026-07-26 13:15:45 +03:00
Hamza-Ayed 4b5235c35c إصلاح أخطاء شاشة الكباتن من تحديث الذكاء الاصطناعي 2026-07-26 12:18:23 +03:00
Hamza-Ayed 16feb51a75 إصلاح توافق فلاتر مع Theme الجديد 2026-07-26 11:36:26 +03:00
Hamza-Ayed 3af99cc18a إصلاح توافق فلاتر مع Theme الجديد 2026-07-26 11:33:20 +03:00
Hamza-Ayed 7830efead7 إصلاح توافق فلاتر مع Theme الجديد 2026-07-26 04:28:09 +03:00
Hamza-Ayed ca6cb7a3fe تصميم عالمي جديد، وإصلاح الخرائط ومراقب السيرفرات 2026-07-26 04:21:42 +03:00
Hamza-Ayed f325ffce42 تصميم عالمي جديد، وإصلاح الخرائط ومراقب السيرفرات 2026-07-26 04:02:10 +03:00
Hamza-Ayed c43f801542 إصلاح الشاشة البيضاء ومسار base-href 2026-07-26 03:26:15 +03:00
Hamza-Ayed 2bacb1b9e1 تحديث شامل للوحة التحكم وإضافة كافة الميزات للـ WebSidebar 2026-07-26 03:22:47 +03:00
Hamza-Ayed 5ec54c03f5 تحديث شامل للوحة التحكم وإضافة كافة الميزات للـ WebSidebar 2026-07-26 02:58:59 +03:00
Hamza-Ayed a954f49307 Update: 2026-07-26 02:51:53 2026-07-26 02:51:54 +03:00
Hamza-Ayed 1dfc302a4f Update: 2026-07-26 01:03:40 2026-07-26 01:03:41 +03:00
Hamza-Ayed e03b9c30d5 Update: 2026-07-25 18:43:44 2026-07-25 18:43:44 +03:00
Hamza-Ayed 8d3e63d1c7 Update: 2026-07-25 18:40:38 2026-07-25 18:40:38 +03:00
Hamza-Ayed 4bbc687c15 Update: 2026-07-25 18:28:30 2026-07-25 18:28:31 +03:00
Hamza-Ayed 5e103f60f2 Update: 2026-07-25 18:19:51 2026-07-25 18:19:52 +03:00
Hamza-Ayed 27369b8ac1 Update: 2026-07-25 18:05:37 2026-07-25 18:05:37 +03:00
Hamza-AyedandClaude Opus 5 3fb7bc5190 Show the build id, tame long table cells, and add purposeful motion
The build identifier now sits in the sidebar footer. "Is my deploy actually
live?" was only answerable by opening Session & Security, which is the wrong
place for the first question asked after every deploy.

Error-log rows carry stack traces and full URLs. They stretched their row far
past the viewport and pushed the other columns out of view, which is exactly
where the console is least usable. Values over 70 characters truncate and
expand on click.

Motion is limited to two things that mean something: content arriving
(staggered, so a grid resolves instead of snapping), and a fetch being in
flight — the refresh control spins and the status pill pulses, so a section
that legitimately returns nothing still shows that it tried. All of it is
disabled under prefers-reduced-motion.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-25 17:49:48 +03:00
Hamza-Ayed f9110a7d92 Update: 2026-07-25 17:40:28 2026-07-25 17:40:29 +03:00
Hamza-AyedandClaude Opus 5 a0812dbd10 Fix broadcast delivery; make transit organisations manageable
Broadcasts never reached anyone. The internal FCM call defaulted to
127.0.0.1, which inside the php container is the php container itself — the
web server runs in a separate nginx container, reachable by service name on
the Compose network. Every send failed the curl and returned a generic 502.
The default now points at nginx, the URL is overridable via FCM_INTERNAL_URL,
and the error carries the actual reason and target instead of a bare status.

Transit organisations were a read-only count table with nothing to act on.
The module now supports the operations an admin actually needs:
- open an organisation for its counts, routes, recent trips and admins
- create one, including the founding administrator create.php requires
- edit city, contact details, contract status and trial end, with a
  confirmation when the contract changes since suspending cuts off service
- add an administrator, and enable or disable an existing one

Verified end to end against the endpoints' real payload shapes, including
that an incomplete create form is rejected before any request is sent.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-25 17:10:51 +03:00
Hamza-AyedandClaude Opus 5 bc1b0129e8 Fix v2 analytics status matching; give Growth and Analytics real charts
Eight queries across the v2 modules counted only status = 'Finished' and so
reported zero on live data, where the current ride pipeline writes
'completed': realtime revenue for today and yesterday, financial stats,
settlements, driver scorecard, driver ranking, and both revenue queries. All
now match either spelling.

Growth and Advanced Analytics rendered through the generic shape-detecting
renderer, which produced raw tables that said little. Both now have purpose-
built views:

- Growth: totals, 30-day joins, and a two-series daily chart. growth.php only
  returns days that had signups, so the series is expanded to a continuous
  30-day axis with explicit zeros — plotting the returned rows directly would
  hide the gaps and make a quiet month look like steady growth. A caption
  states how many days actually had a signup.
- Analytics: revenue summary tiles, a daily revenue trend, and the captain
  ranking, with a note explaining that platform share is what remains after
  the captain's cut.

Null aggregates render as "—" rather than 0.00, and markers are drawn only on
days with a value so a flat zero line stays readable.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-25 16:55:58 +03:00
Hamza-AyedandClaude Opus 5 6802026dbd Add blind-index search layer; fix captain detail 200-with-empty-body
Searching encrypted columns currently works only because encryptData() is
AES-CBC with a fixed IV, i.e. deterministic. That determinism is what leaks
equality and shared prefixes, and it is why moving storage to AES-GCM would
break every lookup. This separates the two concerns.

- core/Security/BlindIndex.php: HMAC-SHA256 over a normalised value, keyed by
  a secret pepper. Phone numbers have a small keyspace, so a bare SHA-256
  would be reversible by enumeration; the pepper lives in the environment, not
  the database. The scope string includes table and field so the same number
  does not produce a matching index across tables.
  Normalisation unifies local/international phone forms, lowercases emails and
  folds Arabic alef/ya/ta-marbuta and diacritics for names.
- migrations/: nullable *_bidx columns plus indexes, and the missing
  adminUser.status/approved_by/approved_at columns that admin approvals need.
- scripts/backfill_blind_index.php: restartable, batched, --dry-run capable,
  touches only index columns.
- Admin lookups by phone/email now match the index, keeping the old ciphertext
  comparison in the same query so search keeps working until the backfill runs.
  bootstrap exposes $blindIndex as null when no pepper is configured.

Also: AdminCaptain/getCaptainDetailsById.php selected driver.education, a
column absent from this schema. The PDOException was uncaught, so the client
received an empty body with HTTP 200 — the "non-JSON response" seen when
opening a captain. It now omits the column, catches the error, reports it as
JSON, and requires an admin role.

Console: opening any sidebar section refetches its data instead of showing
what was loaded when the console started.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-25 15:16:09 +03:00
Hamza-AyedandClaude Opus 5 81ee2acefd Add removal/blacklist tools, Arabic UI, and a persistent sign-in error
Authorisation: driver/deleteCaptain.php permanently deletes a captain and had
no role check at all — any valid token, including a driver's or passenger's,
could delete captains. It now requires super_admin. The two unblacklist
endpoints had no role check either and now require an admin role.

Console:
- Blacklist & removal screen (super admin only): current blocks, permanent
  removal, and lifting a block. Deletion additionally requires the phone
  number to be retyped, because the row is deleted outright.
- Arabic interface with full RTL layout and a language toggle. Sidebar,
  content offset, input affordances, toasts and directional icons all mirror;
  numbers, identifiers and the diagnostics output stay LTR.
- Sign-in failures now render in the form and stay there. They were only
  shown as a toast, which disappears before it can be read — a locked
  account or a rejected device looked like the page simply returning to
  the login screen with no explanation.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-25 14:53:26 +03:00
Hamza-Ayed 42f6d33efd Update: 2026-07-25 14:44:30 2026-07-25 14:44:30 +03:00
Hamza-AyedandClaude Opus 5 4009af8dd3 Add campaign launcher and app version manager; fix SQL injection in updatePackages
serviceapp/updatePackages.php built its UPDATE by interpolating the request
values straight into the SQL string, so any caller with a valid token could
execute arbitrary SQL through the version field. It now uses bound
parameters, requires an admin role, validates the version format, and writes
an audit entry.

trigger_campaign.php gains dry_run=1: it performs the same Gemini analysis
and target selection but returns before creating the promo code and before
dispatching any notification. Launching without previewing was the only
option before, and a launch writes a seven-day discount and pushes to every
passenger in the country.

Console:
- Campaign launcher with a mandatory preview. Launching stays disabled until
  the current parameters have been previewed, and re-locks if any parameter
  changes afterwards or once a launch completes.
- App version manager with the same version-format check as the server and a
  confirmation naming the old and new values.

Cache busting: assets are served straight off a bind mount with no version,
so browsers kept running the previously cached build after a deploy. Both
asset links now carry ?v=, and the build id is shown in Session & Security
and printed in the diagnostics report.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-25 14:41:27 +03:00
Hamza-AyedandClaude Opus 5 67f55e5192 Add driver document review and staff onboarding
Driver documents: paged list from auth/driver/drivers_pending_list.php, a
detail panel showing each uploaded document as a thumbnail linking to the
full image, and activation via Admin/driver/updateDriverFromAdmin.php. The
confirmation states how many documents were reviewed and warns explicitly
when a captain has none on file, since approving then activates an
unverified account.

Details are requested as a POST body. The mobile app calls this endpoint as
GET "?id=", which filterRequest() never reads, so its detail lookup cannot
be receiving an id at all.

Staff: pending admin/service accounts with per-account activation via
Staff/activate.php, the employee list, and a creation form posting to
Staff/add.php. Administrator accounts are offered only to super admins,
matching add.php's own check; passwords are rejected below 8 characters and
cleared from the form after submission.

Both screens mask phone numbers for plain admins and never render
token/password/fingerprint fields.

Also stop .btn-primary stretching to full width when used inline in a card
header — it is styled for the login form.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-25 14:30:49 +03:00
Hamza-AyedandClaude Opus 5 a0ab6c5155 Add broadcast notifications and transit route approvals
Broadcast: ride/firebase/send_fcm.php is an internal service guarded by a
shared secret, so the browser cannot call it — holding that key client-side
would expose it, and the endpoint cannot tell who the sender is. A new
Admin/notifications/broadcast.php sits in front of it: it runs behind
connect.php, requires super_admin, restricts the target to the two topics the
apps actually subscribe to ('drivers'/'passengers') so it cannot be used to
push to an arbitrary topic or a single device token, bounds the title and
body, writes an audit entry before dispatching, and only then forwards the
call internally with the shared secret.

The composer shows a live push preview and an explicit confirmation naming
the audience, since a broadcast cannot be recalled.

Route approvals: draft routes render with their stops, distance and stop
count, and approve/reject posts to transit/route/approve.php behind a
confirmation stating the consequence. Available to admins and super admins,
matching the endpoint's own role check.

Also render user-supplied text with unicode-bidi: plaintext — Arabic names,
addresses and messages were being laid out left-to-right inside the
English UI.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-25 02:15:02 +03:00
Hamza-AyedandClaude Opus 5 41a06bba0c Add fleet, invoice, promo and lookup-driven admin modules
Brings the console to 18 modules across 26 navigation entries.

- Fleet performance (best captains, per-captain card charges), invoice
  totals and promo codes as read-only panels.
- Ride monitor: monitorRide.php and getDriverGiftPayment.php answer only for
  a given phone number, so they get an input rather than a panel that would
  render an error on load.
- Status-like values in generated tiles use the same label mapping as the
  tables, so raw values such as cancelled_by_passenger no longer leak into
  the UI.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-25 02:02:08 +03:00
Hamza-AyedandClaude Opus 5 db4ca7dd7a Fix dashbord.php parse error; require super_admin on pricing and crypto tools
Hotfix: a comment added to the dashboard SQL contained double quotes inside
the double-quoted PHP string, terminating it and making dashbord.php fail to
parse. Production was returning a parse error for every dashboard request.

Authorisation gaps closed — connect.php only proves a token is valid, it does
not check what the caller is allowed to do:

- Admin/ggg.php decrypts any database field and was authorised solely by an
  admin phone number sent in the request body. Anyone who knew a listed
  number could decrypt platform data without signing in. It now runs behind
  connect.php, requires super_admin, keeps the phone list as a second factor,
  and records every use.
- ride/kazan/update.php, kazan/add.php and ride/promo/{add,update,delete}.php
  changed live pricing and discount codes with no role check at all, so any
  valid token — including a driver's or passenger's — could rewrite the fare
  table. All now require super_admin.

Staff/pending.php: adminUser has no `status` column in this deployment, so
the query failed with an opaque "unavailable". It now checks for the column
and reports the actual reason.

Console: Kazan tariff editor for super admins — sends only changed fields,
shows an old → new confirmation before saving, and stays read-only with an
explanatory notice for plain admins.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-25 02:00:14 +03:00
Hamza-AyedandClaude Opus 5 852c6ece5c Fix admin status handling for the current ride pipeline; extend console
The ride table holds two generations of status values: the legacy CamelCase
set ('Finished', 'CancelFromPassenger') and the lowercase set written by
backend/ride/rides/* today ('completed', 'cancelled_by_passenger'). Admin
queries only matched the legacy set, so on live data:

- get_rides_by_status.php returned nothing meaningful for every filter, and
  the "in progress" default masked it.
- dashbord.php reported total_driver_earnings as NULL, completed_rides as a
  fraction of the real count, and cancelled_rides as 0.
- driver_avg_duration averaged in negative durations, yielding "-00h 22m".

All three now match on LOWER(status) across both families.

Staff/pending.php ran with no authentication at all, exposing pending
admins' names and phone numbers to any caller; it now goes through
connect.php with a role check. It also returned HTTP 400 for everything when
the `users` table was absent — each source is queried independently and
reports its own availability.

Console:
- Render rides from either schema generation (price/date/time and
  start_location coordinates, or the older address/created_at columns).
- Null aggregates render as "—" rather than a measured 0.00.
- Add tariff/promo, WhatsApp send and encryption modules, all super-admin
  gated; pricing remains read-only.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-25 01:47:55 +03:00
Hamza-Ayed 915a148ebf Update: 2026-07-25 01:38:11 2026-07-25 01:38:11 +03:00
Hamza-Ayed 0d9095fd3f Update: 2026-07-25 01:16:32 2026-07-25 01:16:33 +03:00
Hamza-Ayed eda7018434 Update: 2026-07-25 01:02:01 2026-07-25 01:02:02 +03:00
Hamza-Ayed 822cb5963a Ensure Live Backend mode is enforced and clear old Demo localStorage session 2026-07-25 00:44:11 +03:00
Hamza-Ayed 8ec7b9aae6 Bind live MySQL database tables (Rides, Passengers, Pending Approvals) into Siro Admin Portal 2026-07-25 00:41:18 +03:00
Hamza-Ayed c9168c1c80 Enhance Siro Admin Dashboard with live backend API database bindings 2026-07-25 00:33:32 +03:00
Hamza-Ayed 9e2964d307 Allow email and ID login in Admin auth login.php and bind web device fingerprint 2026-07-24 23:38:17 +03:00
Hamza-Ayed b3126013f5 Update: 2026-07-24 23:31:37 2026-07-24 23:31:37 +03:00
Hamza-Ayed 5ebff42841 Update: 2026-07-24 23:23:54 2026-07-24 23:23:55 +03:00
Hamza-Ayed 917dfc025f Update: 2026-07-24 22:57:32 2026-07-24 22:57:32 +03:00
Hamza-Ayed 0b24bc21b6 Update: 2026-07-24 22:55:34 2026-07-24 22:55:34 +03:00