# The reporter portal (https://docs.vitrinka.ai/qa/portal)



## Where it lives [#where]

Every project has a portal for the people who report problems to it. On the hosted service it is at `https://portal.vitrinka.ai/<workspace>/<project>`; on your own deployment, under the portal origin your operator sets ([running the portal](#operator)). A team that wants its own address, such as `support.example.com`, can have it bound to one project's portal, and that domain then serves the portal from its root.

The portal is a public surface of its own. It answers its pages and nothing else — never the team's app, its API or its sign-in — so a reporter's way in is never a way into the workspace. It speaks Czech or English, following the browser.

Custom domains are bound by deployment authority, because each one needs its DNS, its edge configuration and a certificate first: on the hosted service, ask us; on your own deployment, the operator binds it in **Settings → Workspace → Reporters → Portal domains** once the edge serves it — [the reporter portal for operators](/operator/install#portal).

## Signing in [#signin]

There is no password, ever.

* **From your app.** If your app vouches for its users in [Report a problem](/qa/report-a-problem#identity), the same signed token opens the portal already signed in: link to any portal page with the token in the fragment, `#host=<token>`. The fragment never travels in a request line; the page trades it for a portal session.
* **With an email.** Anyone else types their address and receives a 6-digit code and a link. Typing the code signs this tab in. Opening the link in another tab of the same browser confirms the sign-in on a page of its own, and the tab that is waiting for the code signs itself in a moment later, with nothing to copy back. Opened on another device, the link signs in that device only — type the code to sign this tab in too. A code lives 15 minutes and allows five tries. The link never signs anyone in on its own, so a mail scanner that opens it does nothing.

Email sign-in needs outbound mail on the deployment; without it the portal says so, and only your app's token can sign people in.

A portal session lasts 30 days in that browser and is good for that portal only. Reports someone sent under their address before proving it — from an app that passed only their email — become theirs the moment they first sign in.

## My reports [#reports]

**My reports** is an updates feed, newest first: a report moving a step, a reply from the team, something you wrote. **All my reports** lists everything you sent here.

Each report reads as a story, along these steps:

| Step        | When                                              |
| ----------- | ------------------------------------------------- |
| Received    | The team has it and has not planned it yet.       |
| Planned     | It is in a sprint.                                |
| In progress | Someone is working on it, or it is in review.     |
| Fixed       | The fix is done and the team waits for your word. |
| Done        | You confirmed it works.                           |

A report the team declines, or merges into another one, reads **Closed**. Beneath the steps come what you wrote; **Before** — the places you marked, as pictures; **After** — the fix's picture when the team attached one; and the activity.

* **Email me when it's fixed** — a switch on each report. You get one email when it reaches Fixed, with a link back.
* **It works now** or **Still broken** — once a report reads Fixed, you answer. **It works now** moves it to Done. **Still broken**, with a line about what still goes wrong if you like, sends it back to the team's to-do and arms the email again for the next fix.
* **Write to the team** — a message on the report. The team's replies appear in your feed and arrive by email.
* **Report a problem** — the portal's own button sends a new report in words alone. It reaches the team's Inbox at once, from you.

The pages update by themselves while they are open.

## Privacy [#privacy]

* **Only your own.** A reporter sees a report only when it is theirs and belongs to the project this portal serves. Someone else's report and one that does not exist look the same: not found. A reporter reads the team's replies to them, never the team's own discussion on the task.
* **Not members, no seat.** A reporter is not a member of the workspace and never takes a seat. No role, board, search, agent tool or team API reaches them, and the app never accepts a portal session — even one signed for a team member's address.
* **Removing a reporter.** Workspace admins see every reporter in **Settings → Workspace → Reporters** — who vouched for them (the app, or an emailed code) and when they were last seen — and **remove** one. Their portal sessions end at once, and your app vouching for them later does not bring them back. Removal is audited as `reporter.revoke`.

## For the team [#team]

* Every report sent from the portal or the widget lands in the [Inbox](/pm/inbox); **Reply to reporter** there writes to the person — [replying](/pm/inbox#reply).
* The project's **Report a problem** tab in **Settings → Projects** shows the portal's address, beside the host signing key and the capture profile.

## Running the portal [#operator]

On your own deployment the portal needs `VITRINKA_PORTAL_ORIGIN`, a public hostname at your reverse proxy, and outbound mail — [the reporter portal](/operator/install#portal). Without it there is no portal, and Report a problem works without the **See your report** link.
