Commit Graph

20 Commits

Author SHA1 Message Date
Anas Rashid
0511f7d2ee Monitoring: /health (site, API, database) for an uptime monitor; errors logged as one JSON line each by the API and the site; the API answers errors without internal details
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 19:30:09 +02:00
Anas Rashid
09336ead0e E-books: a poet's books as PDF, EPUB, text (DOCX made text) or archive.org items, uploaded with their own permission and approved like any change
- ebooks permission (create, per poet); the upload button only for L2/L1 moderators with it (and admins).
- Files kept by SHA-256 in DIVAN_FILES_DIR (ab/cd/<sha>.<ext>; one copy per file), up to 100 MB, kind read from
  the bytes; details in PostgreSQL indexed by poet and trigram (title, text of text books); search shows e-books.
- An upload is a revision (entity 'ebook') through L2 -> L1 -> admin; unpublished files only for moderators;
  approved details committed to divan-data (divan/<poet>/ebooks/<id>.txt).
- ای بکس on the poet page; /ebook/<id>: PDF in the browser viewer, EPUB with epub.js, text, archive.org embed.
- README: e-books and the file store (attach growable block storage or an S3 bucket via rclone).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 14:52:23 +02:00
Anas Rashid
542c4672c9 Tags (#52): typed tags on poets, books/chapters, works and couplets; tag pages; tag: in search
- Types موضوع، صنف، بحر، شخصیت، مقام، دور and free ٹیگ; a work's tag may be on one couplet (شعر n, from 1).
- Tagging is a revision (tags-category / tags-work) through the L2 -> L1 -> admin pipeline with the new 'tags'
  permission; publishing writes divan-data/divan/<url>.tags, commits it and updates the site; the import reloads them.
- Pages show tag chips (couplet tags under the couplet); /tag/<type>/<name> lists what carries a tag; /tags lists all.
- Search: tag:عشق / ٹیگ:"حب الوطنی" filters works (tagged work, couplet or book), matching tags shown as a group.
- Tag editor rows with suggestions, Urdu keyboard and Roman typing.
- Tests run one file at a time (they share Ghalib's ghazals); the library test picks a ghazal with three couplets.
- Mod buttons sit in a div (a form closes a p, which broke the row).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 14:42:19 +02:00
Anas Rashid
771ba54863 Home page sections (site permission): rename, add, remove and reorder sections; chosen poets; sort by hand, alphabetically or by timeline
- home_sections: chosen-poets sections (مقبول شعرا) and century sections (every poet born in that Hijri century,
  so new poets appear on their own); first use seeds the layout the home page had.
- New content type 'site' for grants (scope all, action edit); admins always. Changes apply at once and are audited.
- /mod/site editor (tab سرورق): names, ↑ ↓, remove, sort, add/remove/order poets with the Urdu name box.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 14:24:43 +02:00
Anas Rashid
93825fe5d9 Publishing commits to divan-data git (#34); public names only; 'last edited' on poems
- api/src/git.ts: each published version is a commit in the divan-data checkout (queued, one at a
  time): the moderator as author by public name with a placeholder email, the summary and version
  in the message, Reviewed-by / Approved-by / Divan-Revision / Divan-Version trailers;
  DIVAN_GIT_PUSH=1 pushes. The commit id is kept with the revision.
- Privacy fix: published files and commits carry public names (profile name, else 'موڈریٹر <id>'),
  never email addresses (divan-data is public).
- Poem pages: 'دیوان کا ورژن …' with who edited, reviewed and published, the date, and a link to
  the commit diff (DIVAN_DATA_COMMIT_URL).
- deploy/sync.sh: pull --rebase so publishing commits are kept.
- Admins are super moderators (documented).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 00:37:39 +02:00
Anas Rashid
19af91c594 Moderation: versions of works and the L2 -> L1 -> admin pipeline (#31, #51)
- revisions (a work's Divan text, summary, status, author/reviewer/publisher, the text it started from)
  and revision_events (who did what, with comments): the review thread and the moderation log.
- API (api/src/moderation.ts): what a moderator may do on a work, queue, drafts (one open draft per
  person and work), save, submit, approve, return/reject (reason required), publish; history; log.
  Rules come from the IAM grants: L2 drafts, an L1 covering the work reviews, an admin publishes; L1
  drafts go to the admin, admin drafts publish directly. Publishing numbers the version, writes it
  to divan-data (owned.ts) and updates the site; a draft based on an older version is refused (409).
- Line diff (api/src/diff.ts) against the text a draft started from.
- Site: ترمیم کریں / تاریخچہ on works, /mod (queue, activity log), /mod/rev/<id> (editor with the Urdu
  keyboard and Roman typing, diff, preview, actions, timeline), /mod/work/<id> (versions).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 00:31:47 +02:00
Anas Rashid
453659f5d1 Search: poets/writers and books separate from content; numbered pages; filter by authors with Urdu input
- Results in groups: شعرا و ادبا (by name or pen name, with years, work counts and a 'search in their
  works' link), کتابیں اور ابواب (books/chapters by title), and کلام (content).
- Content pages: numbered pagination (first, last, two either side, gaps) and 'نتائج ۴۱–۶۰ از ۸۱۱۶'.
- Author filter: chips for the authors the results come from, with counts; tick one or several to
  narrow; a name box finds any other poet/writer, with the Urdu keyboard and Roman-to-Urdu typing.
  The keyboard and Roman typing now work on any input marked data-urdu, not only the search box.
- API: poet=1,2 (several), authors with counts, poets and books on page 1 (api/src/search.ts).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 00:14:26 +02:00
Anas Rashid
55cc602815 Library: bookmarked phrases, and glyphs where the reader's marks are
- Select any part of a couplet or paragraph and press نشان (selection menu): the phrase is
  bookmarked and shown underlined with a small 🔖, also across the two misras; clicking it removes
  the bookmark (with a confirmation). Listed in the library as نشان زدہ عبارتیں.
- Contents lists show ♥ on favourite works and 🔖 on works holding bookmarks; book/section cards and
  poet cards (home) show 🔖 when they hold any. API: GET /api/library/marks; phrases in state and
  library; phrase kind validated against the couplet's text.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 23:48:42 +02:00
Anas Rashid
8f4a71530d Personal library and word collection (#24, #25)
- Save (♡) poets and works, bookmark (🔖) couplets and paragraphs, save words from the word sidebar
  or the selection menu (with the couplet they came from); notes on items.
- /library (میری لائبریری): the reader's name and bio, then favourite poets, works, bookmarked
  couplets and saved words, each with its full path (poet » book » section » work) and a link to
  the couplet (#cN anchors on poem pages); saved words open the word sidebar.
- API (api/src/library.ts), JSON + Bearer tokens so mobile apps (#44) can use it; deleting an
  account deletes its library. Signed-out readers are sent to sign-in.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 23:35:34 +02:00
Anas Rashid
d72c14f8bd Permissions (IAM): L2/L1 moderators and scoped grants (#29)
- Roles: reader, mod-l2, mod-l1, admin. Grants: scope (all, poet, book/section with everything in
  it, one work) x content (poets, books, works, dictionary) x actions (create, edit, delete,
  arrange); dictionary grants are site-wide. can() in api/src/permissions.ts is the one check.
- Admin API and pages: role dropdown on /admin; /admin/user/:id lists a moderator's grants, adds
  them (target by poet id or page link) and revokes them; demoting a moderator clears their grants;
  grant and revoke go to the audit log.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 23:13:06 +02:00
Anas Rashid
acf7767495 Admin panel: users, password reset on request, disable, roles, delete, audit log (#27)
- API (api/src/admin.ts, admins only): user list and search; password reset generates a temporary
  password shown once and ends the user's sessions; disable/enable (ends sessions, blocks sign-in);
  roles reader/admin; delete; an admin cannot disable, demote or delete themself. Every action is
  written to audit_log (kept when users are deleted).
- First admin from the server: npm run make-admin -- <email> (after signing up).
- Site: /admin (users) and /admin/audit; 'ایڈمن' link in the header for admins.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 23:08:19 +02:00
Anas Rashid
e409adc668 Accounts: email and password sign-up, sign-in/out, change password, delete account (#18)
- API (api/src/auth.ts): scrypt password hashes; random session tokens stored only as SHA-256;
  30-day sliding sessions; rate limits on sign-in (per IP and per email) and sign-up; changing the
  password signs out other devices; deleting the account removes its data.
- Site: /signup, /signin (returns to the page the reader came from), /account; header link; plain
  forms, no JavaScript needed. Session in an HTTP-only, SameSite=Lax cookie (Secure over HTTPS).
- CSRF: Astro's origin check, with the site's hostnames listed (SITE_HOSTS) so its own form posts
  pass and other sites' are refused.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 22:53:51 +02:00
Anas Rashid
19b68425f6 Word sidebar: readings by vowels, vowel variants, similar words; Persian/Arabic explained in Urdu
- readings: one spelling, different short vowels (ملک: مَلَک، مَلِک، مِلک، مُلک), each with form,
  transliteration, IPA, audio and meanings
- always: same consonants with other long vowels (consonant-skeleton regex)
- not found: inflection stems (آنکھوں -> آنکھ, جاتے -> جانا), prefix regex, trigram similarity
- Persian/Arabic words with no Urdu entry: Urdu translations via English first, then English, then
  their own language; filler glosses (especially, usually…) dropped
- punctuation, dashes and spaces dropped from selected words and lookup keys; clean titles

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 22:07:10 +02:00
Anas Rashid
ef618094d5 Word sidebar: select a word for its meanings and pronunciation from Wiktionary
Urdu, Persian and Arabic Wiktionaries in that order, each labelled; English meanings, IPA,
transliteration and audio from en.wiktionary; Urdu equivalents pivoted through English when Urdu
Wiktionary has no entry. Cached in PostgreSQL for 30 days. Left panel on wide screens, bottom
sheet on phones.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 21:38:10 +02:00
Anas Rashid
efb7aacde3 Search: highlighted matches, matching couplet or prose excerpt, exact phrase first; opened pages keep the highlight (?hl=)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 21:30:42 +02:00
Anas Rashid
9a2db49eab Radif per ghazal, matla/maqta labels, pen name set apart; contents grouped by radif letter
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 21:27:43 +02:00
Anas Rashid
17200fc9aa Show Gregorian (عیسوی) years alongside Hijri for poets
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 20:53:53 +02:00
Anas Rashid
d70e0a1fed Pinned poets on the home page (مقبول شعرا): Iqbal, Ghalib, Mir Taqi Mir, Mir Dard, Dagh
- poets.pin_order; editorial list in db/featured.sql, applied after every import
- home page shows the pinned row first, like Ganjoor
- Faiz is not included: his work is under copyright until 2035, so not in divan-data

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 20:42:33 +02:00
Anas Rashid
60f0791405 Divan v2: Astro site with Divan's own design (proof of concept)
- web/: server-rendered Astro over the Node API: home (poets by Hijri century), poet
  (intro + sections), category (numbered contents), poem (couplets, prev/next, source),
  search (paged); Naskh default with Nastaliq toggle, light/dark, Urdu digits, RTL, mobile
- api: section counts include nested categories
- README: how to run v2

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 20:26:54 +02:00
Anas Rashid
c450ec010a Divan v2: Node.js API + PostgreSQL (proof of concept)
- db/schema.sql: poets, categories, poems, verses; normalised search_text with pg_trgm index
- api/: Fastify + pg, Node native TypeScript (no build step)
  - import.ts: loads divan-data (folder or CDN) with upserts; full import in ~36 s
  - server.ts: /api/poets, /api/page?url=, /api/search (Urdu-normalised ILIKE), /health
  - urdu.ts (+ test): normaliser ported from the .NET version

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 20:24:20 +02:00