آيات الأرقم
AyyatAlArqam
تَعَاهَدُوا الْقُرْآنَ
هذا العمل خالص لوجه الله. اللهم ثبتنا على ذلك. This work is purely for the sake of Allah
بِسْمِ اللَّهِ الرَّحْمَٰنِ الرَّحِيمِ
كل ما تم تحديثه وإضافته في آيات الأرقم — منصة تتبع حفظ القرآن للعائلات والحلقات
عرض ٦١–٨٠ من أصل ١٦٥ إصدار
المواظبة and الأجزاء are paired and trimmed. Both shipped as full-width bands stacked one above the other, so the two new cards pushed the surah grid — the thing the dashboard is actually for — most of a screen further down.
Document the Data API schema cache, which broke progress saves the moment v6.2.0 shipped. Every save failed with «تعذّر حفظ التقدم. تحقق من اتصالك وحاول مرة أخرى.» — a connectivity message for something that had nothing to do with connectivity.
الأجزاء: juz coverage on the dashboard. Progress is stored per surah and the dashboard reported it that way — «١٧ سورة بدأتها» — but nobody describes their حفظ in surahs. They say how many juz they hold. The app could not express that number at all.
المواظبة: a consistency card on the dashboard. `progress_activity` has recorded every save since v3.1.0.0 with a `created_at`, and nothing ever read it except the paginated «آخر نشاطاتي» list. The dashboard could tell you how much you had memorized and never whether you were still at it.
مراجعة اليوم is a list you choose. The review card had no membership rule: every surah with any progress was due, forever, and the only way off the list was to review it. On a full mushaf that is 114 rows the user never asked for, and a surah being actively memorized sat in the revision queue alongside one finished years ago.
Admin user deletion works. Deleting a user from the admin panel failed with `relation "neon_auth.user" does not exist`, and the group-decision modal behind the alert sat stuck on «...Loading groups».
Track progress without a group. A new account could open the surah grid, tap a surah, set the ayahs, hit حفظ التقدم — and get «لا يمكن حفظ تقدمك لأن حسابك غير مرتبط بعضو» every time. Not a UI bug: `progress` carries a NOT NULL `member_id` and a NOT NULL `group_id`, so with no group there is no member and no row to write. The dead end was total, because the `student` role — what every account starts as — cannot create a group either. The only exit was for somebody else to send an invite. A user who signed up on their own had a fully rendered dashboard they could not use.
Remove the onboarding wizard. Registration already asked for the user's name, then `/onboarding` asked for it twice more: step two's "الاسم المعروض" was pre-filled from that same name, and "الاسم الحقيقي" sat empty right beneath it asking for the thing just typed on the previous screen. Breaking: a route and a column are removed.
Remove Vercel Analytics, which v5.0.0 said it had already removed. `<Analytics />` from `@vercel/analytics` was still mounted in the root layout, so it shipped on every page of every deploy since the migration.
Next.js 16.2.6 → 16.3.5. `npm audit` rated the installed range **critical**: eleven advisories against `next` alone, plus vulnerable `postcss`, `sharp` and `nanoid` pulled in beneath it.
Close an unauthenticated read of `/admin`. A GET with no cookies returned **200** and the full admin overview in the response body: every user's email, full name and uuid, plus the platform stat block. `/admin/users` leaked the same. A browser showed only a flash before the page's `<meta http-equiv="refresh">` bounced it to `/login`, so the hole was invisible to anyone clicking around — but `curl`, view-source and any crawler read the payload straight out of the HTML. Confirmed against the deployed site, not just locally.
Password change works. The profile card called `updateUser({ password })`, which Better Auth has no equivalent for — Supabase changed a password from an authenticated session alone, Better Auth requires proof of the current one. The form never collected it, so the card could not succeed under any input.
رسالة العودة: the message no longer changes while you are reading it. `InactivityModal` picked one with `Math.random()` directly in the render body, so every re-render of the dashboard — which re-renders often — rolled a new message. It is now chosen once per mount via a `useState` initializer.
Email verification and transactional mail. Disabling Neon Auth removed its shared sender, leaving the app with no email provider at all: password reset silently did nothing and no address could be verified. Adds a Resend sender (`lib/auth/email.ts`) with Arabic RTL templates for verification and password reset, wired into Better Auth via `sendResetPassword` and `emailVerification.sendVerificationEmail`, with `sendOnSignUp` on. `ayyatalarqam.com` is verified in Resend (eu-west-1) — DKIM, SPF and return-path.
Self-hosted Better Auth; Google sign-in works. Under Neon's Managed Better Auth, Google OAuth completed successfully — users, sessions and profile rows were all created — but the app never saw a session and bounced the user back to `/login`. The cause was structural: the managed service runs the whole handshake on its own domain, the `redirect_uri` is generated by Neon and not configurable, the OAuth state cookies are bound to that domain, and the session cookie is created there. The app is handed back a bare redirect with no code and no token, so there is nothing to exchange for a first-party session. There is no bridge either — no one-time-token endpoints, `get-access-token` returns only provider tokens, and the service ignores the `idToken` flow. Email/password was unaffected because it goes through the app's own `/api/auth` proxy, which re-scopes the `Set-Cookie`.
Migrated off Supabase and Vercel onto Neon and Netlify. Breaking: every database, auth and hosting dependency changed.
Switched version numbering from the custom 4-digit `vA.B.C.D` scheme to standard semantic versioning. MAJOR is now reserved for breaking changes (architecture overhauls, data-invalidating migrations, removed features/routes), MINOR for backwards-compatible functionality, PATCH for backwards-compatible fixes. Old entries keep their 4-digit numbers — rewriting them would collide, since `v3.6.3.0` and `v3.6.3.1` are separate releases that both collapse to `3.6.3`. The `/releases` parser now accepts 3- and 4-segment versions and derives its gold/teal/muted tier badge from whichever scheme an entry uses.
AppHeader redesign. The bar carried 14 targets at roughly equal weight, so nothing read as primary. Now:
الأهداف: dropped the "العضو" selector from the add-goal form. `GoalsPanel` was written for a group context where an owner picks which member a goal belongs to, but the dashboard card is scoped to your own member — so the select held one real option that was already pre-selected, and its only usable interaction was choosing the blank entry, which disabled حفظ. Goals now always target the card's member. Removed the unused `goals.member` / `goals.selectMember` keys from both locales.
الأهداف: "إضافة هدف" is a real button now — solid teal pill (`bg-[#0D5466]`, `rounded-xl`, white text, `hover:bg-[#619B8A]`) instead of bare teal text, matching the راجِع button in the review card.