آيات الأرقم
AyyatAlArqam
تَعَاهَدُوا الْقُرْآنَ
هذا العمل خالص لوجه الله. اللهم ثبتنا على ذلك. This work is purely for the sake of Allah
بِسْمِ اللَّهِ الرَّحْمَٰنِ الرَّحِيمِ
كل ما تم تحديثه وإضافته في آيات الأرقم — منصة تتبع حفظ القرآن للعائلات والحلقات
عرض ٢١–٤٠ من أصل ١٦٥ إصدار
iPad PWAs stop launching to a black screen, and the dead bindings go.
Three public pages were missing from the sitemap. `/releases`, `/public` and `/sitemap` have answered 200 for months while being absent from `app/sitemap.ts`, so the only way Google could find them was by following a link — which is the job the sitemap exists to do instead. Eleven URLs there, fourteen now.
الوضع الداكن. A dark theme for the whole platform, with a toggle beside the language button.
One task list, on the dashboard. Pending work was being tracked in three places that had all drifted apart: `roadmap.md`'s seventeen pending features, `cleanup.md`'s audit checklist, and the AbuZaid Projects dashboard, which held three tasks. Keeping them in step was never going to happen, and the failure mode is not merely untidy — it is acting on the wrong one.
Cleanup, and three documents that were lying. Seven dead files deleted, two brand-colour violations fixed, and the two audit docs corrected where following them would have caused damage.
Rate limiting knows who is asking. Better Auth was logging that it could not determine a client IP and was "falling back to a single shared per-path bucket", which is a plain description of a real hole: **every visitor shared one sign-in limit**. One person retyping a forgotten password locked the sign-in form for everybody at once, and nobody's own attempts were counted against them in particular. Noticed in the logs while verifying v6.20.4, and reproduced immediately — a local run hit 429 on the third attempt from a single machine with the rate limiter treating the whole world as one caller.
Better Auth's session lookups retry too, which closes the last of this. v6.20.3 put a one-shot retry on every query the admin client makes and left the other pool untouched, for a structural reason rather than an oversight: Better Auth does not call `pool.query`. It hands the pool to Kysely, whose postgres driver takes a client out with `pool.connect()` and then calls `client.query(sql, params)` directly, so `runQuery` never sees a single one of those. A `getSession` arriving exactly as Neon suspended the compute still failed — and that is the query on the path of every signed-in navigation.
The first read after a compute suspend no longer fails. v6.20.2 stopped a dying connection from crashing the whole serverless instance, which is what was serving 500s to people on unrelated pages. It could not rescue the query that was actually holding that connection: `pg` rejects an in-flight query when its socket dies and does not try again elsewhere, so the request that happened to arrive as Neon suspended the compute still failed. Verifying that release caught it in the act — `ERROR [Better Auth]: Could not validate the database schema` immediately after the four discarded connections, with the next request fine.
The site answered 500 at random, and the reason was one missing event listener.
A word in the reader was drawn on top of itself, and the save bar sat on the screen edge.
The PWA opens on a splash instead of a black screen. A cold launch on a phone showed nothing at all for four to six seconds, then the splash for about a second, then the app. Four separate causes, each of which alone would have produced most of that.
The dashboard ships arranged. Nine cards had accumulated one release at a time, each appended where a new card belongs — at the end — so the shipped order was a record of the release history rather than an arrangement anybody chose, and every card arrived expanded. v6.7.0 gave the user the controls to fix that themselves; this makes the default worth keeping.
The show-password eye sat on top of the placeholder in English. `Input` positioned it with `left-0` and reserved room with `pr-10` — both physical directions, which only ever lined up in Arabic by accident: the eye landed at the visual left (the end of an RTL line) while the padding went to the right. Flip the page to English and the eye is at the start of the line, over the first characters of «Password», «At least 8 characters» and «Re-enter password» — all three fields of the sign-up form, which is the first screen anybody sees.
The platform is bilingual. Every user-facing surface outside the admin panel now reads in the reader's language, and `/landing-new` is gone.
`/features`, `/programs` and the program card speak both languages; `/landing-new` is deleted.
The language button works, and the chrome around every page speaks both languages. Phase one of making the platform genuinely bilingual.
«نقاط» instead of «خطوات» in the guide. Each section carried a badge counting its «خطوات», which was true of البداية and الدعوات and false of everything else: الأدوار والصلاحيات lists five roles and a note, الفلاتر والبحث lists what the filters do, لوحتي describes the panels. Numbering those as steps tells the reader to perform a sequence that does not exist, and the roles section shipped a release earlier made it obvious — «٦ خطوات» over a list of who can do what.
«الأدوار والصلاحيات» in the guide, and two roles that were lying about themselves.
`/admin/feedback` pages instead of loading every report. Same defect as the recipient picker, one page over: it selected the whole `feedback` table with no limit and filtered it in the browser, so every load carried every report ever sent — fine at nine, not at nine thousand — and the tab counts described the rows that happened to be loaded rather than the table.
The recipient picker stops loading every user. `/admin/messages` shipped a day old with `SELECT id, email, display_name, full_name FROM profiles` and no limit, rendered into a `<select>`: fine at two accounts, and at five thousand it is the entire user table in the page's HTML on every load, inside a dropdown nobody can find anybody in.