signoff 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: daf22fb998df2e5bef0e6207a62b5a92706b25ae6d32c29b3be5ec813f5067aa
4
+ data.tar.gz: bc00d77c7d53a2aa56883d637d0edcc984e431593acbfbf360ba3f01fe431940
5
+ SHA512:
6
+ metadata.gz: c7a29fac8c99c70171b22aac59c5b60522ff3bde67b3c81a3a58d8d66943e50d9e4f595012acdf29c7d692d8c638f8b7147af1dd397895c42d1e34f3043e3933
7
+ data.tar.gz: 519e9fbfd372cddf725038124762ada8dc54a0fc280dd9c566228fa2e832e854aff5147767ab3b7173eb527417ddfd153536ccaa52e1aac63e0c329cb00fc6e3
data/CHANGELOG.md ADDED
@@ -0,0 +1,79 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project will be documented in this file.
4
+
5
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
+ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
+
8
+ ## [Unreleased]
9
+
10
+ ## [0.1.0] - 2026-06-05
11
+
12
+ Initial public release. `signoff` adds concurrency-safe approval workflows
13
+ with a complete, immutable audit trail to ActiveRecord models on Rails 7.x
14
+ and 8.x, backed by PostgreSQL — no external services required.
15
+
16
+ ### Added
17
+
18
+ - **Declarative workflow DSL.** `include Signoff` then declare states and
19
+ transitions inside a `signoff do ... end` block. DSL methods:
20
+ `state(name, initial: false)`, `states(*names)`, `initial_state(name)`,
21
+ `transition(from, to:)` (where `to:` accepts a single state or an array),
22
+ `reject_to(state)`, `allow_transition(from_state) { |user[, record]| }`,
23
+ `before_transition { |record, from, to| }`, and
24
+ `after_transition { |record, event| }`. The macro accepts a per-model state
25
+ column override via `signoff(column: :workflow_state) do ... end`.
26
+ - **Transition methods.** `submit!`, `approve!`, and `reject!`, each accepting
27
+ `user:`, `comment:`, `metadata:`, `ip_address:`, and `user_agent:` keyword
28
+ arguments (`submit!`/`approve!` also accept `to:` for branching transitions).
29
+ `submit!` and `approve!` advance the single forward transition and differ only
30
+ in the recorded action label; `reject!` moves the record to the configured
31
+ `reject_to` state. Transitions run inside a transaction and roll the in-memory
32
+ state back if anything raises.
33
+ - **From-state authorization guards.** `allow_transition` guards are keyed by the
34
+ state the record is currently in. Unauthorized attempts — including the case
35
+ where a guard exists but no user is supplied — raise
36
+ `Signoff::UnauthorizedError`. The non-raising predicates
37
+ `can_approve?(user = nil)` and `can_reject?(user = nil)` report whether a
38
+ transition is currently permitted without raising.
39
+ - **Before/after transition callbacks.** `before_transition` runs inside the
40
+ transaction before the state column is written; `after_transition` runs after
41
+ the transaction commits with the persisted event, making it the right place to
42
+ enqueue ActiveJob jobs or send ActionMailer notifications.
43
+ - **Immutable PostgreSQL JSONB audit trail.** Every transition writes a
44
+ `Signoff::Event` record (polymorphic `workflowable`, `user`, `action`,
45
+ `from_state`, `to_state`, `comment`, JSONB `metadata`, optional `ip_address`
46
+ and `user_agent`, `created_at`). Persisted events are read-only by default
47
+ (`config.immutable_events`), guaranteeing an append-only history.
48
+ - **Audit-trail helpers.** `workflow_history` (the preloadable, chronologically
49
+ ordered events relation), `last_approval`, `last_rejection`, and `approved_by`
50
+ (the user who moved the record into a successful terminal state).
51
+ - **State introspection.** `current_state` (returns a `Symbol`), the
52
+ `approved?` / `rejected?` / `pending?` predicates, and auto-generated
53
+ per-state predicates such as `draft?` and `manager_review?`.
54
+ - **Query scopes.** `.approved`, `.pending`, `.rejected`, and `.in_state(*states)`,
55
+ all reading from the state column (the source of truth), plus the
56
+ `.signoff_column` and `.signoff_states` introspection
57
+ helpers.
58
+ - **Rails generators.** `rails g signoff:install` creates the
59
+ `create_signoff_events` migration (JSONB `metadata` with supporting
60
+ indexes) and a `config/initializers/signoff.rb` initializer.
61
+ `rails g signoff:model ExpenseReport [--column=approval_state]
62
+ [--initial=draft]` adds an indexed state column to the target model's table.
63
+ - **Configuration** via `Signoff.configure { |config| ... }`:
64
+ `user_class` (`"User"`), `track_ip_addresses` (`false`), `store_user_agent`
65
+ (`false`), `default_state_column` (`:approval_state`), `event_table_name`
66
+ (`"signoff_events"`), `validate_on_transition` (`false`), `dependent`
67
+ (`:delete_all`), and `immutable_events` (`true`).
68
+ - **Request-context capture.** `Signoff::Current` (an
69
+ `ActiveSupport::CurrentAttributes` holding `user`, `ip_address`, and
70
+ `user_agent`) supplies actor and request details to transitions automatically.
71
+ Include `Signoff::Controller` in `ApplicationController` to populate it
72
+ from `current_user` and the incoming request.
73
+ - **Typed error hierarchy** under `Signoff::Error`: `DefinitionError`,
74
+ `InvalidTransitionError`, `UnauthorizedError`, `NotConfiguredError`, and
75
+ `MissingColumnError`.
76
+ - **Rails 7.x and 8.x support** on Ruby >= 3.2 with PostgreSQL.
77
+
78
+ [Unreleased]: https://github.com/JijoBose/Signoff/compare/v0.1.0...HEAD
79
+ [0.1.0]: https://github.com/JijoBose/Signoff/releases/tag/v0.1.0
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2026 Jijo Bose
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.