Skip to content

feat: add v1/v2 API paths with v2 backed by Bloom's GraphQL API - #46

Merged
franccesco merged 4 commits into
mainfrom
feat/v2-graphql-api
Sep 24, 2026
Merged

franccesco merged 4 commits into
mainfrom
feat/v2-graphql-api

Conversation

@franccesco

Copy link
Copy Markdown
Owner

Summary

Adds two API paths to Client and AsyncClient:

  • client.v1: the existing Bloom REST v1 operations, unchanged. The top-level attributes (client.user, client.issue, ...) are aliases of the same objects, so existing code keeps working.
  • client.v2: a new package (src/bloomy/v2/) that calls Bloom Growth's GraphQL API at https://app.bloomgrowth.com/graphql/, which is the API the current web app uses. It uses the same API key: the /graphql endpoint accepts the JWT from /Token.

client.v2 has sync and async operations for:

Namespace Operations
user details, list
meeting list, details, attendees
issue list (short-term / long-term / solved / archived), details, create, update (incl. move to another meeting), solve, reopen, archive, restore
headline list (by meeting or user), details, create, update, archive, restore
todo list (by meeting or user), details, create (meeting or personal), update, complete, reopen, archive, restore
goal list (by meeting or user, with milestones), details, create (with milestones), update (incl. status), archive, restore
milestone list, create, update, complete, delete
metric list, details, create, update, archive, scores, set_score, update_score, clear_score

Descriptions (notes) are supported on issues, headlines, to-dos, goals and metrics. Metric score cells also accept a note.

How the v2 API surface was determined

  • Captured from the web app: I did every create/edit/solve/complete/archive action in a test meeting ("v2 API", 349524) through Chrome and recorded the GraphQL operations the web app sent, including issues, headlines, to-dos, goals, milestones and KPIs with their descriptions.
  • Checked against the backend: the operations were then checked against the web-backend source and its checked-in schema snapshot (production has introspection disabled).
  • Server quirks handled in the SDK:
    • Descriptions are Etherpad pads. Writing one means creating a pad with CreateNote and pointing the item's notesId at it, which is what the web app does.
    • On meeting.metrics, the node id is a link id; the real metric id is measurableId.
    • The API reports long-term issues as archived, while the web app lists them on the Long-Term tab. The SDK reports them as not archived.
    • Weekly scores map to Sunday-anchored UTC weeks. Daily scores can't be upserted, so set_score edits the existing row instead.

Verification

  • ruff format --check, ruff check, and basedpyright (strict) are clean.
  • pytest -m "not integration": 834 passed on Python 3.12. Before the final refactor, 698 passed on 3.13 and 3.14 too. The v2 modules have 100% line coverage (base.py 99%).
  • Live integration tests against production (BG_API_KEY, test meeting 349524 only; the tests archive or delete what they create):
    • 45 v2 tests passed.
    • 134 v1 tests passed after the client wiring changed.
  • Checked visually in Chrome: I created one issue, headline, to-do, goal (with 2 milestones) and metric (with 2 weekly scores) through client.v2, each with a description. I checked them in the web app, edited them through the SDK and checked again, then archived them through the SDK and confirmed the workspace was empty. I did this twice, once before and once after the /simplify refactor.
  • mkdocs build --strict passes.

Review passes

  • /code-review: fixed missing-entity crashes, milestone updates writing before checking the goal id, merged lists that were out of order or made 3 requests, zero-valued scores being dropped, and the goal default due date using local time. One finding about deleted to-dos turned out to be a false positive.
  • /simplify:
    • Consolidated request building, result checks and not-found handling into the base.
    • Models now validate raw GraphQL nodes directly.
    • One current-user lookup per client.
    • To-do meeting lists no longer load the full to-do history.
    • Issue and to-do creates use the mutation result instead of re-reading.

Notes

  • Not changed, for you to decide:
    • list() queries select notesText, so every item with a description triggers one Etherpad lookup on the server. The web app's list views don't select it. Dropping it would make list() return items without descriptions.
  • Also in this PR:
    • .claude/agents/* now run on Opus instead of Sonnet.
    • CLAUDE.md documents the v2 package layout.
    • CHANGELOG has an [Unreleased] entry. The version is not bumped.

🤖 Generated with Claude Code

franccesco and others added 4 commits September 24, 2026 14:02
client.v1 exposes the existing REST v1 operations (the top-level
attributes remain aliases of the same objects). client.v2 exposes the
GraphQL API used by the Bloom Growth web app, with sync and async
operations for users, meetings, issues, headlines, to-dos, goals,
milestones, and metrics with scores, including descriptions.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
- Raise GraphQLError when an entity is missing or a create returns no id
- Verify a milestone belongs to its goal before editing; goal_id is keyword-only
- Fetch merged issue/headline lists in one request, deduped and ordered by creation date
- Keep zero-valued metric scores in scores()
- Use the UTC date for the default goal due date
- Document the v2 package layout in CLAUDE.md

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Shared request building and result checks live in the base and mixins
(_mutate, _one, _notes_input, input builders), models validate raw
GraphQL nodes directly, and one user-id cache is shared per client.
Merged issue lists, to-do lists by meeting, and user headline lists
filter on the server in one request; issue and to-do creates use the
mutation result instead of re-reading. v2 date parameters also accept
ISO 8601 strings.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@franccesco
franccesco merged commit a5d52c0 into main Sep 24, 2026
9 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant