# دليل الأحكام — Dalil Al-Ahkam
**Semantic search over authenticated hadith collections of Islamic rulings** — ask a jurisprudential question in Arabic, get the exact hadith text with its book, volume, page and isnād, plus an optional grounded AI summary with citations. Every hadith shown is fetched **verbatim from the database** — never generated by AI.
> مشروع بحث دلالي في أحاديث الأحكام: اسأل بطريقتك (عامية، موقف واقعي، أو قصة) فيفهم النظام المقصد الفقهي، ويسترجع لك نص الحديث حرفياً وموضعه من المصدر المعتمد مع خلاصة مستندة إلى الأدلة وحدها.
---
## Why this project
Generic chatbots **hallucinate hadith texts and rulings** — an unacceptable failure mode for religious sources. Dalil Al-Ahkam solves this with a strict retrieval pipeline:
- **The AI never writes hadiths.** It only reorders database rows and summarizes them. The hadith cards in the UI are verbatim `SELECT` results from PostgreSQL (`lib/ai/pipeline.ts` step 5a).
- **Real corpus, real citations:** authenticated books (المحرر في الحديث، عمدة الأحكام الكبرى) — 2,656 rows, 2,213 searchable hadiths with volume/page numbers and full sanad chains.
- **Cost-transparent:** every answer displays its estimated USD cost and latency.
- **Hadiths-only by default:** `RAG_ANSWER_ENABLED=false` — the reranked hadith list with citations is the whole answer (no AI summary box); flip to `true` for a grounded summary.
## The pipeline (6 steps, ~$0.002 per request)
```
[1] User question (Arabic, juristic language)
│
[2] Query rewriter — light LLM Google gemini-3.5-flash-lite
│ long question → short search phrase (falls back to original on failure)
▼
[3] EMBEDDING + cosine search Cloudflare @cf/baai/bge-m3 (1024 dims)
│ pgvector `<=>` over 2,213 hadiths → top 30 candidates
▼
[4] RERANKER vs ORIGINAL question Cohere rerank-multilingual-v3.0
│ → top 3; cosine < 0.40 hidden as irrelevant
▼
[5] DIRECT database fetch Prisma Postgres (pgvector)
│ text, sanad, hukm, book/volume/page — verbatim rows, never AI text
▼
[6] Grounded summary + [n] citations Google gemini-3.5-flash-lite (OPTIONAL)
│ OFF by default (RAG_ANSWER_ENABLED=false) → hadiths-only answers;
│ set true to restore the «الخلاصة» box — answer ONLY from attached hadiths
▼
[7] Persist run (SearchQuery + SearchResult) → UI shows hadiths, cost, latency
```
Graceful degradation at every stage — a missing key or a failing provider never blocks the request.
## Cost per request (shown live in the UI)
| Stage | Model | Price | Typical/request |
|---|---|---|---|
| Rewrite | `gemini-3.5-flash-lite` (Google) | flash-lite tier | ~$0.0001 (set `COST_REWRITE_USD_PER_MTOK` to count it) |
| Embed | `@cf/baai/bge-m3` | $0.0118 / 1M tok | ~$0.0000002 |
| Rerank | `rerank-multilingual-v3.0` | $2.00 / 1K searches | $0.0020 |
| Answer | `gemini-3.5-flash-lite` (optional, off by default) | flash-lite tier | $0.00 when `RAG_ANSWER_ENABLED=false` |
| **Total** | | | **≈ $0.002** |
One-time corpus embedding (2,213 hadiths ≈ 0.25M tokens): **≈ $0.003**.
## Tech stack
- **Next.js 16** (App Router) · React 19 · TypeScript (strict)
- **PostgreSQL 16 + pgvector** (`vector(1024)`, HNSW cosine index) via **Prisma 7**
- **Tailwind CSS v4** · shadcn-style UI · bilingual AR/RTL (default) + EN/LTR · dark & light themes · fully responsive (mobile-first)
- Providers: **Cloudflare Workers AI** (embeddings) · **Cohere** (reranking) · **Google AI Studio / Gemini** (LLM: rewriter + optional summary) — each model independently configurable via env vars
## Features
- 💬 Chat-style ask page with starter prompts and typing indicator
- 📚 Book scope filter (search all sources or one book)
- 🕐 Per-answer **estimated cost ($)** and **latency (s)** meta line
- 🗄️ "Hadiths are fetched verbatim from the database" note on every answer
- 🤖 Hadiths-only by default (`RAG_ANSWER_ENABLED=false`) — no AI summary box; set `true` for a grounded summary with [n] citations
- 🧾 Result cards: rank, topic, hadith text, citation, **sanad chain visual**, hukm + scholar, alternative rulings, PDF link, txt export
- ⭐ 5-star relevance rating · 🔖 save to folders · 🚩 report a wrong result
- 🗂️ Workspace: search history + saved hadiths (server + localStorage)
- 🛠️ Manager page: activate/suspend books, update editions
- 📊 Report page + `GET /api/health` (DB + providers + corpus status)
## Quick start
```bash
# 1. Install
npm install # (postinstall runs `prisma generate` for you)
# 2. Configure — fill the THREE keys (see .env.example, every var commented)
cp .env.example .env
# 3. Database (needs Docker)
npm run db:up # PostgreSQL + pgvector
npm run db:generate # Prisma client
npm run db:migrate # apply migrations
# 4. Load the corpus
# a) mock corpus (fast demo): npm run db:seed
# b) REAL corpus (recommended): python scripts/sync_shamela.py
# (or pg_restore from a dump — see docs/DATABASE.md)
# 5. Embed the corpus with the SAME provider as the queries
npm run db:embed
# 6. Run
npm run dev # → http://localhost:3000
```
Verify the full pipeline end-to-end:
```bash
npx tsx scripts/verify-pipeline.ts "ما حكم النية في الوضوء؟"
npx tsx scripts/verify-cloudflare-embed.ts # embeddings only, no DB
curl localhost:3000/api/health # DB + providers + corpus
```
## Environment variables
Everything is documented inline in **[`.env.example`](./.env.example)** — the three required keys:
| Variable | Provider | Where to get it |
|---|---|---|
| `EMBEDDING_API_KEY` | Cloudflare Workers AI | dash.cloudflare.com → Workers AI → API token |
| `RERANKER_API_KEY` | Cohere | dashboard.cohere.com → API keys |
| `LLM_API_KEY` | Google AI Studio (Gemini) | aistudio.google.com/apikey (starts with `AIza…`) |
Optional: `OPENROUTER_API_KEY` fills any empty `*_API_KEY` if you switch a base URL back to OpenRouter.
Tuning defaults: `RAG_RECALL_K` (30) · `RAG_FINAL_K` (3) · `RAG_MIN_SCORE` (0.40) · `QUERY_REWRITE_ENABLED` (true) · `QUERY_REWRITE_MIN_LENGTH` (0 = always rewrite) · `RAG_ANSWER_ENABLED` (**false = hadiths-only**) · `COST_*` price overrides.
## npm scripts
| Script | Purpose |
|---|---|
| `npm run dev` / `build` / `start` | Next.js dev / production build / serve |
| `npm run db:up` / `db:down` | start/stop PostgreSQL + pgvector (Docker) |
| `npm run db:generate` / `db:migrate` | Prisma client / migrations |
| `npm run db:seed` | mock corpus (auto-skips if a real corpus exists) |
| `npm run db:embed` | backfill BGE-M3 embeddings (NULL rows only) |
| `npm run db:reembed` | **reset + re-embed all** — REQUIRED after any embedding-provider switch |
| `npm run db:studio` | browse data in Prisma Studio |
| `npm run lint` | ESLint |
## API
| Method | Route | Purpose |
|---|---|---|
| `POST` | `/api/ask` | `{question, bookId?, userId?}` → answer + top-3 hadiths + cost + latency |
| `GET` | `/api/books` | book list for the scope filter |
| `GET` | `/api/health` | DB + providers + corpus health |
| `POST` | `/api/ratings` · `/api/reports` | 5-star rating · report a bad result |
| `GET` | `/api/history` · `GET/POST /api/folders` | workspace data |
| `PATCH` | `/api/manager/books` | book status/edition updates |
## Deploying to Vercel
1. **Remote database** — the corpus is already live on **Prisma Postgres**
(`pooled.db.prisma.io`, pgvector 0.8.1 enabled, restored + embedded
2026-10-06): 2 books · 2,656 rows · 2,213 searchable, all embedded.
Set that URL as `DATABASE_URL`.
⚠ Do **not** run `npm run db:migrate` against it — the schema was
restored via `pg_dump` and has no `_prisma_migrations` history.
2. Set the three keys + tuning vars in Vercel env settings
3. `vercel deploy` — `/api/ask` sets `maxDuration = 60` (Hobby; 300 on Pro)
4. Nothing else to remember: `postinstall` runs `prisma generate` on every
Vercel build (the generated client at `lib/generated/` is gitignored, so
it must be regenerated in CI)
Full guide: **[`docs/DATABASE.md`](./docs/DATABASE.md)**
## Project layout
```
app/ # App Router pages (+ _components per page) + api routes
components/ # ui primitives · common · layout
lib/ai/ # pipeline · providers · costs · embed/rerank · llm · rewrite
lib/ # i18n · workspace (folders/history) · mock · utils
prisma/ # schema · migrations · seed · embed
scripts/ # sync_shamela.py (corpus) · verify-pipeline.ts · verify-cloudflare-embed.ts
types/ # shared TypeScript types
```
## Honest limitations (MVP)
- Corpus = 2 books / 2,213 searchable hadiths (extensible via `scripts/sync_shamela.py`)
- Ratings/reports/folders persist but auth is a UI mock (Google OAuth + TOTP screens only)
- The AI summary is a convenience; the hadith cards are the source of truth
---
## تحدي الذكاء الاصطناعي في خدمة المحتوى الإسلامي — التماهي مع المتطلبات
### المسار المستهدف
**المسار 01 — الحوار المعرفي وإجابات موثوقة**، بعناصر قوية من **المسار 04 — أدوات المعرفة والتحقق للمتخصصين** (مطاردة المصدر، الحد من الهلوسة).
### كيف يحقق المشروع المعايير المرجعية
| المعيار المطلوب | تنفيذه في دليل الأحكام |
|---|---|
| كل معلومة تُعزى لمصدرها | كل حديث يُعرض بكتابه وطبعته وجزئه وصفحته ورقمه + رابط PDF |
| تمييز السنة الصحيحة | المتن مأخوذ حرفياً من قاعدة بيانات مصنفة من **المكتبة الشاملة (shamela.ws)** — أحد المصادر المعتمدة في المرجعية |
| لا فتاوى شخصية ولا أحكام اجتهادية | النظام **يسترجع فقط ولا يولّد فتاوى**؛ الحكم المعروض هو حكم المحقق في المصدر، مع «أقوال أخرى» عند الاختلاف |
| إجابة موثوقة أو إحالة | عند عدم كفاية الأدلة (< 30% صلة) يُعلن النظام عدم وجود أحاديث مطابقة واقتراح صياغة أدق — ولا يخترع |
| الشفافية: التصريح باستخدام الذكاء الاصطناعي | ملخص الذكاء الاصطناعي منفصل وموسوم، وملاحظة صريحة تحت كل إجابة: «نصوص الأحاديث من قاعدة البيانات مباشرة ولا ينشئها الذكاء الاصطناعي» |
| التخصص: لا استنتاجات شرعية/نظامية | مرحلة «الخلاصة» تعتمد حصراً على الأحاديث المرفقة مع أرقام الإحالة [n]، وممنوعة من الاستدلال خارجها |
| الحد من الهلوسة | قلب المنتج هو الاسترجاع (embedding + rerank) — النص الظاهر للمستخدم صفّ قاعدة بيانات وليس توليداً |
| لا بيانات شخصية | لا جمع لأي بيانات شخصية |
| تعدد اللغات في الواجهة | واجهة ثنائية عربية (RTL افتراضياً) / إنجليزية |
### مستويات الضبط في الإجابة
النظام يعمل ضمن المستويين (أ) و(ب) من المرجعية — **إجابات موثوقة من المصادر المعتمدة مباشرة** — ولا يقترب من المستوى (د) (الفتاوى الشخصية والأحكام الاجتهادية) بنيوياً.
---
## تسليم المشروع النهائي — آلية التسليم على منصة التحدي
> المنصة: `islamicaich.org` (تحدي الذكاء الاصطناعي في خدمة المحتوى الإسلامي — باتل BATHEL).
> هذا القسم يلخص **كل ما يلزم لجاهزية التسليم**.
### المنصة والحساب
1. الموقع: `islamicaich.org` → «تسجيل الدخول» → لوحة التحكم `islamicaich.org/dashboard`
2. اللوحة تعرض: «لوحة التحكم / مرحباً بعودتك»، عدّاد **الوقت المتبقي على نهاية التحكيم النهائي**
(يوم / ساعة / دقيقة / ثانية)، وبطاقة **الانضمام إلى قناة التحدي عبر ديسكورد**
(إلزامي عملياً: كل الإعلانات والدعم الفني والإرشاد المباشر تمر عبرها).
3. بطاقة **بيانات المشاركة**: اسم الفريق + المسار + وصف المشروع + ملف الفكرة،
وزر **«تسليم المشروع»**.
### نموذج «تسليم المشروع النهائي» (`/dashboard/submission/11/create`)
كل الحقول التالية **إلزامية (*)**:
| # | الحقل في المنصة | المطلوب من فريقنا |
|---|---|---|
| 1 | اسم المشروع * | **دليل الأحكام — Dalil Al-Ahkam** |
| 2 | وصف المشروع * | بحث دلالي عربي في أحاديث الأحكام: سؤال فقهي → نص الحديث حرفياً من قاعدة البيانات مع موضعه (الكتاب/الجزء/الصفحة) والسند والحكم + خلاصة ذكية موثقة بالإحالات |
| 3 | مسار التحدي * | **المسار 01 — الحوار المعرفي والإجابات الموثوقة** (بعناصر من المسار 04 — أدوات المعرفة والتحقق للمتخصصين) |
| 4 | عرض تقديمي للمشكلة والحل وآلية العمل * | ملف `PDF/PPT/PPTX` بحد أقصى **10MB** — المولّد من هذا الريبو: [`docs/dalil-al-ahkam-presentation.pptx`](./docs/dalil-al-ahkam-presentation.pptx) (انظر `docs/PRESENTATION.md` للمحتوى الجاهز للنسخ) |
| 5 | رابط فيديو توضيحي لا يتجاوز دقيقتين * | رابط YouTube عام/غير مدرج (≤ 2:00) — سكربت مقترح: 0:00 المشكلة (هلوسة النماذج) → 0:30 الحل (يسترجع ولا يولّد) → 1:00 ديمو حي لسؤال فقهي → 1:40 الأثر والتكلفة |
| 6 | الكود المصدري مستودع GitHub * | رابط الريبو العام (هذا المستودع) |
| 7 | رابط مباشر للحل live demo * | رابط النشر على Vercel (يُملأ بعد `vercel deploy`) |
زر **«حفظ وارسال»** (و«العودة» للمسودة). بعد الإرسال تظهر رسالة **«تم الحفظ بنجاح»**
وجدول **التسليمات**: المرحلة (التحكيم النهائي) · رقم الفريق · التقديم بواسطة ·
تاريخ التسليم · آخر تحديث · الإجراءات (عرض 👁 / تعديل ✏️ — التعديل متاح قبل إغلاق البوابة).
### خيارات «مسار التحدي» الخمسة (كما ظهرت في القائمة المنسدلة)
1. الحوار المعرفي والإجابات الموثوقة ← **اختيارنا**
2. صناعة المحتوى متعدد اللغات والتوطين الثقافي
3. التجارب التفاعلية والرحلة المعرفية للتعريف بالإسلام وتعلمه
4. أدوات المعرفة والتحقق لتمكين المعرفين بالإسلام (عنصر ثانوي في مشروعنا)
5. المسار المفتوح: حلول مبتكرة في التعريف بالإسلام
### قالب العرض الرسمي (من تبويب «الموارد والأدلة»)
- ملف القالب في هذا الريبو: `hackthons_files/قالب العرض (دليل الاستخدام والنماذج).pptx`
- **احذف الشرائح 1–7** (دليل الاستخدام) قبل الإرسال — الشرائح القابلة للتعبئة تبدأ من الشريحة 8
- الهوية: خط **Readex Pro** (عنوان 45pt Bold / نص 24pt / تعليق 18pt) ·
كحلي `#12183F` · بنفسجي `#6150EA` · تركواز `#2EF2C2` · أبيض مائل `#F2F4FF` ·
16:9 (1920×1080) · محاذاة يمين + RTL
- الترتيب المقترح: المشكلة → الحل → آلية العمل → النموذج (لقطات حية) → الأثر → الفريق → الشكر
- استبدل أرقام الرسوم الافتراضية (20/35/50/65 …) بأرقامنا الحقيقية، واختبر كل رابط قبل الحفظ
### قائمة الجاهزية قبل الضغط على «حفظ وارسال»
- [ ] العرض ≤ 10MB بصيغة PDF/PPT/PPTX وبدون شرائح الدليل (1–7)
- [ ] فيديو YouTube علني ≤ دقيقتين يشرح المشكلة والحل والديمو
- [ ] ريبو GitHub عام + رابط live demo يعمل من الـ Incognito
- [ ] اسم/وصف المشروع والمسار (01) مطابقة بين النموذج والعرض والفيديو
- [ ] لا بيانات شخصية في أي شاشة مسجلة · وملاحظة «نصوص الأحاديث من قاعدة البيانات مباشرة» ظاهرة