# Aurea — Scholarly Journal & Peer Review Platform

A self-contained, OJS-inspired journal management and peer-review system.
Pure PHP (no Composer, no frameworks, no CDNs), SQLite storage, vanilla
CSS/JS front-end in a premium maroon aesthetic, role-based access control,
and a token-authenticated REST API.

> **New here?** Open **`readme.html`** in a browser for a fully illustrated,
> styled installation and usage guide (technology stack, infrastructure
> requirements, role walkthroughs, sitemap, security — all in one place).
> This file (`README.md`) is the plain-text technical reference alongside it.

---

## 1. Requirements

- PHP **8.1+** with the `pdo_sqlite` extension enabled (bundled with most PHP installs)
- Apache with `mod_rewrite` and `mod_headers` (recommended), or any server that can run PHP
- Write permissions on `/data` and `/iedad`

No Composer, no npm, no external CDNs — everything needed ships in this folder.

## 2. Installation

1. Upload the whole folder to your web server. For **local testing**, use PHP's
   built-in server with the router script (required for clean URLs to work
   without Apache):
   ```
   php -S localhost:8000 muwajjih.php
   ```
   For **production**, deploy behind Apache with `mod_rewrite` + `mod_headers`
   enabled and `AllowOverride All` set for this directory — `.htaccess` does
   the routing and also blocks direct access to the underlying files (see
   §4 below). Nginx/other servers need an equivalent rewrite-everything-to-
   `muwajjih.php` rule; none is shipped since there's no `.htaccess` equivalent.
2. Visit `/taasis/index.php` in your browser (the installer is reachable
   directly — it's the one page not yet behind the router, since no config
   exists before installation).
3. The installer checks requirements, then asks for:
   - Site name
   - Your name, email and password — this becomes your **Super Administrator** account
4. On success you're redirected to `/login`. Log in and you're done.

The installer writes `/iedad/iedad.php` (your live config, including a randomly
generated 256-bit secret key) and creates `/data/majalla.sqlite` with the full
schema, plus one demo journal so the homepage isn't empty on first run.

**The installer refuses to run again once `iedad/iedad.php` and the database
both exist.** To reinstall from scratch, delete `/iedad/iedad.php` and
`/data/majalla.sqlite*`.

## 3. Roles & permissions

Four account tiers, enforced in `nawat/tahqiq.php` as an ascending hierarchy
(`author < editor < admin < super_admin`) — anyone with a higher rank
automatically passes a lower rank's permission check, so Admins and Super
Admins can already reach every Editor screen (Editorial Overview / All
Submissions, linked from their own sidebar) without a separate account.

| Role | Arabic transliteration | Can do |
|---|---|---|
| Super Administrator | `super_admin` | Everything below, plus site settings, activity log, the raw database console, and the homepage/indexing-logos editor |
| Administrator | `admin` | Manage journals, users, custom pages (not the homepage), API keys — plus everything an Editor can do |
| Editor | `muharrir` (`editor`) | Manage submissions, edit article metadata (title, byline name/institution, abstract, keywords, replace the manuscript file), leave revision notes for the author, upload the final typeset PDF, assign reviewers, make editorial decisions |
| Author | `katib` (`author`) | Submit manuscripts, edit or delete their own submission **while it isn't published yet**, track status, read editor feedback |

**Peer reviewer** is not a separate account tier — it's an *eligibility flag*
(`ahliyya_muraja3a`) an admin can grant to any account, exactly like OJS lets
one person hold multiple roles. A user with this flag sees a "My Review
Assignments" item in their sidebar once an editor assigns them a manuscript.

**API keys** are Admin/Super Admin only (`/account/api-keys`) — Authors and
Editors no longer see this in their sidebar, since API integration is a
platform-management concern rather than a per-user one.

### Article editing & deletion rules

- **Author**: full edit (journal, title, institution, abstract, keywords,
  replace the manuscript PDF) and delete, but only while the article's
  status isn't `published`. Once published, both actions 403.
- **Editor** (and Admin/Super Admin): can edit an article's metadata at any
  status — including the byline name and institution shown publicly — leave
  revision notes the author sees on their edit page, and upload a separate
  **final PDF** that supersedes the author's original manuscript once
  published (falls back to the original if no final PDF was uploaded).

### Custom pages & the homepage

- **Admin and Super Admin** can create/edit/delete standalone content pages
  (e.g. "Author Guidelines") from **Pages** in the sidebar — live at
  `/pages/<slug>`, listed automatically in the footer once published.
- **Only Super Admin** can edit the homepage itself, via **Homepage & Logos**
  — this is where indexing/partner badges (Google Scholar, Mendeley, DOAJ,
  etc.) are added; each is a name + link + logo (upload or pasted image URL)
  and appears as a clickable badge row near the bottom of `/`.

### Database console (Super Admin only)

`/admin/database` gives the Super Administrator a raw SQLite browser (table
list + first-100-rows view) and a SQL console that runs arbitrary
statements directly against `data/majalla.sqlite`. This intentionally
bypasses all of the app's normal validation — that's the point of the
feature — so it's gated behind an explicit "I understand this may change or
delete data" checkbox for anything that looks like `DROP`/`DELETE`/`UPDATE`/
`ALTER`, and every statement run through it is recorded in the activity log.
**There is no undo.** Back up the database file before using it for anything
beyond read-only `SELECT`s.

