# Admin Guide

This guide covers what's exclusive to a **master user** (`is_master = true`)
in Aumni AMS. It assumes you've already read `docs/USER_GUIDE.md` — day-to-day
navigation, the asset register, assignments, warranty and reports work
exactly the same for a master as for anyone else. What's different is two
whole screens only masters can reach (**Users**, **Settings**), and a handful
of extra actions (deleting) scattered across the modules everyone shares.

Everywhere in the system, master-only areas are guarded twice: route-level
middleware keeps a non-master out of the page entirely, and — where the rule
depends on *which* record is being touched (you can't delete yourself, you
can't remove the last master) — a policy enforces that on top.

---

## 1. User Management

**Configure → Users** (visible only to master users) lists every account:
name, access level, status, and last sign-in. Filters: search (name or
email), Status (Active/Disabled), Access level (Master User/User).

### Creating an account

**Add User** asks for:

- **Full Name**, **Email Address** (this is the sign-in identity; must be
  unique).
- **Initial password** — leave both password fields blank to have the
  system generate a strong one, which is the recommended path (a password
  you type tends to be weak, or one you'll reuse). If you do type one, it
  must meet the configured minimum length.
- **Master user** checkbox — grants full access to Users and Settings.
  Everything else in the system is identical for both account types.
- **Account is active** checkbox.

Whichever way the password was set, the new account is **always** flagged
to require a password change at first sign-in — a password a master has
seen is temporary by definition.

### The one-time generated password

If you left the password blank, it's generated and shown to you **exactly
once**, immediately after creation, in a yellow banner at the top of the
Users list. It is never stored anywhere in readable form and cannot be
retrieved again — pass it to the account holder directly (not by email, not
written down where others can see it). If it's lost before you can pass it
on, use **Reset Password** to issue a fresh one.

### Editing an account

**Edit User** lets you change name, email, master/active flags — except on
your **own** account, where the master/active checkboxes are disabled
outright (submitted as hidden fields so they can't silently change). You
cannot demote or disable yourself; another master has to do that.

Editing shows a side panel with the account's activity: status, whether a
temporary password is pending, last sign-in, last sign-in IP, when the
password was last changed, and when the account was created.

### Resetting another user's password

From the Users list or an account's edit page, **Reset Password**:

- Leave the field blank to generate a new strong password (shown once, the
  same as at account creation) — the recommended path.
- Or type one directly.

Either way, the account is immediately flagged to require a password change
at next sign-in, and **every session that account currently has open is
ended immediately** — its old password stops working the instant you
confirm the reset.

You cannot reset your own password this way — use **Change Password** from
your own account menu instead, which requires your current password.

### Disabling and enabling accounts

The status toggle on the Users list (or Edit User) disables or re-enables
an account:

- **Disabling** ends every session that account currently has open, right
  away — if they're mid-task when you disable them, their very next
  request signs them out.
- **Enabling** is always allowed.
- **Disabling is refused if the account is you**, and refused if disabling
  it would leave **no active master user** anywhere in the system.

### Deleting an account

Deleting is a soft delete: the account can no longer sign in and disappears
from every listing and picker, but the row (and everything it's linked to
in the audit trail) is retained. The same two protections apply:

- **You cannot delete your own account.**
- **The last remaining active master user cannot be deleted** — nor
  disabled — by anyone, including another master. This is deliberate: it's
  the one guarantee that user management itself can never be locked out
  from the inside. If your organisation only has one master user and you
  need to hand off, create the new master first, confirm they can sign in
  and manage settings, and only then remove the old account (or demote it,
  if you'd rather it stayed as a regular account).

---

## 2. Application Settings

**Configure → Settings** (master-only) is one form with five tabs; every
tab posts together with a single **Save Changes** — editing Company doesn't
risk losing an in-progress edit to Notifications made in the same sitting.
Every change here is recorded to the audit log as a single "Updated N
application settings" entry, listing exactly which settings changed.

### Company

- **Company Name**, **Contact Email**, **Contact Phone**, **Company
  Address** — printed on exported reports; the address is reproduced
  exactly as typed, line breaks included.
- **Company Logo** — replaces the sidebar's default mark. PNG, JPG or SVG,
  up to 2 MB. A **Remove the current logo** checkbox appears once one is
  set.

### System Preferences

- **Application Name** — shown in the browser tab and the topbar.
- **Currency** — default 3-letter ISO code (e.g. `INR`) used when an asset
  doesn't specify its own.
- **Rows Per Page** — the default page size across every list in the
  system (10–200).
- **Date Format** / **Date & Time Format** — PHP date-format strings (e.g.
  `d M Y` and `d M Y, H:i`) controlling how every timestamp in the UI is
  displayed.
- **Timezone** — governs every timestamp computed from the moment you save
  this. The dropdown is a short, curated list of zones relevant to the
  company and the vendors it deals with, not the full IANA list.

### Assets & Imports

- **Asset Tag Prefix** — the leading segment of every new tag (e.g. `AUM`
  in `AUM-LAP-0042`). Letters and digits only.
- **Numbering** — **Restart per category** (each category counts from 1
  using its own code, e.g. `AUM-LAP-0042`) or **Run globally** (one shared
  sequence with no category code, e.g. `AUM-0042`).
- **Number Length** — how many digits the sequence is padded to (3–8).
- Changes here apply only to the **next** asset created — existing tags are
  never rewritten.
- **Import Row Cap** — the maximum number of data rows accepted in one
  bulk-import file (100–10,000; 2,000 by default). Imports run
  synchronously (there is no background queue), so setting this very high
  risks a request timeout on shared hosting — raise it deliberately, not
  reflexively.

### Notifications

- **Send the daily warranty expiry digest** — turns the
  `ams:send-warranty-digest` scheduled command's email on or off (see §5).
  With this off, the command runs on schedule but sends nothing and logs
  that it's turned off.
- **Alert Windows (days before expiry)** — a comma-separated list (e.g.
  `30, 15, 7`) of how many days out a warranty enters the digest. These are
  separate from the dashboard's fixed 30/60/90-day buckets, which never
  change.
- **Recipients** — one email address per line, or comma-separated; either
  works. If this is empty, the digest command sends nothing even with the
  toggle on.
- **From Name** / **From Address** — the outgoing mail's From header. The
  actual SMTP connection (host, port, credentials) is server configuration
  in `.env`, not something this screen touches — see `docs/DEPLOYMENT.md`.

### Security

- **Minimum Password Length** — the effective floor for every new or
  changed password. It can only be raised above the application's built-in
  floor of 10 characters, never lowered below it.
- **Audit Log Retention (months)** — how long routine audit entries are
  kept before the weekly pruning job removes them (see §5). **Custody
  events — Assigned, Returned, Renewed — are never pruned, at any age**:
  those are the chain-of-custody record, not routine activity, and this
  setting has no effect on them.

---

## 3. Master Data: Categories, Departments, Locations

Regular users can already view, create and edit Categories, Departments and
Locations (see `docs/USER_GUIDE.md` §8). What's master-only is **deleting**
and **restoring** them.

All three follow the same rule: **deletion is refused, with a specific
explanation, if anything still references the record** — rather than
letting a database constraint error surface as a raw failure:

| Record | Blocked by |
|---|---|
| Category | Has subcategories under it, or has assets classified under it |
| Department | Has employees in it, or has assets on the books under it |
| Location | Has employees based there, or has assets held there |

In every case, the error names exactly what's attached ("has 14 assets
classified under it") and suggests the alternative: reassign or delete the
dependents first, or **deactivate** the record (the `is_active` checkbox on
its edit form) instead of deleting it — an inactive record stays fully
intact and visible in history, but stops being offered on create/edit forms
elsewhere.

Deletion is a soft delete in all three cases: the record disappears from
the active listing and its picker, but is recoverable from that module's
**Deleted** view via **Restore**. One category-specific wrinkle: restoring
a subcategory whose parent is *also* still deleted is refused until you
restore the parent first — otherwise it would come back orphaned.

---

## 4. Bulk Import

Import (`Data → Import`) is open to every signed-in user and works exactly
as described in `docs/USER_GUIDE.md` §9 — upload, preview, confirm, with
nothing written until you confirm. What's worth knowing as a master:

- **The row cap** (Settings → Assets & Imports → Import Row Cap) is the
  only import behaviour you control. It defaults to 2,000 and can range
  100–10,000. Because imports run synchronously in the same request that
  submits them (there's no background queue), a very high cap is a request
  timeout risk on shared hosting, not just a data-volume decision.
- **A row is rejected, not the whole file.** Validation runs per row, using
  the same rules as the manual **Add Asset** form (required fields, value
  sets for Status/Condition, date bounds, serial-number uniqueness), so an
  imported asset can never end up less valid than one entered by hand. A
  file with some bad rows still imports every row that *did* pass —
  "42 of 50 imported" is the normal, expected outcome of a messy source
  spreadsheet, not a failure.
- **A genuine failure rolls back to nothing.** That's different from a
  rejected row: if something goes wrong partway through actually writing
  the valid rows (a database-level error, not a row that failed
  validation), the whole commit is rolled back and nothing from that run is
  added — at that point the batch can no longer promise its row counts are
  accurate, so it doesn't try.
- **The Asset Name and Category columns must be present and recognisable.**
  Those two headers are the minimum the importer checks for before it will
  even offer a preview; if they're missing or renamed, the batch is marked
  Failed immediately at upload, with a message pointing back at the
  downloadable template. The other columns are matched by the template's
  headings but are individually optional — a missing optional column just
  means that field is blank on every imported row, not a failed upload.
- Every import attempt — successful, partially successful, or failed
  outright — writes exactly one audit log entry summarising the outcome
  (`Imported` event, Data module). Individual imported rows do **not** each
  get their own "created" audit entry; the one import-level entry is the
  record.

---

## 5. Audit Logs: Retention and the Scheduled Commands

Every signed-in user can browse and export the audit log (see
`docs/USER_GUIDE.md` §11). Two things about it are master-controlled or
master-run.

### What gets logged

Every create/update/delete/restore on an audited record (Assets, Asset
Assignments, Asset Warranties, Employees, Departments, Locations, Asset
Categories, Users) is captured automatically, including a before/after diff
of every changed field. Sensitive fields (passwords, remember tokens) are
recorded as a fixed mask rather than in cleartext or dropped entirely, so a
password change still produces a visible entry without ever exposing the
value. On top of that, the domain services themselves write explicit,
hand-described entries for actions that a generic "record changed" line
wouldn't explain on its own: sign-in/out, failed sign-ins, password
changes/resets, account enable/disable, asset assignment/return, status
changes, warranty renewals, exports, imports, and settings changes.

### Retention and pruning

The **Audit Log Retention (months)** setting (Settings → Security) governs
how long routine entries are kept — 24 months by default. **Chain-of-custody
events (Assigned, Returned, Renewed) are permanently exempt regardless of
age**; nothing in Settings can shorten their retention, because they are
the record of who has held what, not routine activity that ages out.

Pruning itself doesn't happen automatically on its own schedule inside the
app — it's a console command, `php artisan ams:prune-audit-logs`, meant to
be wired into the server's cron/scheduler (see `docs/DEPLOYMENT.md` for how
the scheduler itself is set up). Running it deletes every non-exempt entry
older than the configured retention window and reports how many rows it
removed (or that there was nothing to prune).

### Exporting the trail

**Export** on the Audit Logs screen downloads the currently filtered log as
an `.xlsx` file — available to every user, not just masters, since the
screen itself carries no write actions of any kind.

---

## 6. Artisan Commands

Two commands are part of ongoing administration; a third exists but isn't
something you'd typically run by hand.

### `php artisan ams:create-master-user`

Creates a master account directly on the server — the way the very first
master account comes into existence (before there's anyone able to use
Users → Add User yet), and a documented fallback for creating another one
without going through the UI at all. It exists instead of a database seeder
specifically so no login credential ever sits in version control.

Interactive use prompts for name, email and password. For scripted setup:

```
php artisan ams:create-master-user \
    --name="Priya Sharma" --email=priya@aumnitechworks.com --generate
```

Options:

| Option | Effect |
|---|---|
| `--name=` | Full name |
| `--email=` | Sign-in email address |
| `--password=` | Set a specific password (otherwise you're prompted, or use `--generate`) |
| `--generate` | Generate a random password and print it once — not recoverable afterwards, same as the UI's generated-password flow |
| `--force-change` | Require a password change at first sign-in even if you supplied `--password` yourself |

A password produced by `--generate` always requires a change at first
sign-in. The command validates name, email and password the same way the
Add User form does, and refuses a duplicate email address.

### `php artisan ams:prune-audit-logs`

Deletes routine audit log entries older than the **Audit Log Retention**
setting (§5), leaving custody events untouched regardless of age. Meant to
run weekly via the server's scheduler — see `docs/DEPLOYMENT.md` for how
Aumni AMS's scheduled tasks are wired up on the hosting side.

### `php artisan ams:send-warranty-digest`

Not something you run manually day to day — it's the daily job behind the
**Send the daily warranty expiry digest** setting (§2). It reads
`enable_warranty_emails`, `warranty_alert_days` and
`warranty_alert_recipients`, and emails the configured recipients a summary
of warranties entering an alert window that day, grouped by how many days
remain. If the toggle is off, no recipients are configured, or nothing is
newly entering an alert window, it does nothing and says so — it never
sends an empty digest.

---

## 7. Server and Infrastructure

Everything past this point — hosting requirements, deployment steps,
scheduler/cron setup, database backups and restore procedures — is outside
this guide. See:

- **`docs/DEPLOYMENT.md`** — how the application ships to production and
  the pre-launch checklist.
- **`docs/BACKUP.md`** — what's backed up, how often, and how to restore
  it.
