# Changelog

All notable changes to this project are documented in this file.

The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [Unreleased]

## [0.2.0] - 2026-09-02

Coverage and packaging since the first Hex release. **Breaking for inbound
webhooks:** add [`ex_pipedrive_web`](packages/ex_pipedrive_web) if you used
`ExPipedrive.Incoming.Handler` from core.

### Added

- Run Dialyzer in CI on the primary Elixir 1.17 matrix cell with PLT caching;
  document `mix dialyzer` in the local quality gate
  ([#84](https://github.com/blksheep80/ex_pipedrive/issues/84)).
- Optional sibling package `ex_pipedrive_phoenix` (`packages/ex_pipedrive_phoenix`)
  for marketplace OAuth install helpers (independent of Überauth)
  ([#21](https://github.com/blksheep80/ex_pipedrive/issues/21)).
- Optional sibling package `ex_pipedrive_oban` (`packages/ex_pipedrive_oban`)
  with cursor-aware Oban sync workers and rate-limit snooze
  ([#20](https://github.com/blksheep80/ex_pipedrive/issues/20)).
- Optional sibling package `ex_pipedrive_web` (`packages/ex_pipedrive_web`)
  with inbound webhook Plug helpers; Event structs stay in core
  ([#82](https://github.com/blksheep80/ex_pipedrive/issues/82)).
- Expand `ExPipedrive.Webhook.Event` beyond deal/person: typed decode for
  organization, activity, lead, note, product, pipeline, stage, user,
  activityType, deal_product, deal_installment, project, task, and board;
  v1 `merged` plus v2 `create`/`change`/`delete`; real v2 payloads synthesize
  an event name from `meta.action`/`meta.entity`; unknown resources stay maps
  ([#81](https://github.com/blksheep80/ex_pipedrive/issues/81)).

### Fixed

- `ExPipedrive.Users.find_users_by_name/3` matched atom-key response bodies
  (`%{success: true, data: data}`) and silently returned no matches against
  Jason-decoded (string-key) JSON. Now matches `%{"data" => data}` like every
  other resource module ([#67](https://github.com/blksheep80/ex_pipedrive/issues/67)).
- Preserve API-provided lead value currencies and leave bare numeric values
  currency-less.

### Changed

- **Inbound webhook Plug** — `ExPipedrive.Incoming.Handler` moved to sibling
  package `ex_pipedrive_web` as `ExPipedriveWeb.Incoming.Handler` (old module
  names remain compatibility aliases there). Core no longer depends on Plug
  ([#82](https://github.com/blksheep80/ex_pipedrive/issues/82)).
- **Facade / twin cleanup** — Document blessed path (`ExPipedrive.Deals.get/2`,
  `list_page/2`, `stream/2`, …). Soft-deprecate legacy v1 twin names on resource
  modules and the root facade; nothing removed yet
  ([#79](https://github.com/blksheep80/ex_pipedrive/issues/79)).
- **Resource adoption** — `Deals`, `Persons`, `Organizations`, `Activities`,
  and `Pipelines` implement `ExPipedrive.Resource` for v2 CRUD/list/stream
  (same pattern as Products/Stages). Public APIs unchanged; v1 legacy helpers
  retained ([#78](https://github.com/blksheep80/ex_pipedrive/issues/78)).
- **List return shapes** — `Notes.get_all_org_notes/2` now returns
  `{:ok, %PagedResult{}}` like `Notes.list/2` (was a bare note list). Prefer
  `list/2` with `:org_id`. Documented list conventions on `ExPipedrive.Page`;
  soft-documented `Pipelines.list_pipelines/1` in favor of `list_page/2` /
  `stream/2` ([#86](https://github.com/blksheep80/ex_pipedrive/issues/86)).
- Refresh [AUDIT.md](AUDIT.md) as a current Pipedrive OpenAPI gap map
  (implemented vs missing tags); catch-all checklist split into focused
  issues ([#83](https://github.com/blksheep80/ex_pipedrive/issues/83),
  [#88](https://github.com/blksheep80/ex_pipedrive/issues/88)).

### Added

- `ExPipedrive.Projects` and `ExPipedrive.ProjectBoards` (API v2): CRUD plus
  cursor list/stream for projects (including archived list), and full board
  lifecycle on `/api/v2/boards`; typed `ExPipedrive.Project` and
  `ExPipedrive.ProjectBoard`. Phases, templates, fields, search, and archive
  actions deferred
  ([#105](https://github.com/blksheep80/ex_pipedrive/issues/105)).
- `ExPipedrive.Tasks` (API v2, beta): `list_page/2`/`stream/2`, `get/2`,
  `create/2`, `update/3`, and `delete/2` against `/api/v2/tasks`; typed
  `ExPipedrive.Task`
  ([#106](https://github.com/blksheep80/ex_pipedrive/issues/106)).
- `ExPipedrive.DealInstallments` (API v2, Growth+ plans): `list_page/2`/`stream/2`
  (requires `:deal_ids`), `create/3`, `update/4`, and `delete/3` against
  `/api/v2/deals/installments` and `/api/v2/deals/:id/installments`; typed
  `ExPipedrive.DealInstallment`
  ([#103](https://github.com/blksheep80/ex_pipedrive/issues/103)).
- `ExPipedrive.LeadFields` and `ExPipedrive.LeadSources` (API v1):
  `list/2`/`stream/2` over `/api/v1/leadFields` (offset pagination,
  reusing `ExPipedrive.Field`) and `list/1` over `/api/v1/leadSources`
  (fixed source names via `ExPipedrive.LeadSource`)
  ([#104](https://github.com/blksheep80/ex_pipedrive/issues/104)).
- `ExPipedrive.NoteFields` (API v1): `list/1` (plus `list_note_fields/1`
  alias) over `/api/v1/noteFields`; reuses `ExPipedrive.Field`
  ([#107](https://github.com/blksheep80/ex_pipedrive/issues/107)).
- `ExPipedrive.DealProducts` (API v2): `list_page/3`/`stream/3`, client-side
  `get/3`, `create/3`, `update/4` (PATCH), `delete/3`, and `delete_many/3`
  against `/api/v2/deals/:id/products`; typed `ExPipedrive.DealProduct`
  ([#102](https://github.com/blksheep80/ex_pipedrive/issues/102)).
- Expand `ExPipedrive.ActivityTypes` (API v1): `list/1` (plus
  `list_activity_types/1` alias), client-side `get/2`, `create/2`,
  `update/3`, `delete/2` against `/api/v1/activityTypes`; `ActivityType`
  gains `order_nr`/`icon_key`/`color`
  ([#87](https://github.com/blksheep80/ex_pipedrive/issues/87)).
- Admin / meta APIs (v1 read-first)
  ([#77](https://github.com/blksheep80/ex_pipedrive/issues/77)):
  `ExPipedrive.Currencies` (`list`/`get`/`get_by_code` over
  `/api/v1/currencies`), `ExPipedrive.Recents` (`list` over
  `/api/v1/recents`), `ExPipedrive.Roles` (list/get/assignments/pipelines/
  settings), `ExPipedrive.PermissionSets` (list/get/assignments), and
  `ExPipedrive.Teams` against `/api/v1/legacyTeams` (list/get/users/
  list_for_user). Role/team writes deferred to `Raw`.
- `ExPipedrive.Mailbox` (API v1): `list_threads/2`, `get_thread/2`,
  `list_thread_messages/2`, `get_message/3`, `update_thread/3`,
  `delete_thread/2` against `/api/v1/mailbox/{mailThreads,mailMessages}`;
  typed `ExPipedrive.MailThread`, `MailMessage`, and `MailMessageParty`
  structs (`mail:read`/`mail:full` OAuth scopes)
  ([#74](https://github.com/blksheep80/ex_pipedrive/issues/74)).
- `ExPipedrive.Goals` (API v1): `list/2` (`GET /api/v1/goals/find` with
  dot-notation filter options), `create/2`, `update/3`, `delete/2`, and
  `get_result/4` (a goal's progress for a period) against `/api/v1/goals`;
  typed `ExPipedrive.Goal` struct with string ids and plain-map
  `type`/`assignee`/`expected_outcome`/`duration` (Pipedrive has no
  single-goal `get` endpoint) ([#75](https://github.com/blksheep80/ex_pipedrive/issues/75)).
- `ExPipedrive.ActivityFields` and `ExPipedrive.ProductFields` (API v2):
  `list_page/2`/`stream/2` over `/api/v2/{activity,product}Fields`, matching
  the existing Deal/Person/Organization field modules; `ExPipedrive.Fields`
  resolves custom-field hashes/labels for both
  ([#72](https://github.com/blksheep80/ex_pipedrive/issues/72)).
- Followers, deal participants, and organization relationships
  ([#73](https://github.com/blksheep80/ex_pipedrive/issues/73)):
  `ExPipedrive.Followers` (API v2) manages followers on deals, persons, and
  organizations via the shared `GET`/`POST`/`DELETE
  /api/v2/{deals,persons,organizations}/:id/followers` shape, with cursor
  `list_page/4`/`stream/4` and per-entity convenience wrappers;
  `ExPipedrive.DealParticipants` is an API v1 shim over
  `/api/v1/deals/:id/participants` (`ExPipedrive.DealParticipant` is distinct
  from the existing `ActivityParticipant`, which decodes activity payloads);
  `ExPipedrive.OrganizationRelationships` is an API v1 client over
  `/api/v1/organizationRelationships` (parent/related org hierarchies).
- `ExPipedrive.ProductVariations` (API v2): `list_page/3`, `stream/3`,
  `get/3` (client-side, since Pipedrive has no single-variation endpoint),
  `create/3`, `update/4`, `delete/3` against the nested
  `/api/v2/products/:id/variations` API; typed `ExPipedrive.ProductVariation`
  struct ([#71](https://github.com/blksheep80/ex_pipedrive/issues/71)).
- `ExPipedrive.CallLogs` (API v1): `list/2`, `get/2`, `create/2`,
  `add_recording/4` (multipart audio upload), `delete/2` against
  `/api/v1/callLogs`; typed `ExPipedrive.CallLog` struct with string ids
  (Pipedrive does not expose a call log update endpoint)
  ([#76](https://github.com/blksheep80/ex_pipedrive/issues/76)).
- `ExPipedrive.Files` (API v1): list/get/upload/download/update/delete plus
  Google Drive `create_remote/2` and `remote_link/2`; multipart uploads via
  `Tesla.Multipart` with deal/person/org/activity/product/lead/project link
  fields ([#68](https://github.com/blksheep80/ex_pipedrive/issues/68)).
- Labels API ([#70](https://github.com/blksheep80/ex_pipedrive/issues/70)):
  `ExPipedrive.DealLabels`, `PersonLabels`, `OrganizationLabels` manage label
  definitions via the API v2 `label_ids` field-options bulk endpoints
  (`POST`/`PATCH`/`DELETE /api/v2/{deal,person,organization}Fields/label_ids/options`);
  `ExPipedrive.LeadLabels` is an API v1 shim over the dedicated
  `/leadLabels` endpoint; `ExPipedrive.Labels` facade delegates across all
  four. Typed `ExPipedrive.Label` struct. Assigning/clearing labels on an
  entity remains a normal `label_ids` write via that entity's own
  `update/3` — there is no separate assign/clear endpoint.
- `ExPipedrive.Filters` (API v1): `list/2`, `get/2`, `create/2`, `update/3`,
  `delete/2` against `/api/v1/filters`; `conditions` accepted as a plain map
  ([#69](https://github.com/blksheep80/ex_pipedrive/issues/69)).
- `ExPipedrive.Users` (API v1): `me/1`, `get/2`, `list/2` (offset pagination),
  plus fake-server fixtures and tests for `me`/`get`/`list`/`find_users_by_name`
  ([#67](https://github.com/blksheep80/ex_pipedrive/issues/67)).

## [0.1.0] - 2026-07-31

First Hex release of **ExPipedrive**, a v2-first fork of
[LineDrive](https://github.com/tmecklem/line_drive).

### Added

#### Client foundation

- Pipedrive API **v2** client foundation (`Client`, `Request`, default `/api/v2`;
  explicit `api_version: :v1` where needed)
- Header API token auth (`x-api-token`); legacy query auth via `auth: :query`
- Structured `ExPipedrive.Error` / `Response` mapping
- `Page` / `Cursor.stream` for cursor pagination (limit clamped to 500)
- OAuth `Token` bundles, `ensure_fresh`, pluggable `TokenStore` (no Ecto in core)
- Rate-limit aware retry middleware + request telemetry
  (`ExPipedrive.Middleware.Retry`, `ExPipedrive.Middleware.Telemetry`,
  `ExPipedrive.RateLimit`); Client opts `:retry`, `:telemetry`, `:middleware`
- `ExPipedrive.Resource` behaviour + CRUD/list/stream helpers; `Products` and
  `Stages` adopt the pattern
- `ExPipedrive.Raw.request/4` escape hatch for unsupported endpoints

#### Resources (API v2 unless noted)

- Deals and Persons: list/stream (cursor), get, create, update; deal delete
- Organizations, Activities, Pipelines, Stages, Products: list/stream, get,
  create, update, delete (product variations deferred)
- Search: `ExPipedrive.Search` over `/api/v2/itemSearch` with cursor pages/stream
  and typed `SearchResult`
- Deal, Person, and Organization Fields list/page/stream plus
  `ExPipedrive.Fields` for resolving custom-field hashes and labels
- Leads / Notes: explicit **API v1** shims with map-based create helpers and
  `get/2`, `create/2`, `list/2` aliases
- Webhooks: `ExPipedrive.Webhooks` subscription list/create/delete (**API v1**
  management); `Webhook.Event` / `Webhook.Handler` inbound surface (optional Plug;
  Basic auth; package extract deferred)

#### Docs & tooling

- Fake Pipedrive server fixtures for v2 resources used in tests
- MVP README flows: stream open deals; create person then deal
- CI matrix, ExDoc, Hex publish-on-release workflow

### Changed

- Package / OTP app / modules rebranded from LineDrive → `ex_pipedrive` /
  `ExPipedrive`
- Core deps slimmed (Timex removed; Plug optional for webhooks only)
- Silent OTP Application/Registry coupling removed

### Migrating from LineDrive

1. Depend on `{:ex_pipedrive, "~> 0.1.0"}` instead of `:line_drive`.
2. Rename modules `LineDrive.*` → `ExPipedrive.*`.
3. Prefer `ExPipedrive.client/2` (header token) and v2 helpers
   (`Deals.stream/2`, `Deals.create/2`, `Persons.create/2`, …) over legacy v1
   list APIs.
4. OAuth: persist `ExPipedrive.Oauth.Token` via your `TokenStore` implementation;
   build clients with `Client.from_token/2` or `from_token_store/4`.
5. Use `ExPipedrive.Raw.request/4` for endpoints not yet wrapped.

[unreleased]: https://github.com/blksheep80/ex_pipedrive/compare/v0.2.0...HEAD
[0.2.0]: https://github.com/blksheep80/ex_pipedrive/releases/tag/v0.2.0
[0.1.0]: https://github.com/blksheep80/ex_pipedrive/releases/tag/v0.1.0
