Skip to content

bug(compose): nothing gates on email verification, so posting fails at publish time (G38) #41

Description

@Adron

Summary

The platform requires a verified email before a user can post a message or attach media. The macOS app decodes the flag, renders it once in Settings, and gates nothing on it — so an unverified user writes a whole message (or picks images) and only finds out at publish time, from a server error.

The documented rule

/help/settings: "You must verify your email before posting messages or attaching media. If you did not receive the verification email, click Resend verification email in the Security section. You can resend once every 10 minutes."

/help/messages: "You must have verified your email before you can post images or video." and "You must verify your email address before posting messages."

/help/direct-messages: "You'll need a verified email address to send images" in a DM.

What we ship today

  • CurrentUser.isEmailVerified (CurrentUser.swift:57) is modelled and mapped (Mappers.swift:39).
  • Its only consumer is AccountSettingsView.swift:114, which displays it.
  • Nothing in the composer, the media picker, or the DM image path consults it.

Backend constraint to resolve first

POST /api/auth/send-verification-email is declared x-auth-type: session in the live OpenAPI spec — a Bearer-only client cannot call it. Verify this against the live API before building the resend button:

POST https://interlinedlist.com/api/auth/send-verification-email   (Bearer)

If it genuinely rejects Bearer, the resend action must deep-link to the web Settings ▸ Security page instead of calling the route, and the backend ask should be filed with the other session-only-route asks. Do not ship a button that silently 401s.

Division of labor

Kit

  • Add the resend request builder only if the live probe shows Bearer is accepted. Otherwise skip Kit entirely and go with the deep-link.

Domain

  • A single PostingEligibility (or equivalent) projection that answers "can this account post / attach media right now, and if not, why" from CurrentUser. Keep it separate from EntitlementsService — verification is not a subscription tier — but make the composer consult both.
  • Model the 10-minute resend cooldown so the UI can disable the button and say when it will be available again, rather than letting the user hammer a rate-limited route.

App

  • Composer: when unverified, disable Post with an inline, non-modal explanation ("Verify your email before posting") plus the resend/deep-link action. Do not block typing — let the draft survive.
  • Media picker and DM image attach: same gate, same explanation.
  • Settings ▸ Account: put the resend action next to the existing verified indicator, with the cooldown surfaced.

Tests

  • happy — verified account → composer posts normally
  • invalid — unverified → Post disabled, explanation shown, draft preserved
  • upstream-failure — resend returns 429 → cooldown message, button disabled, no crash
  • boundary — cooldown boundary (just under / just over 10 minutes)

Acceptance criteria

  • An unverified account is told before composing, not after publishing.
  • The resend action either works over Bearer or opens the web page — never fails silently.
  • Full E2E gate green.

Notes

work-consolidation.md tracks this as G38. Size S. Related: the account-status gate issue covers the other reason a new account cannot post (rate limits on "new" accounts), which is a different mechanism with a different message.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingparityWeb-parity gap with the InterlinedList web app

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions