Ownware
Home›Helpora›Manual
Helpora · Manual

Helpora Manual, as shipped in the download

Helpora — User Manual

A support desk you can be honest about: requests, threads, response and resolution targets, and a clock that cannot be improved without answering somebody. Version 1.0.3 [src: app/controllers/api.php:25].

About this manual

Every statement here was written by reading Helpora's own source, and each one carries the file it came from in a bracketed src marker. Paths are relative to the folder this docs directory sits in. If a sentence disagrees with the application, the application is right and this manual has a bug.

Nothing is described that the code does not do. Where something is deliberately limited, or currently wrong, that is said plainly rather than left out.

⭐ The clock is the product

The source opens with the argument the whole design rests on [src: app/src/Request.php:5]:

Every help desk reports response times. Almost every one of them can be made to report better ones than it earned, because the timer is reset by things that are not an answer: an internal note, a reassignment, a status change, an auto-reply. A desk whose numbers can be improved without answering anybody is not measuring service, it is measuring how well its agents know the tool.

Four rules follow, and all four are enforced in one file.

1. The first response happens once

first_response_at is stamped by the first message that actually goes to the requester, and is never written again [src: app/src/Request.php:13]. The write is guarded — WHERE first_response_at IS NULL — so two agents replying in the same second cannot both claim it: the loser matches zero rows and the earlier stamp stands [src: app/src/Request.php:14].

Nothing else touches it: no note, no reassignment, no status change, no reopening [src: app/src/Request.php:16].

2. You cannot close what you never answered

Resolving or closing a request that has never had an outbound message is refused, because a desk that can close in silence will, and its numbers will look excellent [src: app/src/Request.php:19]. Executed, with the refusal it actually produces [src: app/src/Request.php:446]:

status new,  never answered  ->  "This request has never been answered. Write to the person who
                                  raised it before resolving or closing it — a desk that can settle
                                  in silence will, and its response times will look excellent."
status open, never answered  ->  same refusal
status open, answered        ->  allowed

3. The only pause is waiting on the requester, and it costs the first response nothing

You may stop the resolution clock while genuinely waiting for the person who asked — but only after you have written to them, because otherwise "waiting on the requester" means "waiting for them to guess we need something" [src: app/src/Request.php:23]. The pause ends by itself the moment they reply.

And the first-response clock cannot be paused at all: there is no state of the world in which you are waiting on somebody to hear back from you for the first time [src: app/src/Request.php:27].

Executed [src: app/src/Request.php:461]:

open, nothing sent yet  ->  "Nothing has been sent to the requester yet, so they are not the ones
                             being waited on. Ask them the question first, then mark it waiting."
open, already answered  ->  allowed
already resolved        ->  "That request is already settled."

4. A deadline only ever moves later

Targets land on working days; a weekend or one of your own non-working days rolls the observed date forward. The policy date itself is never rewritten, and both are shown, so nothing becomes breached sooner because a holiday was added [src: app/src/Request.php:30].

Executed with Monday 7 September marked as a company non-working day [src: app/src/Request.php:198]:

policy 2026-09-04 (Fri)  ->  observed 2026-09-04
policy 2026-09-05 (Sat)  ->  observed 2026-09-08
policy 2026-09-06 (Sun)  ->  observed 2026-09-08
policy 2026-09-07 (Mon, non-working)  ->  observed 2026-09-08

The same arithmetic applies to the hour, not just the day. A four-hour response target set at five o'clock on that Friday lands at one o'clock on the Tuesday once the weekend and the closed Monday are stepped over [src: app/src/Request.php:135]:

response, 4h from 2026-09-04 17:00   ->  2026-09-08 13:00
resolution, 2 days from the same     ->  2026-09-09

Targets per priority

Four priorities, each with a response target in hours and a resolution target in days [src: app/src/Request.php:61]. Executed:

urgent   1 hour    1 day          normal    8 hours   5 days
high     4 hours   2 days         low      24 hours  10 days

Requesters do not need an account

A request is identified by an unguessable code [src: app/src/Request.php:88] and followed up with a passphrase, of which only the hash is kept [src: app/src/Request.php:324]. There is no account to create and no password to reset.

An email address is optional. Replies always reach the requester on their request page, behind the reference and passphrase. With Settings → Email the requester switched on (it is off by default), a requester who gave an address is also emailed when you reply and when you resolve or close the request [src: app/src/helpers.php:174]. The email carries the reference, their own summary line and the address of the request page — never your reply, an internal note or their passphrase — and each send, or the reason it did not send, is written on the request's log. With no address, nothing can be emailed, which the interface says rather than hides [src: app/src/Request.php:36].

Mail goes through your own SMTP server; the Security setting offers STARTTLS (usually port 587), SSL/TLS (usually port 465) or none for a local relay.

Month arithmetic

Where a month has to be added, it clamps to the end of the target month rather than overflowing [src: app/src/Request.php:97]. Executed against PHP's own:

2026-01-31 + 1 month   PHP: 2026-03-03    Helpora: 2026-02-28
2026-08-31 + 6 months  PHP: 2027-03-03    Helpora: 2027-02-28

Users and roles

Three roles [src: app/controllers/v3.php:60]. A member can handle requests and read the thread [src: app/controllers/v3.php:61]; admin holds everything.

A viewer is granted audit.view explicitly, written into the role by name rather than inherited from a wildcard [src: app/controllers/v3.php:60], and the audit page requires exactly that [src: app/controllers/v3.php:659]. On a desk whose value is the honesty of its numbers, letting a read-only account see who changed what reads as deliberate — but if you expected otherwise, change the role.

Backups are gated on settings.edit [src: app/controllers/api.php:238], which no role below admin holds [src: app/controllers/api.php:246].

Webhooks

The events you can subscribe to are the events the app sends [src: app/src/Webhook.php:22]:

eventsent when
request.createda request arrives through the form
request.first_responsethe first reply to a request is sent — once per request
request.messagethe requester writes back
request.status_changeda request moves, on the board, the request screen, in bulk or through the API
request.settleda request is resolved or closed

An endpoint with no events ticked receives all of them. An endpoint saved before this release under the older names case.created, case.message or case.status_changed receives the matching request.* event [src: app/src/Webhook.php:25]. Payloads carry the reference, the queue, the status and the clock facts — never the request text or a message body.

The API and agent access

Five tools [src: app/controllers/v3.php:309]: three read — the request list, one request in detail, and the statistics — and two write, posting a handler message [src: app/controllers/v3.php:368] and settling a request [src: app/controllers/v3.php:397].

The statistics tool reports first-reply performance as met, missed and never answered [src: app/controllers/v3.php:470] — the third figure being the one a desk with a silent-close habit would rather not publish.

An agent settling a request goes through the same refusal as a person: it cannot close what was never answered.

What Helpora does not do

It does not let a note, a reassignment or a status change stamp a first response [src: app/src/Request.php:16].

It does not let two agents both claim the first reply [src: app/src/Request.php:14].

It does not allow a request to be settled in silence [src: app/src/Request.php:19].

It does not let you pause a clock before you have written to anybody [src: app/src/Request.php:23].

It does not pause the first-response clock at all [src: app/src/Request.php:27].

It does not move a deadline earlier [src: app/src/Request.php:30].

It does not store a requester's passphrase [src: app/src/Request.php:324].

← Back to Helpora · Quickstart · API · Test run

Affiliate program
Recommend tools people own — earn 35% on every sale. 90-day tracking, instant delivery, payouts by Lemon Squeezy.
Become an affiliate →