# Overview.Admin

## What it does

Access Gate protects named page, download, or member-area routes. Visitors without a matching grant can request access; authorised reviewers can approve, reject, expire, resend, or revoke access and investigate the resulting audit history.

## Before you protect content

An integrator must run the package install flow and attach the Access Gate middleware with the intended area key to every route that needs protection. Creating an area in the admin does not protect a route by itself. The install command creates its default area as **Paused** so content is not accidentally gated before this wiring is checked.

Run `capell:access-gate-doctor` after setup and test the protected URL as a signed-out visitor, an approved visitor, and a revoked visitor. Gated responses are private and excluded from public HTML caching; missing storage returns a private `503`, and a protected route with no matching area fails closed.

## Where it shows up

Go to **Workflow > Access Gate**. What each user can see or change depends on their Access Gate resource permissions and assigned-site scope.

- **Access areas** controls the area key, site, status, schedule, identity and approval modes, grant lifetime, token policy, public exceptions, claim destination, and optional announcement.
- **Registrations** lists requests and provides approve, reject, expire, bulk approve, and claim-link resend actions when the request state permits them.
- **Grants** shows who can currently enter and lets an authorised reviewer revoke the underlying access.
- **Claim links** and **Browser sessions** show link/device lifecycle state. A browser session can be revoked without revoking every session on the grant.
- **Audit events** records requests, decisions, claims, grants, revocations, and denied visits. Use `capell:access-gate-audit-export` when a filtered CSV is required.

## Site Lockdown

Site Lockdown protects an entire human-facing host before controllers, public rendering, HTML Cache, or static output. In **System > Sites**, open **Access Protection** to set the site default and optional domain overrides. A protected policy can accept a shared password, a signed-in account assigned to that site (global admins also qualify), a trusted upstream assertion, or any configured combination of those alternatives.

Environment protection is an explicit one-way ratchet. `ACCESS_GATE_SITE_LOCKDOWN_FORCE_HOSTS` can force selected hosts but the database cannot turn those hosts off or widen `ACCESS_GATE_SITE_LOCKDOWN_FORCE_METHODS`. Point `ACCESS_GATE_SITE_LOCKDOWN_FORCE_PROFILE` at a named profile and provide its secret outside Git. Do not infer protection from `APP_ENV`.

Set `ACCESS_GATE_SITE_LOCKDOWN_DISCOVERY_THROUGH_LARAVEL=true` only after the protected host routes robots, sitemap, feed, manifest, and `llms` requests through Laravel. The doctor check treats this as operator evidence and the deployment smoke verifies the live responses.

Shared-password access lasts for the browser session unless an absolute timeout is set. Changing a policy or credential increments its revision and invalidates existing sessions. `?pass=…` performs a one-time exchange and immediately redirects to a URL without the parameter; upstream access logs can still observe that initial request, so prefer the form or HTTP Basic for routine automation.

Database passwords are Argon2id hashes by default. Recoverable encrypted storage must be explicitly enabled and secret reveal requires a password-confirmed, audited admin flow. Named configuration profiles are useful for deployment-managed credentials. If a protected database policy cannot be resolved, Access Gate returns a private `503`; an environment-forced profile remains enforceable without package storage.

Site duplication and SiteSpec portability copy only policy shape, method choices, timeouts, revisions, and named profile references. Database password hashes and encrypted password values are never copied. Imported shared-password policies therefore remain protected but return a private `503` until an operator supplies a database credential or a valid named profile.

All protected responses, including authorised pages and `/up`, carry `Cache-Control: private, no-store` and `X-Robots-Tag: noindex, nofollow, nosnippet`. Protected `robots.txt` is replaced with `Disallow: /`; sitemaps, feeds, manifests and discovery documents remain behind authentication. Access/logout, required login callbacks, `/up`, the lockdown robots response and static assets are the only built-in exemptions. Add machine exemptions in code through `SiteAccessExemptionContributor`, never through database wildcards.

Run `capell:access-gate-doctor` after configuration. It reports forced hosts, effective methods, named profile availability, storage, middleware/cache ordering and route throttles without printing secrets. Policy changes clear HTML Cache and generated static artifacts. Do not generate or publish a static site while protection is active.

### Server and proxy notes

- Route `/robots.txt`, `/sitemap.xml`, `/feed`, `/site.webmanifest`, `/llms.txt` and similar discovery paths through Laravel on a protected host; do not let Nginx or Apache serve generated files ahead of the application.
- At Cloudflare or another proxy, bypass caching for protected hosts and preserve the application's private/no-store and robots headers.
- Trust an upstream assertion only from explicit proxy IP addresses and require an exact configured header value. Never trust a client-controlled header from the public internet.
- Recovery is configuration-first: restore the named credential profile or disable the explicit force-host setting during rollback. Keep `/up` routed to Laravel and public for deployment health checks.

## Configure an access area safely

- **Active** gates only inside its optional open/close window. Before the opening time and after the closing time, the protected route is allowed through; omit the window when content must remain gated continuously.
- **Paused** does not gate the route but still accepts registrations. **Closed** does not gate the route and rejects new registrations.
- **Guest link** recognises the browser token created from an emailed claim link. **Authenticated** requires a valid user or verified-email grant. **Hybrid** accepts either.
- Approval can be manual, automatic, invite-only, or automatic for the first configured number of approvals. The approval limit controls only the **first N auto-approve** strategy; it is not a hard cap on later manual approvals.
- **Single per email** reuses an existing request and can resend access for an already approved or claimed email. **Duplicate allowed** creates separate requests.
- With **Single active browser token**, a new claimed browser token replaces the previous active token for that grant. Choose multiple tokens only when the same grant should work on several browsers.
- A site-scoped area applies only to that site. A global area can cover every site, so reserve it for global operators. Treat public allowlist entries as deliberate bypasses and keep them as narrow paths or exact URLs.

## Access lifecycle and recovery

Approving a pending request creates a grant and sends a one-time claim link when the identity mode uses guest access. Claim links expire after seven days by default. A browser token defaults to 180 days but cannot outlive its grant; the grant itself follows **Grant duration days**. Resending creates a fresh claim link only while an active grant still exists.

Revoking a grant also revokes its active claim links and browser tokens. If one device alone is lost or shared, revoke that **Browser session** instead. Check the claim-link state, grant expiry, area status/schedule, and audit events when an approved person remains blocked.

## Data, privacy, and retention

Access Gate stores registration email and configured field values, requested URLs, grants, hashed claim/browser tokens, keyed IP fingerprints, browser use timestamps, and audit events. Privacy Center can export or erase records associated with a person when that package is installed.

`capell:access-gate-prune` removes stale claim/browser tokens and expired registrations after 90 days by default, and audit events after 365 days. The package does not register that command with Laravel's scheduler; schedule it in the host application if those retention windows must be enforced automatically. Use `--dry-run` first to report what would be deleted.