## 4. URL scheme — clean English routes, real file names hidden

Every page is reached through a clean, English-only URL. The real
(Arabic-transliterated) file layout described in §7 never appears in the
browser's address bar or in any link the app generates — everything routes
through `muwajjih.php`, and `.htaccess` blocks direct HTTP access to the
underlying files outright (a browser request for the literal file still
404s/403s; only the router's internal `require()` can reach it).

| What | URL |
|---|---|
| Homepage | `/` |
| Journals directory | `/journals` |
| Single journal | `/journals/<journal-slug>` |
| Single article | `/articles/<article-slug>` |
| About | `/about` |
| Custom page | `/pages/<page-slug>` |
| Log in / Register / Log out | `/login` · `/register` · `/logout` |
| Confirm email / Resend confirmation | `/confirm-email?ramz=<token>` · `/resend-confirmation` |
| Author dashboard | `/author/dashboard`, `/author/submissions`, `/author/submissions/new`, `/author/submissions/edit/<id>` |
| Editor dashboard | `/editor/dashboard`, `/editor/submissions`, `/editor/submissions/<id>` |
| Reviewer dashboard | `/reviewer/dashboard`, `/reviewer/review/<id>` |
| Admin dashboard | `/admin/dashboard`, `/admin/journals`, `/admin/users`, `/admin/pages`, `/admin/pages/edit/<id|new>` |
| Super Admin only | `/admin/settings`, `/admin/activity-log`, `/admin/database`, `/admin/external-links` |
| API keys (Admin/Super Admin) | `/account/api-keys` |
| Article PDF (public, published only) | `/downloads/article/<id>` (add `?download=1` to force Save-As instead of viewing) |
| Manuscript PDF (author/editor/reviewer) | `/downloads/manuscript/<id>` (same `?download=1` option) |
| REST API | `/api/journals`, `/api/articles`, `/api/articles/<slug>` |
| Sitemap | `/sitemap.xml` |

The whole map lives in one place, `nawat/masarat.php`, as PHP constants
(`MASAR_DUKHUL`, `MASAR_MAJALLA`, …) — every link, redirect, and form in the
codebase uses these constants rather than a hardcoded path, so the URL
scheme can be changed in one file if you ever need to.

### Article slugs

An article's slug is generated as **`<author's full name>-<first 5 words of
the title>`**, lower-cased and hyphenated (see `buat_rawabit_maqal()` in
`nawat/dawal.php`). If that combination is already taken, a numeric suffix
is appended: `-2`, `-3`, and so on. For example, "Jane Doe" submitting
*"A Study of Coastal Erosion Patterns in Northern Java"* gets
`/articles/jane-doe-a-study-of-coastal-erosion`; a second, unrelated
submission that happens to collide becomes `…-erosion-2`.

## 5. The REST API

Any logged-in user can generate their own API key from **API Keys** in the
dashboard sidebar (`/account/api-keys`). The raw key is shown once —
only its SHA-256 hash is stored in the database.

```
GET /api/journals
GET /api/articles?majalla=<journal-slug>&sfha=1
GET /api/articles/<article-slug>
Authorization: Bearer <your-api-key>
```

Responses are JSON. Invalid/revoked keys get `401`; unknown resources get `400`.

## 6. PDF viewing

Article and manuscript pages show an inline `<object type="application/pdf">`
preview (not `<iframe>` — `<object>` degrades more gracefully and isn't
affected by the framing bug iframes hit under a strict CSP). Below the
preview, "View Full" opens the same PDF in a new tab via the browser's own
full-page renderer, and "Download PDF" forces a Save-As prompt via
`Content-Disposition: attachment`.

**About the zoom / find / fullscreen / back toolbar**: the small inline
`<object>` preview is a quick look only — browsers do not give embedded PDF
previews a toolbar (this is a browser limitation, not something addable
without bundling a JS PDF renderer like PDF.js, which the "no external
libraries" requirement rules out). The full native toolbar — zoom in/out,
text search, print, download, and fullscreen — is always available, but
only once the PDF is the sole content of a tab: that's exactly what **"View
Full"** does. "Back" is then just the browser's own Back button, since it's
a normal page in your history at that point.

**If PDFs download instead of displaying inline at all** — even via "View
Full" — that's almost always a browser-level setting rather than a server
bug:
- Chrome/Edge: `chrome://settings/content/pdfDocuments` → turn **off**
  "Download PDFs instead of automatically opening them"
- Firefox: `about:preferences#general` → *Applications* → set
  "Portable Document Format (PDF)" to **Open in Firefox**

This setting overrides the server's `Content-Disposition: inline` header for
full-tab navigation, which is why "View Full" and "Download PDF" can look
identical if it's switched on.

## 7. Security measures implemented

- **SQL injection** — every query goes through PDO prepared statements
  (`nawat/qaeda.php`); there is no raw string interpolation into SQL anywhere.
- **XSS** — all output is escaped through `Amn::tanqiya()` (a `htmlspecialchars`
  wrapper); a strict Content-Security-Policy header blocks inline scripts.
- **CSRF** — every state-changing form carries a per-session token verified
  with `hash_equals()` before any write happens.
- **Passwords** — hashed with Argon2id (`password_hash(..., PASSWORD_ARGON2ID)`).
- **Session hardening** — HttpOnly + SameSite cookies, periodic session ID
  regeneration, secure flag auto-enabled under HTTPS.
- **Brute-force protection** — failed logins are rate-limited per IP
  (5 attempts / 15 minutes) via `muhawalat_dukhul`.
- **File uploads** — manuscripts are validated by real MIME sniffing
  (`finfo`, not the client-supplied extension), renamed to random hex
  filenames, capped at 20MB, and PHP execution is disabled inside the
  upload directory via `.htaccess`.
- **Path traversal** — download endpoints resolve `realpath()` and verify
  the result still lives inside the uploads directory before serving.
- **API keys** — stored as salted SHA-256 hashes (pepper = your instance's
  secret key), never in plaintext; revocation is immediate.
- **Security headers** — `X-Frame-Options`, `X-Content-Type-Options`,
  `Referrer-Policy`, `Permissions-Policy`, and CSP are sent on every request
  (`Amn::ruus_amina()`), plus HSTS when served over HTTPS.
- **Activity log** — logins, submissions, editorial decisions, key creation,
  and user status changes are all recorded (`sijil_nashat`), visible to the
  Super Administrator.

- **Direct file access blocked** — the underlying PHP files (see §9) are
  blocked from direct HTTP access by `.htaccess`; every page is only
  reachable through its clean `/login`-style route, resolved server-side.

## 8. SEO

- Semantic HTML, one `<h1>` per page, descriptive `<title>`/meta description per route
- Canonical URLs, Open Graph tags
- `schema.org` JSON-LD (`ScholarlyArticle`, `Periodical`, `WebSite`) on relevant pages
- Dynamic `sitemap.php`, served at `/sitemap.xml`, covering every journal and published article
- `robots.txt` excluding dashboards/admin areas from crawling
- Clean, human-readable, English-only URLs and slugs throughout (see §4)

## 9. Folder glossary (Arabic transliteration → meaning)

These are the **real, on-disk** file and folder names — never exposed in
the browser (see §4). They're transliterated Arabic, per the original
brief; what visitors and users actually see is always an English route.

| Folder/file | Meaning |
|---|---|
| `taasis/` | *ta'sīs* — "founding" → installer |
| `iedad/` | *i'dād* — "preparation" → configuration |
| `nawat/` | *nawāh* — "core/nucleus" → core classes & bootstrap |
| `qawalib/` | *qawālib* — "templates/moulds" → header/footer/sidebar partials |
| `mawad/` | *mawādd* — "materials" → CSS/JS/images |
| `idara/` | *idārah* — "administration" → admin/super-admin panel |
| `tahrir/` | *taḥrīr* — "editing" → editor panel |
| `kuttab/` | *kuttāb* — "writers" → author panel |
| `muraji3in/` | *murāji'īn* — "reviewers" → peer-review panel |
| `hisab/` | *ḥisāb* — "account" → login/register/logout |
| `wasla/` | *waṣlah* — "connector/link" → REST API & file downloads |
| `muwajjih.php` | *muwajjih* — "router/director" → front controller resolving clean URLs to these files |
| `data/` | (not transliterated — the SQLite DB and uploads live here) |

Individual file names follow the same convention, e.g. `dukhul.php` (login),
`tasjil.php` (register), `khuruj.php` (logout), `lawha.php` (dashboard),
`mustakhdimin.php` (users), `majallat.php` (journals), `maqalat.php` (articles),
`taeyinat_muraja3a` (review assignments), `mafatih_rabt` (API keys).

## 10. Known scope limits — please read

This is a strong, production-grade **foundation**, not a byte-for-byte clone
of the full Open Journal Systems suite (which represents well over a decade
of development). Deliberately out of scope for this build: multi-language
UI, a plugin system, OAI-PMH harvesting, DOI registration with CrossRef,
co-authorship, and multiple review rounds per assignment. Email is limited
to registration confirmation (via `nawat/barid.php`, PHP's built-in `mail()`
— no editorial-decision or reviewer-invitation emails yet). The
architecture (clean model classes, prepared statements everywhere, one
responsibility per file) is meant to make adding these straightforward.

## 11. Default login

There is no default login — the Super Administrator account is the one you
create during installation at `/taasis/index.php`.

## 12. Upgrading an existing installation

If you installed an earlier build of this app, just replace the files and
reload any page — `nawat/tarqiya.php` runs automatically on the next
request, adds any missing columns/tables (article editor notes, final PDF,
email confirmation, custom pages, external logos), and marks itself done
via a version flag in `iedadat_nizam` so it doesn't re-run every time.
Existing accounts are marked as already email-confirmed automatically, so
nobody already using the site gets locked out. No manual SQL required —
though a backup of `data/majalla.sqlite` before upgrading is still wise.
