# Changelog

All notable changes to the Tallyfy SDK will be documented in this file.

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


## [Unreleased]

### Added
-

### Changed
-

### Fixed
-

## [1.3.0] - 2026-03-22

### Added
- `get_organization_runs` — added `archived` parameter to filter archived processes (`'only'` = archived only, `'true'` = include archived), replacing the previous `status='archived'` approach

### Changed
- `get_organization_runs` — improved docstrings for `owners` (numeric user IDs, matches run owner OR task assignees), `folder` (numeric folder IDs, comma-separated), and `status` (removed `'archived'` from valid values since it's now a separate parameter)

### Removed
- **`FormFieldSuggestions`** module (`tallyfy/form_fields_management/suggestions.py`) — removed AI-powered form field suggestion methods (`suggest_form_fields_for_step`, `suggest_field_improvements`) that operated on local heuristics rather than API endpoints
- **`TemplateHealthAssessment`** module (`tallyfy/template_management/health_assessment.py`) — removed `assess_template_health` method (local analysis, not an API endpoint)
- **Template analysis methods** (`tallyfy/template_management/analysis.py`) — removed `suggest_step_deadline` and related complexity analysis helpers; retained `get_step_dependencies` and `get_step_visibility_conditions`
- **Automation analysis methods** (`tallyfy/template_management/automation.py`) — removed `analyze_template_automations`, `consolidate_automation_rules`, `suggest_automation_consolidation` and their helpers (local heuristics, not API endpoints)
- **`suggest_kickoff_fields`** — removed from template manager and `TallyfySDK`
- Corresponding convenience methods removed from `TallyfySDK` (`core.py`): `suggest_step_deadline`, `analyze_template_automations`, `consolidate_automation_rules`, `suggest_automation_consolidation`, `suggest_kickoff_fields`, `suggest_form_fields_for_step`, `assess_template_health`

### Fixed
- `archive_process` docstring — corrected retrieval hint from `get_organization_runs(status='archived')` to `get_organization_runs(archived='only')`

## [1.2.2] - 2026-03-21

### Added
-

### Changed
-

### Fixed
-

## [1.2.1] - 2026-03-19

### Added
- `get_guest_tasks` — added `page` parameter for pagination support, matching `get_user_tasks` behavior
- `get_process` — added `with_` parameter for relationship includes (e.g. `tags`, `tasks`, `checklist`, `folders`, etc.)
- `tag_process` — attach a tag to a process run (POST `/checklists/tags` with `subject_type: "Run"`)
- `untag_process` — remove a tag from a process run; auto-resolves the association ID by fetching the run with `?with=tags`
- `Run` dataclass — added `tags` field (`Optional[List[Dict[str, Any]]]`) populated when fetching with `?with=tags`
- `SearchResult` dataclass — added `run_id` field for task search results
- `add_assignees_to_step` — added `guests` parameter to assign guest emails to a step
- Convenience methods `tag_process` and `untag_process` on `TallyfySDK`

### Changed
- `add_assignees_to_step` — now merges new assignees/guests with existing ones instead of overwriting with the full step payload; sends minimal payload (`title`, `assignees`, `guests`) to avoid API rejection
- `move_form_field` — now verifies the field landed on the target step after move (checks response then falls back to GET verification)
- Dropdown option suggestions in `FormFieldSuggestions` — changed format from `{value, label}` to `{id, text}` to match API expectations

### Fixed
- `untag_template` — handle tags include wrapped in `{"data": [...]}` (API may nest the tags array inside a data key)

## [1.2.0] - 2026-03-16

### Added
-

### Changed
-

### Fixed
-

## [1.2.0] - 2026-03-16

### Added

#### Template Management
- `create_template` — create new templates (POST `/checklists`)
- `delete_template` — soft-delete templates (DELETE `/checklists/{id}`)
- `delete_step` — remove a step from a template (DELETE `/checklists/{id}/steps/{step_id}`)
- `clone_step` — duplicate a step within a template (POST `/steps/{step_id}/clone`)
- `reorder_step` — change step position (PUT `/steps/{step_id}/reorder`)
- `get_kickoff_form_fields` — retrieve kick-off form fields (GET `/checklists/{id}/form-fields`)

#### Task Management
- `get_task` — get a single task within a process (GET `/runs/{run_id}/tasks/{task_id}`)
- `get_standalone_task` — get a one-off task (GET `/tasks/{task_id}`)
- `update_standalone_task` — update a one-off task (PUT `/tasks/{task_id}`)
- `delete_standalone_task` — delete a one-off task (DELETE `/tasks/{task_id}`)
- `reactivate_process` — reactivate an archived process (PUT `/runs/{run_id}/activate`)
- `complete_kickoff_form` — complete a process kick-off form (POST `/runs/{run_id}/complete-prerun`)
- `reopen_kickoff_form` — reopen a completed kick-off form (DELETE `/runs/{run_id}/complete-prerun`)

#### Thread Management
- `report_task_issue` — report an issue on a task (POST `/tasks/{task_id}/problem`)
- `resolve_task_issues` — resolve all issues on a task (POST `/tasks/{task_id}/resolved-threads`)

#### Organization Management
- `get_organization` — get organization details with optional includes like `subscription`, `billing_info` (GET `/organizations/{org}`)

#### Folder Management
- `add_object_to_folder` — add an object (run, template) to a folder
- `remove_object_from_folder` — remove an object from a folder (DELETE `/folders-objects/{id}`)

#### Tag Management
- `tag_template` — tag a template (POST `/checklists/tags`)
- `untag_template` — remove a tag from a template (DELETE `/checklists/tags/{association_id}`)

#### User Management
- `create_guest` — create a new guest (POST `/guests`)
- `get_guest` — get guest by email (GET `/guests/{email}`)
- `update_guest` — update guest details (PUT `/guests/{email}`)
- `disable_guest` — disable a guest (DELETE `/guests/{email}/disable`)
- `enable_guest` — re-enable a guest (PUT `/guests/{email}/enable`)
- `change_user_role` — change a user's role (PUT `/users/{user_id}/role`)
- `disable_user` — disable a user (DELETE `/users/{user_id}/disable`)
- `enable_user` — re-enable a user (PUT `/users/{user_id}/enable`)
- `approve_user` — approve a pending user (PUT `/users/{user_id}/approve`)

#### Form Fields Management
- `reorder_form_fields` — reorder form fields on a step (one PUT per field to `/steps/{step_id}/captures`)

#### New Modules
- `tallyfy/user_management/guest_operations.py` — guest CRUD operations
- `tallyfy/user_management/admin_operations.py` — admin user management operations
- `tallyfy/folder_management/operations.py` — folder object operations
- `tallyfy/tag_management/operations.py` — template tagging operations

#### Testing
- 98 unit tests across 10 test files using `pytest` + `responses` library
- `tests/conftest.py` — shared fixtures and helpers
- Full endpoint verification for every SDK method (HTTP method, URL path, request body, query params)

### Changed
- `update_automation_rule` on `TallyfySDK` now accepts `update_data` dict or `**kwargs`
- Added `responses>=0.20.0` to dev dependencies in `pyproject.toml`

### Fixed
- **204 No Content handling** — `_make_request` now returns `{'success': True}` for 204 responses instead of crashing on `response.json()` with empty body
- **Search query parameter** — changed from `search` to `q` in `search_for_tasks`, `search_for_processes`, and `search_templates_by_name`
- **`delete_form_field` return logic** — simplified to always return `True` after successful DELETE (was returning empty string)
- **`_build_query_params` `with_` key leak** — `with_` is now automatically renamed to `with`; removed redundant manual fixup in `get_organization_runs`
- **`get_template` incomplete includes** — now fetches `steps,automated_actions,prerun,tags` (was only `steps`)
- **`update_template_metadata` missing fields** — added `type`, `starred`, `default_process_name_format`, `can_add_oot`, `owner_id`, `users`, `groups`, `prerun` to accepted fields
- **`add_form_field_to_step` and `update_form_field` missing fields** — added `columns`, `collect_time`, `use_wysiwyg_editor`, `field_validation`, `prefix`, `suffix`, `settings`, `list`
- **`add_step_to_template` leaked `checklist_id`** — removed `checklist_id` from request body (API rejects it)
- **`tag_template` invalid `tag_type`** — changed `"tag_type": "Tag"` to `"tag_type": "private"`; the API validates `tag_type` with `in:private,public` and `"Tag"` caused a 422 error
- **`add_object_to_folder` checklist branch** — was sending only `{"default_folder": folder_id}` which fails because `UpdateChecklistRequest` requires `title` and uses `folder_id` (not `default_folder`) for template folder membership; fixed to GET the template first then PUT `{"title": title, "folder_id": folder_id}`
- **`reorder_form_fields` bulk send** — was sending the entire field list as a single PUT body; the API processes one item at a time so fixed to loop and issue one PUT per item with `{"capture_id": ..., "position": ...}`
- **`get_step_visibility_conditions` wrong field names** — was checking `action.get('type')` for `'show_step'`/`'hide_step'`; the API serializes these as `action_type='visibility'` and `action_verb='show'`/`'hide'` with the target step in `target_step_id`; fixed to handle both the new format and legacy field names as a fallback

## [1.1.4] - 2026-03-14

### Added
-

### Changed
-

### Fixed
-

## [1.1.3] - 2026-03-14

### Fixed
- `move_form_field`: fixed endpoint from `/move` to `/move-out` and HTTP method from POST to PUT; renamed parameter `to_step_id` to `target_step_id` to match API
- `get_dropdown_options`: fixed 405 error by fetching the parent step instead of individual capture (GET on single capture is not supported); extracts field from step's captures list
- `update_dropdown_options`: fixed option format to use `{id: int, text: str}` instead of `{value, label, position}` to match API expectations
- `create_automation_rule`, `update_automation_rule`, `delete_automation_rule`: fixed endpoint path from `automated_actions` to `automated-actions`

## [1.1.2] - 2026-02-27

### Added
-

### Changed
-

### Fixed
- `get_all_templates`: fixed query parameters (`per_page`, `page`) being URL-encoded into the path instead of passed as query params, causing 404 errors

## [1.1.1] - 2026-02-22

### Fixed
- `duplicate_template`: fixed wrong endpoint (`/duplicate` → `/clone`), wrong content-type (JSON → `application/x-www-form-urlencoded`), and wrong body fields (`copy_permissions` → `tenant`)
- `duplicate_template` in `core.py` wrapper: fixed incorrect argument order that caused `TypeError`
- `_make_request`: added `form_data` parameter for `application/x-www-form-urlencoded` requests

### Changed
- `duplicate_template` signature: `new_name` and `tenant` are now both required positional arguments; `copy_permissions` removed

## [1.1.0] - 2026-02-21

### Added
- **GroupManager** (`sdk.groups`) — full CRUD for organization groups: `get_groups`, `get_group`, `create_group`, `update_group`, `delete_group`
- **TagManager** (`sdk.tags`) — full CRUD for organization tags: `get_tags`, `get_tag`, `create_tag`, `update_tag`, `delete_tag`
- **FolderManager** (`sdk.folders`) — full CRUD for organization folders: `get_folders`, `get_folder`, `create_folder`, `update_folder`, `delete_folder`
- **ThreadManager** (`sdk.threads`) — task comment CRUD: `add_task_comment`, `get_task_comments`, `update_task_comment`, `delete_task_comment`
- **Process lifecycle methods**: `get_process`, `update_process` (name/summary/starred), `archive_process`
- **Task lifecycle methods**: `complete_task`, `reopen_task`, `update_task`
- **`launch_process`** — create a new process run from a template with assignees, name, summary, and due dates
- **`tallyfy/validation.py`** — centralized input validation module:
  - `validate_id()` — strict allowlist (`[a-zA-Z0-9_-]`), 255-char max; blocks path traversal and URL injection in all ID parameters
  - `validate_positive_int()` — ensures positive integer; rejects booleans, floats, zero, negatives
  - `validate_string()` — non-empty check with configurable max length (default 10,000)
- `Group`, `Tag`, `Folder` data models added to `tallyfy/models.py`
- `validate_id`, `validate_positive_int`, `validate_string` exported from the top-level `tallyfy` package

### Changed
- All manager `_validate_*` methods across `task_management`, `user_management`, `template_management`, `form_fields_management`, `group_management`, `tag_management`, `folder_management`, and `thread_management` now delegate to the shared validators in `validation.py`
- `BaseSDK._build_url` percent-encodes every path segment via `urllib.parse.quote` (defense-in-depth against path traversal)
- `Tag` model: `color` and `type` fields are now `Optional`; added `auto_generated` field
- `Folder` model: added `parent_id`, `total`, `position`, `folder_type` fields

### Fixed
- `update_group` now fetches current group state before PUT (API requires all fields; partial update was causing 422)
- `create_group` validates that `description` is non-empty (API rejects blank strings with 422)
- Step update requests now always include `title` to satisfy API requirements
- Step creation payload now includes `checklist_id` when provided


## [1.0.18] - 2026-01-29

### Changed
- Improved response handling for list-based endpoints across all management modules
- Added `_count` support and unified `from_list` class methods to list model classes
- Refactored user and guest retrieval to handle varied API response formats


## [1.0.17] - 2026-01-25

### Added
- `UsersList` and `GuestsList` response models with `from_list` class methods and `count` property

### Changed
- Refactored user and guest retrieval to use structured list models instead of raw dicts

### Infrastructure
- Use `PAT_TOKEN` in release workflow to trigger PyPI publish
- Added `workflow_dispatch` trigger to `build-whl.yml`


## [1.0.16] - 2026-01-21

### Added
- Pagination support for user, guest, and task queries
- Release `Makefile` for streamlined publishing

### Fixed
- Repository URLs corrected in `setup.py`

### Infrastructure
- Updated GitHub Actions workflow for release automation


## [1.0.15] - 2026-01-21

### Added
- Pagination support groundwork for list endpoints


## [1.0.14] - 2025-11-14

### Changed
- **BREAKING**: Refactored user management from monolithic to modular architecture
  - `user_management.py` → `user_management/` package with specialized modules
  - New `UserManager` class replaces `UserManagement` (backward compatible alias maintained)
  - Improved separation of concerns with dedicated retrieval and invitation modules

### Added
- **Enhanced User Management Features**:
  - `get_user_by_email()` - Find users by email address with exact matching
  - `get_guest_by_email()` - Find guests by email address with exact matching
  - `search_members_by_name()` - Fuzzy search for users and guests by name
  - `get_all_organization_members()` - Convenience method to get users and guests in one call
  - `invite_multiple_users()` - Batch invitation support with default role/message handling
  - `resend_invitation()` - Resend invitations with custom messaging
  - `get_invitation_template_message()` - Generate customized invitation messages
  - `validate_invitation_data()` - Validate invitation data before sending

- **Modular Architecture Improvements**:
  - `user_management/base.py` - Common validation and error handling
  - `user_management/retrieval.py` - User and guest retrieval operations
  - `user_management/invitation.py` - User invitation operations with enhanced features
  - Direct access to specialized modules via `sdk.users.retrieval` and `sdk.users.invitation`

### Improved
- **Enhanced Validation**: Comprehensive email validation with regex patterns
- **Better Error Handling**: Context-aware error messages with operation details
- **Query Parameter Handling**: Flexible parameter building with proper boolean conversion
- **Code Organization**: Clear separation between retrieval and invitation concerns
- **Type Safety**: Enhanced type hints and validation across all user operations

### Fixed
- **Python Keyword Conflicts**: Resolved issues with `with` keyword in query parameters
- **Import Compatibility**: Maintained full backward compatibility while enabling new functionality

### Deprecated
- `UserManagement` class name (use `UserManager` instead, though alias is maintained)

## [1.0.0] - 2025-06-25

### Added
- Initial release of Tallyfy SDK
- Complete user management functionality
- Task management with natural language processing
- Template management with automation support
- Form field management with AI-powered suggestions
- Comprehensive data models with type safety
- Error handling with automatic retry logic
- Session management and connection pooling
- Full API coverage for Tallyfy platform

### Features
- **User Management**: Organization members, guests, and invitations
- **Task Management**: Personal tasks, process tasks, and natural language creation
- **Template Management**: Template CRUD, automation rules, and health assessment
- **Form Fields**: Dynamic form field management with AI suggestions
- **Search**: Universal search across processes, templates, and tasks
- **Natural Language Processing**: Date extraction and task parsing
- **Error Handling**: Comprehensive error handling with detailed response data
- **Type Safety**: Full dataclass models with type hints

### Dependencies
- requests>=2.25.0
- typing-extensions>=4.0.0 (Python < 3.8)

### Development
- Python 3.7+ support
- Comprehensive test suite
- Type checking with mypy
- Code formatting with black
- Linting with flake8
