SPEC_ANSWERHUB_LIVE.md

AnswerHub — the first real run — spec

What this covers: walking AnswerHub end to end on the tailnet with a real browser and a real siao.ai account, and fixing everything that walk finds. Also the three already-known AnswerHub defects, and the sign-in page's visual alignment with the app family.

For what is actually built, deployed or reachable, see ClaudeDocs/HANDOFF.md — status deliberately does not live here.

This spec builds on SPEC_ACCOUNTS.md (which owns the identity model) and SPEC_ANSWERHUB_FRONTEND.md (which owns the restyle). It does not supersede either. It supersedes nothing; it finishes something.

No issue tracker exists for this project, and no triage-label vocabulary was available, so this spec is filed as a ClaudeDocs/SPEC_* document — the same precedent SPEC_APPS.md recorded.

Problem Statement

AnswerHub's frontend restyle shipped, its credential store was deleted, and it became an OIDC client of accounts.siao.ai. The container runs on the tailnet and every page answers 200. /answerhub/login redirects correctly to Logto's authorization endpoint with PKCE parameters attached.

Nobody has ever completed a sign-in.

Every claim about AnswerHub's identity integration rests on unit tests, Playwright tests against fixtures, and an HTTP probe that stops at the redirect. The parts that only exist in the real deployment have never run once: the token exchange against the live provider, the userinfo call, first-sign-in provisioning of an AnswerHub profile, the member number that provisioning mints, the session cookie surviving a return visit, and RP-initiated logout actually ending the provider's session. The same is true of everything downstream of being signed in — uploading a submission, liking, commenting, editing a profile, and the entire administrator surface, which has never been exercised by an account that actually holds the ADMIN role.

Two documents also describe a system that no longer exists, which means anyone planning work from them plans it wrong:

Separately, three defects are known, recorded, and unfixed. Two of them are correctness and security problems that this walk will run straight into: profile links accept javascript: URLs, and a submission an administrator has taken down still accepts likes and comments. The third is that listing queries fetch whole rows, including each submission's files blob, to render a title.

The like-and-comment defect deserves its own sentence, because it explains why the project's existing guard did not catch it. AnswerHub has a structural test that finds every file reading a content model and requires it to consult the visibility seam. That test matches reads. The like and comment routes never read a submission — they write to one directly. They were invisible to the guard built to catch exactly this class of bug.

Solution

Walk the whole product, on the real deployment, with a real browser, against the real identity provider — then fix what that produces.

The walk covers the identity loop twice (a freshly registered account, to exercise first-sign-in provisioning, and the owner's own account, to exercise the return path), then the ordinary user's actions, then the administrator's, after promoting the owner's AnswerHub profile to ADMIN. It stays on the tailnet. No DNS record, tunnel ingress rule or certificate work is part of this. Sign-in is email plus verification code; Google is deliberately left for the session that settles the public domain name, so its redirect URI is registered once rather than twice.

Fixes land in one pass after the walk, not incrementally during it, so that the shape of the real problems is known before any of them is addressed. The bar for "in scope" is broad: anything broken, anything plainly wrong, and anything plainly unpleasant to use — missing loading states, unhelpful errors, bare empty states, form validation that gives no feedback, layouts that fail on a phone. Pure aesthetic refinement — spacing, weight, rhythm — is a separate round, so this one can finish.

The three known defects are all fixed. Two of them route through seams that already exist rather than adding new checks: the like and comment routes consult the visibility seam, and the structural guard is widened so that writing against a submission counts as needing a visibility decision, not only reading one. The javascript: URL hole gets the one genuinely new seam in this spec — a protocol allow-list applied at the point of rendering, because that covers rows already sitting in the database as well as any future write path.

The Logto sign-in page is treated as part of AnswerHub's interface, because a user really does land on it mid-flow and a page that does not look like siao.ai is a failure of "connected up properly". Its visuals and its Traditional Chinese copy are brought in line with the app family. Its authentication methods are not touched, and Logto's attribution stays.

Deployment goes through the SSH bare mirror, with a rollback commit recorded first.

User Stories

Signing in for the first time

  1. As a new visitor, I want to click a single sign-in control on AnswerHub and arrive at accounts.siao.ai, so that I never have to find a separate registration step.
  2. As a new visitor, I want to register with only my email address, so that I am not asked to invent a password for a site that stores none.
  3. As a new visitor, I want the verification code email to arrive in Traditional Chinese and name siao.ai, so that I can tell it is the message I just asked for and not a phishing attempt.
  4. As a new visitor, I want the verification code to be accepted and to land back on AnswerHub already signed in, so that the round trip feels like one action rather than a departure and a return.
  5. As a new visitor, I want an AnswerHub profile created for me the moment I first arrive, so that there is no second registration to complete before I can do anything.
  6. As a new visitor, I want that profile to carry an AnswerHub member number, so that I have the platform's own identifier from the start.
  7. As a signed-in user, I want the header to show that I am signed in and to offer my profile, so that I can confirm the sign-in actually took effect.

Staying signed in, and signing out

  1. As a signed-in user, I want to close the tab, come back, and still be signed in, so that routine use does not mean authenticating again.
  2. As a returning account holder, I want a second sign-in to find my existing AnswerHub profile rather than create a duplicate, so that my submissions, likes and member number stay attached to me.
  3. As an account holder whose email changed at the identity provider, I want AnswerHub's displayed address to follow it, so that what I see matches who I am.
  4. As a signed-in user, I want signing out to end the session at accounts.siao.ai too, so that the next sign-in genuinely asks who I am instead of completing silently.
  5. As a signed-out user, I want to be able to sign in again immediately afterwards, so that signing out is not a one-way door within a session.

Contributing and reading

  1. As a signed-in user, I want to upload an answer and see it appear, so that contributing works rather than merely appearing to.
  2. As a signed-in user, I want the upload form to tell me what is wrong when it rejects my input, so that I am not left guessing at a form that silently refuses.
  3. As a signed-in user, I want a visible indication while an upload is in progress, so that I do not submit twice believing nothing happened.
  4. As any visitor, I want a submission's detail page to render its title, description and files, so that the thing I came to read is readable.
  5. As a signed-in user, I want to like a submission and see the count change, so that the control is real rather than decorative.
  6. As a signed-in user, I want to comment on a submission and see my comment, so that the discussion feature works.
  7. As a signed-in user, I want to edit my bio and social links and have them persist, so that my profile is mine.
  8. As any visitor, I want the homepage search to behave predictably and state its own limitations, so that an unavailable feature reads as intentional rather than broken.
  9. As any visitor, I want a page with nothing on it yet to say so in words, so that an empty list is not mistaken for a failure.
  10. As a visitor on a phone, I want every page in this walk to be usable at that width, so that the product is not desktop-only by accident.

Moderation

  1. As an administrator, I want my AnswerHub profile to carry the ADMIN role while my siao.ai identity stays untouched, so that authorisation remains AnswerHub's own concern.
  2. As an administrator, I want to see the review list of submissions, so that moderation has a working entry point.
  3. As an administrator, I want to hide a submission and have it vanish from the homepage, from search, and from its own detail page, so that a takedown is a takedown.
  4. As an administrator, I want a hidden submission to stop accepting likes, so that a taken-down item cannot keep accruing engagement.
  5. As an administrator, I want a hidden submission to stop accepting comments, so that a taken-down item cannot keep accumulating replies nobody can see.
  6. As an administrator, I want to ban an account and have that account lose its ability to upload, so that suspension has teeth.
  7. As an administrator, I want banning someone on AnswerHub to leave their siao.ai account and their access to other applications completely alone, so that one product's moderation decision does not become the family's.
  8. As a non-administrator, I want the moderation surface to refuse me, so that the role means something.

Safety

  1. As any visitor, I want a link on someone's profile to be unable to execute code when I click it, so that reading a profile is safe.
  2. As any visitor, I want that protection to cover profiles saved before the protection existed, so that the fix is not only forward-looking.
  3. As a user editing my own profile, I want an unusable link to be rejected while I am still on the form, so that I find out at the time rather than discovering later that my link does nothing.
  4. As a developer adding a route that writes to a submission, I want the test suite to fail unless I have made a visibility decision, so that the next instance of this bug is caught by machinery rather than by an audit.
  5. As a developer adding a page that renders a user-supplied URL, I want the test suite to fail unless I have routed it through the allow-list, so that the protection cannot be quietly bypassed.

The sign-in page as part of the product

  1. As a visitor being sent to sign in, I want the page I land on to carry siao.ai's colors and typography, so that I can tell I have not been redirected somewhere hostile.
  2. As a Traditional Chinese speaker, I want the sign-in page's wording to be in my language and to name the product, so that the handover between applications does not switch languages under me.
  3. As the owner, I want Logto's attribution to remain visible, so that the terms under which the software is given away are honoured.
  4. As the owner, I do not want the sign-in page's authentication methods changed in this pass, so that a visual fix cannot break the only way into the product.

Operating it

  1. As the owner, I want the code that runs on the host to be the code in the repository, so that the deployment is reproducible rather than incidental.
  2. As the owner, I want a recorded rollback point before the deploy, so that a bad build is one command away from being undone.
  3. As the owner, I want the documents describing this system to match it, so that the next session does not plan against a sign-in experience that was replaced.
  4. As the owner, I want the credentials exposed while investigating this work to be listed for rotation, so that an accidental disclosure is closed rather than forgotten.
  5. As the owner, I want the test account created during this walk to be identified clearly and its removal described, so that it does not become permanent fixture data nobody dares delete.

Implementation Decisions

Testing Decisions

Out of Scope

Further Notes