Skip to content

Org member + domain management endpoints; enterprise domains → pro credits; PRO_CREDITS → 9,999 #1841

Description

@sweetmantech

Tracking issue for the platform gaps surfaced while onboarding the Seeker Music org on 2026-07-03 (api#746): org membership and org-domain management have no API endpoints (both required direct SQL), enterprise-domain accounts still land on the 333 free credit tier, and the pro tier itself is being raised. All 11 PRs are merged and live (implementation: docs#261, api#748/#749/#747, chat#1842, docs#263; process: skills#58/#68, api#750, chat#1843, mono#42). Remaining: the two Open — process items.

Decision (sweetmantech, 2026-07-03): all PRs target main; the api/chat test-branch PR flow is retired. api#747/#748/#749 and chat#1842 were opened against test per the then-current CLAUDE.md instructions and retargeted to main the same day (all clean — branches were cut from origin/main). Root-cause docs fixed by api#750 / chat#1843 / mono#42; the ship-issue skill fix was already in flight as skills#68. Supersedes the "base test" notes elsewhere in this issue.

Decision (sweetmantech, 2026-07-03): chat#1842 rescoped from mirror to consolidation. Chat stops computing credits in its duplicated stack; the sidebar consumes the api's GET /api/accounts/{id}/credits (bearer auth) and chat's /api/credits/get route, checkAndResetCredits, dead initializeAccountCredits, and credit constants are deleted. Rationale: tracing showed chat's stack had one live consumer (useCredits/api/credits/get) plus dead code; mirroring would have committed every future credits change to two repos back-to-back. Credits logic now lives only in api.

Goal

Four deliverables, all in the existing api/chat/docs stack (no new tables — account_organization_ids and organization_domains already exist):

  1. Org member endpointsPOST + DELETE /api/organizations/members so members can be added/removed via the API instead of SQL inserts into account_organization_ids.
  2. Org domain endpointsPOST + DELETE (+ GET) /api/organizations/domains to manage organization_domains rows (email-domain auto-join, consumed by assignAccountToOrg).
  3. Enterprise domains grant pro credits — accounts whose email domain is in ENTERPRISE_DOMAINS resolve is_pro: true in the credits system, in both api and chat.
  4. Raise PRO_CREDITS from 1,000 to 9,999 per month, in both repos plus the docs example.

PRs (updated 2026-07-03)

PR Item Base State
docs#261 OpenAPI contract: org members add/remove + org domains add/remove/list; credits example → 9,999 main ✅ merged 2026-07-03 — see Done. 401-envelope reconciliation still pending post-preview-verify
api#748 POST + DELETE /api/organizations/members main ✅ merged 2026-07-03 — see Done
api#749 GET + POST + DELETE /api/organizations/domains main ✅ merged 2026-07-03 — see Done
docs#263 Error envelope reconcile: member/domain errors are {status, error} (ErrorEnvelope schema; closes the 401 drift) main ✅ merged 2026-07-03
api#747 Enterprise-domain accounts resolve pro in credits + PRO_CREDITS → 9,999 main ✅ merged 2026-07-03 — see Done
chat#1842 Consolidation: sidebar consumes the api credits endpoint; chat's duplicated credits stack + stripe dependency deleted main ✅ merged 2026-07-03 — see Done
skills#58 PRs-matrix section + #TBD/PR-open upkeep rules in recoup-internal-dev-issue-tracker; KISS pass (Base column dropped, stale test-branch guidance + gh quick-ref deleted) main ✅ merged 2026-07-03
skills#68 ship-issue skill: targets main, PR-open matrix rule, KISS pass (Principles section deleted, JSON + preview-auth lessons corrected) main ✅ merged 2026-07-03
api#750 api CLAUDE.md: PRs target main; retire test-branch flow main ✅ merged 2026-07-03
chat#1843 chat CLAUDE.md: PRs target main; retire test-branch flow main ✅ merged 2026-07-03
mono#42 monorepo AGENTS.md: all submodule PRs target main main ✅ merged 2026-07-03

Error-envelope convergence (2026-07-03, via api#749 review): the members+domains surface now emits {status: "error", error} everywhere via the shared errorResponse helper — matching the 401s validateAuthContext always emitted. docs#263 reconciles the contract (supersedes the earlier plan to patch only the 401 blocks). The artists endpoint keeps {status, message}.

Merge sequencing (docs-first): docs → api → chat. The docs OpenAPI change is the contract the api PRs fulfill. The two credits PRs (api + chat) should land back-to-back — chat duplicates the entire credits stack (chat/lib/credits/checkAndResetCredits.ts, chat/lib/consts.ts L55-56), so a gap between them means the sidebar shows a different tier than the API grants. The two endpoint PRs are independent of the credits PRs and of each other.

What we noticed (context)

All findings from the 2026-07-03 Seeker Music onboarding, verified against prod:

  • Org Seeker Music 5d2be75b-b49b-4c2a-ac0a-63d812430dda (creator: sidney@recoupable.com). Adding its 4 members required a direct SQL insert into account_organization_ids — the only API paths that write membership are org creation (createOrganizationHandler, creator only) and email-domain auto-join.
  • The seekermusic.com → org mapping likewise required a direct SQL insert into organization_domains. Auto-join then verified end-to-end: POST /api/accounts with a @seekermusic.com email joins the org with no duplicate membership rows.
  • api#746 (merged + deployed 2026-07-03) added seekermusic.com to ENTERPRISE_DOMAINS — but that list feeds exactly one consumer: getProArtists → the nightly pro-artist-social-profiles-scrape cron. It has zero references in lib/credits, lib/stripe, or anywhere in chat. Verified live post-deploy: GET /api/accounts/8bd4cb8e-30fe-43a6-8584-3803ebbca2fe/credits (evan@seekermusic.com) still returns is_pro: false, total_credits: 333.
  • Rostrum's 1,000/mo tier comes from an active Stripe subscription resolved through Rostrum Pacific org membership (getAccountSubscriptionStategetOrgSubscription), not from the domain list — live-verified is_pro: true, total_credits: 1000 for benjy@rostrum.com and jonathan@rostrum.com, while stale rostrum-domain accounts that predate their last access sit at 333 until their next lazy refill.

Open — process

  • DB unique constraints for org membership + domain mappings — spun out to chat#1844 (database migration + upsert conversion; closes the check-then-insert races flagged on api#748/Create a separate YoutubeVideoCard for better code management and rea… #749).
  • chat previews consume the api test-branch deployment (test-recoup-api.vercel.app) — repoint or auto-sync.
    • Why: with PRs now targeting main, test only moves when someone syncs it; it drifted 3 commits stale on 2026-07-03 and chat previews showed total_credits: 1000 after api#747 was already on prod (caught during chat#1842 browser verification; manually synced 0550e9fd).
    • Fix (pick one): point chat's preview env api-base at the prod api; or auto-sync testmain on merge (workflow); or per-PR api preview URLs.
    • Done when: a fresh api main merge is visible from a chat preview without a manual test sync.
  • chat previews consume the api test-branch deployment (test-recoup-api.vercel.app) — repoint or auto-sync.
    • Why: with PRs now targeting main, test only moves when someone syncs it; it drifted 3 commits stale on 2026-07-03 and chat previews showed total_credits: 1000 after api#747 was already on prod (caught during chat#1842 browser verification; manually synced 0550e9fd).
    • Fix (pick one): point chat's preview env api-base at the prod api; or auto-sync testmain on merge (workflow); or per-PR api preview URLs.
    • Done when: a fresh api main merge is visible from a chat preview without a manual test sync.
  • Add PR-matrix upkeep rules to the two issue skills. (tracker skill shipped via skills#58 ✅; ship-issue skill pending in skills#68)
    • Why: neither skill covers matrix rows for not-yet-opened PRs. On this issue, four PRs were open before the matrix was updated (caught by review 2026-07-03); recoup-internal-dev-issue-tracker only covers keeping State current for existing PR refs, and recoup-internal-dev-ship-issue only updates the tracker at merge (step 8), not at PR-open.
    • Fix: one PR to recoupable/skills touching both SKILL.md files. Tracker skill: planned rows may use repo#TBD | item | base | ⏳ not started so the fleet is visible before implementation. Both skills: replace the #TBD placeholder with the live PR ref + verification status in the same session the PR opens — opening a PR without updating its matrix row is drift, same class as a merged PR without a closure note. Per the prune-as-you-add rule, cut any now-redundant wording while adding.
    • Done when: both SKILL.md files state the PR-open-time matrix update; npx skills add recoupable/skills reflects it; no duplicated guidance between the two skills.

Architecture decisions

  • Enterprise status stays a code-level domain list for now. ENTERPRISE_DOMAINS in api/lib/enterprise/consts.ts currently gates only the nightly social scrape; this issue extends it to the credits tier. Moving it to a DB table is out of scope (adding a domain today = one-line PR, e.g. api#746).
  • Credits pro-status precedence: active Stripe subscription (account or org) OR enterprise email domain. Stripe stays the only path that carries current_period_start (early-refill trigger) and payment rails.
  • Credits logic lives only in api (decision 2026-07-03, supersedes the earlier accept-the-duplication stance): chat consumes GET /api/accounts/{id}/credits and its own credits computation is deleted (chat#1842).

Source references

  • Reference issues for house style: chat#1747, chat#1767
  • api#746seekermusic.comENTERPRISE_DOMAINS (merged 2026-07-03, commit 97735c53)
  • Docs surface for the new endpoints: docs/api-reference/openapi/accounts.json (/api/organizations* paths) + docs/api-reference/organizations/*.mdx

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions