Reader questions and feedback
The submitted-question queue and the helpful/unhelpful votes — who may submit, the rate limits, what answering a question actually sends, converting one into an article, and what the feedback comments can and cannot tell you.
Two inbound channels. A question is a reader telling you the library has a hole; feedback is a reader telling you an existing article is not doing its job. They arrive on different screens and are worked differently.
Questions are a queue with people waiting at the end of it. Feedback is a signal you read in aggregate. Work the queue first — that is why Questions sits above Feedback in the navigation.
Submitted questions
A signed-in reader who cannot find an answer can submit one from the help centre. The form takes an email address and the question.
Who may submit
Three gates, in order:
- Signed in. The endpoint requires a session. There is no anonymous submission.
- The
ask_faqKYC feature, shown in the level builder as Knowledge Base Inquiries. Configured per KYC level at Admin → CRM → KYC; recommended level 1. If the reader's level does not carry it, submission is refused. - Five per 24 hours, per reader. Fixed in code, enforced in Redis, not configurable.
What is validated
| Field | Rule |
|---|---|
| Must be a valid address, at most 254 characters. Lower-cased and trimmed before storage | |
| Question | 10–500 characters after trimming. Markup and control characters removed |
The submitter's name is taken from their account, not from the form — first and last name as held on the user record. The email is whatever they typed, which is not necessarily their account address. That distinction matters when you answer.
Working the queue
The queue is at /admin/faq/question, gated on access.faq.question. It is
paginated, filterable by state and searchable across the question text, submitter
name and email — all three server-side, so the search reaches the whole table
rather than the page on screen. The tab badges count the whole table too.
The queue used to load a flat first hundred rows with no pagination and no filter, and the screen did its tab-splitting and searching in memory over that one array. Once a hundred questions had accumulated, the oldest still-pending ones fell off the end — gone from the Pending tab, invisible to the search box, and reachable by no URL. Those people's questions could never be answered.
If you are upgrading from an older build, open the Pending tab and sort back. You may find a backlog you did not know existed.
Three states: PENDING, ANSWERED, REJECTED. You can set the state directly,
or you can answer, which sets ANSWERED for you.
What answering actually does
Answering writes the answer onto the question row, sets the state, and then notifies the asker on two channels:
- An email to the address on the form, quoting their question and carrying your answer.
- An in-app notification, but only if that email address matches a registered account. Since the form accepts any address, the asker and the account that submitted are not necessarily the same person — so the notification is conditional and the email is not.
Both are best-effort. The answer is already committed before either is attempted, so a mail outage cannot lose your work; the failure is written to the backend log instead. Check the log if an asker says they never heard back.
Answering used to update the row and stop there — while the public form promised "We'll send you an email when we have an answer for you" and the admin screen confirmed "Answer Sent." Neither was true. There was no email, no notification, and no page anywhere in the product where the asker could read the answer.
Both sides believed the exchange had completed. If you ran an older build, every question you answered on it reached nobody.
There is no thread. The asker cannot reply, and there is no place in the product where they can go back and read the answer. It is a one-shot exchange by design; anything that needs a conversation belongs in Support.
Converting a question into an article
The queue has a Convert action that opens a pre-filled article editor: the question text becomes the article question, the answer you wrote becomes the answer, and you supply a category and a page path. Saving creates a published article and marks the question answered.
This is the habit worth building. A question that was worth answering once is worth answering publicly, and the whole point of the queue is to feed the library. A queue you clear without converting anything produces the same questions again next month.
Feedback
At the foot of every article, a reader marks it helpful or not, optionally with a comment.
| Rule | Value |
|---|---|
| Sign-in | Required |
| Rate limit | 20 submissions per hour, per reader |
| One vote per reader per article | Enforced by a unique index; voting again updates the existing row |
| Comment | Optional, at most 1,000 characters |
Changing your mind is supported — a second vote overwrites the first rather than adding a second row. That means the helpful percentage is a count of people, not of clicks, which is the number you want.
A quirk to know: when a repeat vote arrives without a comment, the existing comment is kept rather than cleared. A reader cannot remove a comment by voting again.
Reading feedback
The Feedback screen at /admin/faq/feedback is gated on access.faq.feedback.
It is paginated and filterable — all, helpful, unhelpful, or only those with
comments — and the search matches both the comment text and the article's question.
Each row carries the article it belongs to, so the list shows a title without a
second lookup, and the header counts are computed over the whole table.
Start with the comments filter. A thumbs-down with no comment tells you an article failed; a thumbs-down with a comment usually tells you why. That is the difference between knowing you have a problem and being able to fix it.
There is no moderation queue for feedback. Comments are not published anywhere on the reader side — they exist only for you — so there is nothing to approve. The only controls are the one-vote rule and the hourly limit.
Feedback rows survive the article they describe. Deleting an article is a soft delete and does not cascade, so a comment about a retired article can still appear in the list.
Which articles are failing
The dashboard turns feedback into a ranked list of articles readers are voting down, under two thresholds:
- An article needs at least three responses before it can appear. One thumbs-down on a new article is 0% helpful and means nothing; without a floor the list would be topped by articles two people have read.
- Below 50% helpful, an article is treated as failing. Below 25% it is flagged critical — between the two it is work rather than a failure.
Neither threshold is configurable.
The list shows the eight weakest, worst first, each with its helpful share, the number of responses behind it and its view count. The count on the tile above it is the true total of underperforming articles, not the length of the list — so a tile reading 30 above a list of 8 is correct, not a bug.
An article nobody has voted on reads not rated yet, not 0%. A percentage over no responses is unknown, not zero. Older builds printed 0% positive for unrated articles, which routinely libelled the most-read article on the site.
Working the two together
The two signals answer different questions and are best read in sequence.
Feedback tells you which existing articles are wrong. Fix those first — a failing article is worse than a missing one, because the reader stopped looking. Then take the zero-result searches from the search report, which tell you what is missing. Then work the question queue, which is the same signal with a person attached and a deadline implied.
The dashboard's oldest-unanswered-question figure is the one to watch. Nothing in this addon escalates or reminds; if that number is measured in weeks, no automated process anywhere will tell you again.