# User guide — Said Yaqub Sadat Personal Portfolio (administrator)

This guide explains how to maintain the portfolio through the administrator
dashboard. It contains **no production credentials** — the account is created by the
deployment process (see [deployment.md](./deployment.md#2-backend)).

## 1. Signing in

1. Open `https://<site-domain>/admin/login`.
2. Enter the administrator e-mail address and password.
3. On success you land on the dashboard. The session is a bearer token stored in the
   browser; closing the browser ends the session.

Opening `/admin/login` while a session is active sends you straight back to the
panel — there is no second sign-in. Signing in again in another browser or tab does
not sign the open panel out; only **Logout** and a password change end a session.

The dashboard is intentionally separate from the public navigation. After ten failed
sign-in attempts within a minute the endpoint refuses further attempts for that
minute — wait and try again. Every attempt, successful or not, is written to the
activity log.

## 2. Dashboard overview

The dashboard shows:

* **Counters** — total projects, published projects, drafts, skills, experience,
  education, certificates, messages and unread messages.
* **Recent messages** — the five newest contact submissions with a dot marking
  unread ones.
* **Recent activity** — the last administrator actions (sign-ins, content changes,
  uploads) with their timestamps.

Use the sidebar to move between Projects, Skills, Experience, Education, Certificates,
Messages and Settings. **Sign out** is at the bottom of the sidebar.

## 3. Projects

### 3.1 Creating a project

1. Open **Projects → New Project**.
2. Fill in the form:
   * **Title** (required) — the public name of the project.
   * **Slug** — leave empty to generate it from the title (`moraa-mis`). The slug is
     always unique; a second project with the same title gets `moraa-mis-2`.
   * **Status** — `draft`, `published` or `archived`.
   * **Category** — one of the categories used on the public site, for example
     `LMS & Education Systems`, `MIS & Databases`, `Web Applications`.
   * **Role** — your role on the project.
   * **Short description** — one or two sentences used on the project cards.
   * **Description** — the full description shown on the detail page.
   * **Case study** — *Problem*, *Solution*, *Challenges* and *Results*. Fill these in
     with facts you can defend; they are the most valuable part of the page.
   * **Tech stack** — comma separated, e.g. `Laravel, React, MySQL`.
   * **Cover image** — upload a JPG/PNG/WebP (max 5 MB).
   * **Live URL / Repository URL** — leave empty when the link does not exist. The
     public page hides empty links.
   * **Featured** — highlights the project on the home page.
   * **Sort order** — lower numbers appear first.
3. Press **Save**. The project is stored immediately; use the status field to control
   whether it is visible.

### 3.2 Editing and deleting

* **Edit** opens the same form pre-filled. Changing the title does not change the
  slug automatically — edit the slug explicitly if you want a new URL.
* **Delete** asks for confirmation and removes the project together with its
  screenshots. Media files stay in storage, so nothing else breaks.
* **Unpublish / Publish** on a card switches a project between `published` and
  `draft` without opening the form.

### 3.3 Screenshots

Inside the edit dialog:

1. Save the project first — the gallery can only be attached to a stored project.
2. Choose an image file (max 5 MB). The file is uploaded and attached in one step.
3. Use the gallery list to remove a screenshot again.

Every screenshot should have a caption and alt text that describes what the image
shows; the alt text of a newly attached screenshot is pre-filled with the project
title and can be refined in the project payload.

### 3.4 Publication states

| State | Visible publicly? |
|---|---|
| `published` | Yes — listed on the projects page, searchable, and included in the sitemap |
| `draft` | No — the public API returns 404 for it, and it is absent from lists and filters |
| `archived` | No — same as draft, used for work that is no longer promoted |

## 4. Skills

**Skills → New Skill**:

* **Name** — the technology or practice.
* **Category** — `Backend`, `Frontend`, `Database`, `Workflow` or your own grouping.
* **Level** — 0–100, drives the progress bar.
* **Proficiency** — the honest text label shown next to the bar, for example
  `Proficient` or `Advanced`.
* **Description** — one line explaining the practical experience.
* **Sort order** — display order.

## 5. Experience

**Experience → New Entry**:

* **Role** — job title.
* **Company** — employer or organisation.
* **Location** — city and country.
* **Start date / End date** — for example `2023` or `Jan 2023`.
* **Current** — tick it for an ongoing role; the end date is then ignored.
* **Responsibilities** — one bullet per line; they are stored as a list and rendered as
  a bullet list.
* **Sort order** — reverse chronological order is usually the most readable.

## 6. Education and certificates

**Education → New Entry**: institution, degree, period, description, sort order.

**Certificates → New Certificate**:

* **Title** and **Issuer** are required.
* **Issue date**, **Credential ID** and **Verification URL** are optional — only fill
  in a verification link if the credential can actually be verified there.
* **Description** explains what the certificate covers.

## 7. Messages

**Messages** lists every contact submission.

* Use the status filter to narrow the list (`new`, `read`, `replied`, `archived`) and
  the search box to look for a name, address or subject.
* Open a message to read it; opening it marks it as read.
* **Mark as replied** moves it to `replied` and records the time.
* **Archive** keeps the message but removes it from the inbox view.
* **Delete** removes it permanently. Message bodies are never exposed through the
  public API.

Messages are personal data: delete or archive them once the conversation is finished.

## 8. Site settings

**Settings** edits the content that appears across the public site:

* Full name, professional title, tagline.
* Professional summary (home page) and biography (About page).
* Professional focus and values — separate the items with `•`.
* Location, e-mail, phone, nationality.
* GitHub, LinkedIn and portfolio URLs.

Press **Save Settings** to apply the changes. Only the fields listed here are
accepted; unknown keys are ignored by the server.

### Setting the site logo

1. In **Settings → Site logo** press **Upload logo** and choose an SVG, JPG, PNG or
   WEBP file (max 5 MB).
2. The upload is stored in `backend/storage/app/public/logo/` and becomes the active
   logo straight away — no second save is needed.
3. The logo is shown in the public navigation bar, the public footer, the admin
   sidebar and the admin sign-in page. **Remove logo** falls back to the built-in
   mark `frontend/public/logo.svg`.

The previous file stays on disk; remove it from
`backend/storage/app/public/logo/` if it is no longer needed.

### Setting the profile photo

1. In **Settings → Profile photo** press **Upload profile photo** and choose a JPG,
   PNG or WEBP file (max 5 MB).
2. The upload is stored in `backend/storage/app/public/profile/` and becomes the
   active photo straight away — no second save is needed.
3. The photo appears in the hero card and the About page. Until a photo is uploaded,
   the site shows the branded placeholder
   `frontend/public/profile-placeholder.png`.

The previous file stays on disk; remove it from
`backend/storage/app/public/profile/` if it is no longer needed.

### Replacing the CV

1. In **Settings → Current CV (PDF)** press **Upload new CV** and choose a PDF
   (max 10 MB).
2. The upload is stored and the path is filled into the form — press **Save Settings**
   to activate it.
3. The **CV** page and the direct links `https://<api-host>/cv` (or
   `https://<api-host>/api/cv`) then serve the new file.

If no CV is uploaded, the site falls back to the file stored at
`backend/storage/app/public/cv/Said_Yaqub_Sadat_CV.pdf`.

> The CV is only reachable from the **CV** page (linked in the footer) and from the
> direct URL — the download buttons were removed from the navigation bar, the hero
> and the footer.

## 9. My profile and users

### My profile

**My Profile** manages the account you sign in with:

* **Full name** and **e-mail address** — press **Save details** to apply them.
* **Password** — the current password is required, the new one needs at least
  8 characters and must be repeated. After a change, all other sessions of the
  account are signed out.

### Users

**Users** manages every account that may sign in to the dashboard:

* **New User** creates an account with a name, e-mail, password and the
  *Administrator* switch. Administrators may sign in and manage everything, other
  accounts are editors.
* **Edit** changes the name, the e-mail address, the password (leave the field empty
  to keep the current one) and the role.
* The trash button removes an account.

Two rules are enforced by the server: you cannot delete the account you are signed in
with, and the last administrator can neither be deleted nor demoted.

## 10. Common problems

| Problem | What to do |
|---|---|
| "Session expired" / back at the sign-in page | The token was removed or the server rejected it — sign in again |
| "Invalid credentials" | Check the address and password; after ten failed attempts in a minute the endpoint is temporarily blocked |
| A change is not visible on the public site | The project is still a `draft`; publish it. If it is published, clear the cache (`php artisan cache:clear`) |
| Upload fails | The file must be an image (JPG, PNG, GIF, SVG, WebP) up to 5 MB, a JPG/PNG/WebP up to 5 MB for the profile photo, or a PDF up to 10 MB for the CV. A web server limit may also block large files |
| "Save the project before adding screenshots" | The project has to exist first — save the form, then reopen it for the gallery |
| The CV download returns "not found" | Upload the CV in Settings, or place the file in `backend/storage/app/public/cv/` |
| Images are missing after a deployment | Run `php artisan storage:link` and check the file permissions of `backend/storage` |
| The contact form says "sent" but no e-mail arrives | The message is stored either way — configure `MAIL_*` in `.env` to enable real delivery |
