Checkout & Check-in
The endorsement lifecycle is the heart of Safekeep: an asset is checked out (endorsed) to a staff member, the assignee confirms receipt — signing an acceptance agreement when the category requires one — can later request its return, and IT finally checks it back in. Every step stamps the asset record and appends one immutable event to the asset's chain-of-custody Activity log.
ams/assets/view/…) — there is no bulk checkout from the
registry table. In Safekeep's vocabulary an asset is
endorsed to a user; "checkout" and "endorsement" mean the same thing, and the checkout
modal labels the assignee field "Endorsed to".
The endorsement pipeline
The lifecycle state is stored per asset as its endorsement status and shown as a chip next to "Endorsed to" in the detail page's lifecycle summary panel. It moves strictly through four states:
Two stages are optional shortcuts: an asset can be checked in straight from Assigned (the assignee never acknowledged), and Return requested can be skipped entirely when IT initiates the check-in. Once Returned, the asset is free to be checked out again — a fresh checkout restarts the pipeline at Assigned.
asset_checkout)1 · Check out (endorse) an asset
Who: anyone with the
asset_checkout permission ("Assets: Checkout / Endorse").Preconditions: the asset is not currently checked out, and its status label is Deployable type (or the asset has no status label at all — see the guard below).
Open the asset
From the registry (
ams/assets, Browse tab), click the asset's title to open its detail page.Actions → "Check out asset"
Open the "Actions" dropdown and choose "Check out asset". The item only appears while the asset is not checked out.
Fill the checkout modal
Pick the assignee in "Endorsed to" (required), optionally set a "Due / return by" date and a note.
Click "Check out"
On success you get the toast "Asset checked out." and the page reloads showing the Assigned chip and the new "Endorsed" Activity entry.
Checkout modal fields
| Field label | Required | Notes |
|---|---|---|
| "Asset" | — | Read-only: the asset title, plus #ASSET_TAG when a tag is set. |
| "Endorsed to" | Yes | Select2 dropdown of active staff users only. You cannot check out to a location, a department, or another asset — user targets are the only kind implemented. |
| "Due / return by" | No | Datepicker. Drives the "Return due" reason in the "Assets needing attention" widget and the return-due reminder. |
| "Note (optional)" | No | Textarea; stored as the body of the logged event and visible in the Activity timeline. |
Guards — when checkout is refused
What checkout records
- On the asset
- Assignee set ("Issued to"), assignment type
user, "Issued at" stamped with today's date (UTC), "Due / return by" saved, endorsement status set to Assigned, the acting user recorded as the endorser, and any previous return date / acknowledgement flags cleared. - In the Activity log
- One "Endorsed" event titled "Checked out to [assignee]", with your note as its body and the assignee as the event's target user.
- Toast
- "Asset checked out." — then the page reloads.
2 · Confirm receipt (acknowledge)
Who: the current assignee, or an admin. There is no permission key for this action — it is gated purely by identity.
Preconditions: the asset is checked out and not yet acknowledged.
When the assignee opens their endorsed asset, the "Actions" dropdown offers "Confirm receipt" (it appears while the asset is checked out and receipt is not yet confirmed). The server also accepts the confirmation from an admin on the assignee's behalf — but the dropdown item itself is shown only to the assignee, so there is no button for admins. If the asset is not assigned at all, the server refuses with "This asset is not currently assigned."
The acceptance agreement (EULA) panel
What the modal shows depends on the asset's category:
- Category does not require acceptance (the default for every category, including all six seeded ones): the modal simply shows "Asset: [title]" and the muted prompt "Confirm receipt". One click on the "Confirm receipt" button completes it.
- Category requires acceptance: the modal adds a required signature field labeled "Type your full name to sign". If the category also has agreement text, a scrollable "Acceptance agreement" box shows the full terms above a required checkbox "I have read and accept the terms above."
require_acceptance and eula_text on the asset-categories table) can
only be set directly in the database by a technical administrator. Until that UI ships,
most installs will only ever see the plain one-click "Confirm receipt" modal. See
Categories and FAQ & Troubleshooting.
Validation messages
What confirming receipt records
- On the asset
- Acknowledged flag set, acknowledgement timestamp stamped (UTC), endorsement status moves to Acknowledged. The assignee and due date are untouched.
- In the Activity log
- One "Acknowledged" event titled "Receipt confirmed." — with body
"Signed: [typed name]" when a signature was captured. The event row additionally
stores
accepted_at(the acceptance timestamp) and, when acceptance was required, a frozen snapshot of the agreement text as accepted (stored_eula) plus the typed signature (signature_file). Because the snapshot is stored on the event, later edits to the category's agreement never rewrite what this user actually accepted. - Toast
- "Receipt confirmed." — then the page reloads.
3 · Request return
Who: the current assignee, or an admin. No permission key.
Preconditions: the asset is checked out and a return has not already been requested.
The "Actions" dropdown offers "Request return" to the assignee while the asset is checked out and no request is pending. The modal shows "Asset: [title]" and an optional "Note (optional)" textarea; the footer button is "Request return".
- If the asset is not checked out, the server answers "This asset is not currently assigned."
- If a return was already requested, the request is rejected with the message "Return requested".
- On the asset
- Only the endorsement status changes — to Return requested. The assignee keeps the asset: the assignment, issued date, and due date all stay in place until someone checks it in.
- In the Activity log
- One "Return requested" event titled "Return requested", with your note as its body and the assignee as the target.
- Toast
- "Return requested" — then the page reloads.
4 · Check in an asset
Who: anyone with
asset_checkout (the same permission as checkout). It does
not matter who requested the return — any permitted user can check in.Preconditions: the asset is currently assigned.
Actions → "Check in asset"
On the asset detail page, open "Actions" and choose "Check in asset" — the item appears while the asset is checked out. If the asset has no assignee the server refuses with "This asset is not currently assigned."
Record the hand-back
Note the physical "Condition", choose a status in "Set status to" if the asset should move (e.g. back to "Ready to Deploy", or to "In Repair" if it came back damaged), and add a note.
Click "Check in"
Toast "Asset checked in."; the page reloads with the assignment cleared and a "Returned" Activity entry.
Check-in modal fields
| Field label | Required | Notes |
|---|---|---|
| "Endorsed to" | — | Read-only: the current assignee being checked in from. |
| "Condition" | No | Free text (no fixed vocabulary). If filled, it overwrites the asset's stored condition. |
| "Set status to" | No | Status-label dropdown. Optional manual status move recorded together with the check-in — the only place besides the Edit form where you can change status during the lifecycle. |
| "Note (optional)" | No | Stored as the body of the logged event. |
What check-in records and clears
- Stamped
- Return date set to today, endorsement status set to Returned; the asset's condition and status label are updated if you filled those fields.
- Cleared
- The assignee ("Issued to"), issued date, due date, assignment type, the endorser, and both acknowledgement markers (flag + timestamp) are all wiped — the asset is fully back in stock and ready for the next checkout.
- In the Activity log
- One "Returned" event titled "Checked in from [previous assignee]", with your note as its body and the previous assignee as the target.
- Toast
- "Asset checked in." — then the page reloads.
Who can do what, in each state
"Checked out" means the asset has an assignee and its endorsement status is anything other than Returned. The "Actions" dropdown on the detail page shows exactly the actions valid for the current state and viewer:
| Endorsement state | Available lifecycle actions | Who can act |
|---|---|---|
| — / Returned (not checked out) | "Check out asset" | Holder of asset_checkout (status must be Deployable or empty) |
| Assigned | "Confirm receipt" · "Request return" · "Check in asset" | Confirm receipt / Request return: assignee (or admin) · Check in: asset_checkout |
| Acknowledged | "Request return" · "Check in asset" | Request return: assignee (or admin) · Check in: asset_checkout |
| Return requested | "Check in asset" (and "Confirm receipt" if receipt was never confirmed) | Check in: asset_checkout · Confirm receipt: assignee (or admin) |
"Audit asset" (asset_audit) and "Edit" (asset_update) are available in
every state — see Auditing Assets. For "Confirm receipt" and
"Request return", the dropdown item is shown only to the assignee; an admin is authorized
server-side but gets no menu entry. The full permission matrix is in
Permissions & Roles.
Events written per action
Every lifecycle action appends exactly one event to the asset's Activity timeline (the chain of custody, newest first — see Asset Detail & Activity). Each event carries the acting user and the UTC time it occurred; all kinds render with the same blue chip in the timeline.
| Action | Event kind | Event title | Body / extras |
|---|---|---|---|
| Check out | Endorsed | "Checked out to [assignee]" | Your note; target = the assignee. |
| Confirm receipt | Acknowledged | "Receipt confirmed." | "Signed: [name]" when a signature was typed; plus the acceptance timestamp and — when the category required acceptance — the frozen agreement snapshot and the typed signature. |
| Request return | Return requested | "Return requested" | Your note; target = the assignee. |
| Check in | Returned | "Checked in from [previous assignee]" | Your note; target = the previous assignee. |