ideasbugs 0.7.7 → 0.7.8
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 +4 -4
- data/AGENTS.md +174 -0
- data/CHANGELOG.md +14 -0
- data/README.md +5 -0
- data/lib/ideasbugs/version.rb +1 -1
- metadata +2 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 9875f27cec0e4396ed1c2b269cea94335852c1a4776850fd0944bf9e52f5d154
|
|
4
|
+
data.tar.gz: c2301f7df468b8659b99cafb8e4f52e118b0f23f70c983359a1d236368e75121
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: dd3615cbda1b4455a49a345ec5c0620a810547220a44ead6434c1a912f308fad963b4f022b5e9ea3c78140c72d33365420e43c893cb4330975d929ebd9ded36b
|
|
7
|
+
data.tar.gz: b29d7052738b06accc692290f3973c88ef7537fa26cdd5d728da46036267bc581310012600b18d1f20fe9113abd162f733f4b1045867f793f0ae9452ed0276ce
|
data/AGENTS.md
ADDED
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
# AGENTS.md
|
|
2
|
+
|
|
3
|
+
Instructions for coding agents. Two audiences:
|
|
4
|
+
|
|
5
|
+
- **[Installing ideasbugs into a Rails app](#installing-into-a-rails-app)** — you are working in a host app and were asked to add product feedback, bug reports, or a feature-request board.
|
|
6
|
+
- **[Working on the gem itself](#working-on-the-gem-itself)** — you are working in this repository.
|
|
7
|
+
|
|
8
|
+
Requirements: Ruby >= 3.2, Rails >= 7.1. Active Storage only for screenshots. The widget needs the CSRF token from `csrf_meta_tags`, which a standard Rails layout already has.
|
|
9
|
+
|
|
10
|
+
If you are in a host app and this file is not in front of you, it ships inside the gem: `cat "$(bundle show ideasbugs)/AGENTS.md"`.
|
|
11
|
+
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
## Installing into a Rails app
|
|
15
|
+
|
|
16
|
+
### 1. Install
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
bundle add ideasbugs
|
|
20
|
+
bin/rails generate ideasbugs:install
|
|
21
|
+
bin/rails db:migrate
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
The generator writes `config/initializers/ideasbugs.rb`, one migration (`ideasbugs_feedbacks`), and `mount_ideasbugs at: "/feedback"` into `config/routes.rb`. Note the mount path is **`/feedback`**, not `/ideasbugs`. Read the initializer it wrote — every option is documented there in comments, and it is the source of truth over any summary of it, including this file.
|
|
25
|
+
|
|
26
|
+
Every `config.…` line below belongs inside the `Ideasbugs.configure do |config|` block in that initializer. Uncomment and edit in place rather than appending a second `configure` block.
|
|
27
|
+
|
|
28
|
+
### 2. Wire the three things the generator cannot
|
|
29
|
+
|
|
30
|
+
**a. The widget tag.** Nothing appears until this is on the page:
|
|
31
|
+
|
|
32
|
+
```erb
|
|
33
|
+
<%# app/views/layouts/application.html.erb, before </body> %>
|
|
34
|
+
<%= ideasbugs_tag %>
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
The helper is injected into ActionView by the engine — no include, no import, no asset pipeline entry. A floating **Feedback** button appears bottom-right.
|
|
38
|
+
|
|
39
|
+
**b. `authorize_admin` — do this before deploying.** The dashboard at `/feedback` defaults to **development only**. It fails closed, so shipping without this is not an open dashboard — it is a 403 reading "Forbidden. Set Ideasbugs.config.authorize_admin to grant access."
|
|
40
|
+
|
|
41
|
+
Note the asymmetry, and that it is deliberate: **`enabled` defaults to everyone** (real users in production are the point of feedback collection) while **`authorize_admin` defaults to nobody outside development**.
|
|
42
|
+
|
|
43
|
+
```ruby
|
|
44
|
+
config.authorize_admin = ->(request) { request.env["warden"]&.user&.admin? }
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
**c. Attribution**, if the app has users. Optional, but without it every submission is anonymous.
|
|
48
|
+
|
|
49
|
+
```ruby
|
|
50
|
+
config.current_user = ->(request) { request.env["warden"]&.user }
|
|
51
|
+
config.author_label = ->(user) { user.email } # the short label stored + shown
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
> **`enabled`, `authorize_admin`, `current_user` and `tenant` receive the raw `request`, not a controller.** Writing `->(request) { current_user }` is the most common mistake here — that method does not exist in this scope. Resolve the user *from the request*: Warden env, a signed cookie, `Current.user` if middleware already set it. `author_label` is the exception: it receives whatever `current_user` returned.
|
|
55
|
+
|
|
56
|
+
Rails 8 built-in auth:
|
|
57
|
+
|
|
58
|
+
```ruby
|
|
59
|
+
config.current_user = lambda do |request|
|
|
60
|
+
token = request.cookies["session_token"]
|
|
61
|
+
Session.find_signed(token)&.user if token
|
|
62
|
+
end
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
### 3. Verify
|
|
66
|
+
|
|
67
|
+
```bash
|
|
68
|
+
bin/rails routes | grep ideasbugs # engine mounted
|
|
69
|
+
bin/rails ideasbugs:seed_demo # optional sample feedback, idempotent
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
Then in the running app: load any page, confirm the Feedback button appears, send one, and triage it at `/feedback`.
|
|
73
|
+
|
|
74
|
+
### Shaping the widget
|
|
75
|
+
|
|
76
|
+
```ruby
|
|
77
|
+
config.kinds = %w[bug feature other] # labels resolve through I18n (ideasbugs.kinds.<kind>)
|
|
78
|
+
config.sections = ["Billing", "Dashboard"] # [] hides the select entirely
|
|
79
|
+
config.show_button = false # then open it from your own UI
|
|
80
|
+
config.button_label = "Report a problem" # nil = localized default
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
With `show_button = false`, any element carrying `data-ideasbugs-open` opens the form — put it in a menu, a footer, a help panel.
|
|
84
|
+
|
|
85
|
+
### Screenshots
|
|
86
|
+
|
|
87
|
+
`config.screenshots` is on by default but **requires Active Storage in the host app** (`rails active_storage:install`); the widget hides the upload control when it is off or Active Storage is absent, and the config exposes `screenshots_enabled?` for exactly that pair of conditions. Caps: `max_screenshots` (3), `max_screenshot_size` (5 MB), both enforced server-side. Images stream through the dashboard's own gate at `/feedback/feedbacks/:id/screenshots/:id` — **never a public blob URL**. Do not build your own blob links.
|
|
88
|
+
|
|
89
|
+
### Statuses
|
|
90
|
+
|
|
91
|
+
`open → in_review → resolved`, as plain strings in `Ideasbugs::Feedback::STATUSES` with a scope per status (`Feedback.open`, `.in_review`, `.resolved`) plus `newest_first`. Deliberately not an Active Record enum — `open` as an enum scope would collide with `Kernel#open`. Do not "modernize" it into an enum.
|
|
92
|
+
|
|
93
|
+
### Multi-tenancy
|
|
94
|
+
|
|
95
|
+
One resolver returning an **opaque key** — GlobalID, id, subdomain, slug. The gem never takes a foreign key into host models:
|
|
96
|
+
|
|
97
|
+
```ruby
|
|
98
|
+
config.tenant = ->(request) { Current.customer&.to_gid&.to_s }
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
Optional sugar on a host model (`has_feedback` is available on every Active Record class already):
|
|
102
|
+
|
|
103
|
+
```ruby
|
|
104
|
+
class Customer < ApplicationRecord
|
|
105
|
+
has_feedback # keyed by to_gid.to_s — must match config.tenant
|
|
106
|
+
end
|
|
107
|
+
customer.feedback.open
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
`bin/rails generate ideasbugs:tenant` exists **only** to add the `tenant` column to installs made before it existed. A fresh install already has it, and running that generator will fail on a duplicate column. Do not run it as part of a new install.
|
|
111
|
+
|
|
112
|
+
### Do not
|
|
113
|
+
|
|
114
|
+
- **Do not copy the widget JavaScript into `app/javascript`, or add a `<script>` tag for it.** `ideasbugs_tag` renders what is needed and the engine serves the code same-origin. There is no build step and nothing for esbuild/importmap/Tailwind to know about.
|
|
115
|
+
- **Do not build your own dashboard.** Use the mounted one; `config.admin_layout = "admin/application"` renders it inside an existing admin shell.
|
|
116
|
+
- **Do not expose screenshots by blob URL** — the gated route exists so a leaked signed URL cannot hand over a customer's screenshot.
|
|
117
|
+
- **Do not set config outside the initializer.** `rate_limit` in particular is read once when the controller class loads; assigning config per-request mutates it process-wide.
|
|
118
|
+
- **Do not convert the status strings to an enum** (see above).
|
|
119
|
+
|
|
120
|
+
### Configuration worth knowing
|
|
121
|
+
|
|
122
|
+
Everything is optional; a fresh install works with zero config. Full list with comments is in the generated initializer.
|
|
123
|
+
|
|
124
|
+
| Option | Default | Note |
|
|
125
|
+
| --- | --- | --- |
|
|
126
|
+
| `authorize_admin` | development only | **Who can read the dashboard. Set before deploying.** |
|
|
127
|
+
| `enabled` | everyone | Per-request gate for the widget and submissions |
|
|
128
|
+
| `current_user` | `nil` | Receives the request |
|
|
129
|
+
| `author_label` | email, else `to_s` | Receives the user |
|
|
130
|
+
| `tenant` | `nil` | One board per tenant — see [Multi-tenancy](#multi-tenancy) |
|
|
131
|
+
| `kinds` | `bug feature other` | Labels via `ideasbugs.kinds.<kind>` |
|
|
132
|
+
| `sections` | `[]` | App areas as a select; empty hides it |
|
|
133
|
+
| `screenshots` | `true` | Needs Active Storage; inert without it |
|
|
134
|
+
| `max_screenshots`, `max_screenshot_size` | `3`, `5.megabytes` | Enforced server-side |
|
|
135
|
+
| `storage_service` | app default | A `storage.yml` key for a dedicated bucket |
|
|
136
|
+
| `show_button`, `button_label` | `true`, localized | `false` = open from `data-ideasbugs-open` |
|
|
137
|
+
| `admin_layout` | `ideasbugs/application` | Render inside your admin shell |
|
|
138
|
+
| `rate_limit` | `{ to: 10, within: 60 }` | Rails 7.2+; ignored on 7.1. `nil` disables |
|
|
139
|
+
| `mount_path` | `"/feedback"` | Keep in sync with `mount_ideasbugs at:` |
|
|
140
|
+
| `on_submit` | no-op | Runs inline after save — Slack, email, a ticket |
|
|
141
|
+
|
|
142
|
+
### Common failure modes
|
|
143
|
+
|
|
144
|
+
| Symptom | Cause |
|
|
145
|
+
| --- | --- |
|
|
146
|
+
| `/feedback` returns 403 "Set Ideasbugs.config.authorize_admin to grant access" | Exactly what it says: still at the development-only default |
|
|
147
|
+
| No Feedback button | `ideasbugs_tag` missing from the rendered layout, `config.enabled` false, or `show_button = false` with no opener of your own |
|
|
148
|
+
| Submissions rejected with an invalid-token error | The layout is missing `csrf_meta_tags` |
|
|
149
|
+
| No screenshot upload control | Active Storage not installed, or `screenshots = false` |
|
|
150
|
+
| `ideasbugs:tenant` fails on a duplicate column | It is an upgrade generator for pre-tenant installs; a fresh install already has the column |
|
|
151
|
+
| `undefined local variable current_user` in the initializer | A gate lambda treated its argument as a controller. It is a `request` |
|
|
152
|
+
|
|
153
|
+
---
|
|
154
|
+
|
|
155
|
+
## Working on the gem itself
|
|
156
|
+
|
|
157
|
+
```bash
|
|
158
|
+
bundle exec rake test # minitest, dummy app under test/dummy
|
|
159
|
+
bundle exec rake test:system # browser tests, separate task
|
|
160
|
+
bundle exec rubocop # must be clean
|
|
161
|
+
BUNDLE_GEMFILE=gemfiles/rails_7.1.gemfile bundle exec rake test # 7.1, 7.2, 8.0, 8.1 in gemfiles/
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
Layout: `app/` controller, model, dashboard views · `lib/ideasbugs/` config, widget JS, seeds, engine, `has_feedback` · `lib/generators/ideasbugs/` install and tenant · `config/locales/` · `test/` minitest with `test/dummy` as the host app, system tests excluded from the default task.
|
|
165
|
+
|
|
166
|
+
Conventions this codebase holds to — follow them rather than the first thing that works:
|
|
167
|
+
|
|
168
|
+
- **Multi-tenancy is an opaque string key, never a foreign key.** `config.tenant` returns whatever the host wants; `has_feedback` is a veneer over `Feedback.for_tenant`. No association, no `owner_type` coupling.
|
|
169
|
+
- **Active Storage is optional at runtime.** `screenshots_enabled?` checks the switch *and* whether the constant is defined, so an app without Active Storage gets a working widget rather than an exception.
|
|
170
|
+
- **Attachments stream through the engine's gate**, never a public blob URL.
|
|
171
|
+
- **The widget is plain JS served same-origin by the engine** — no build step, no framework.
|
|
172
|
+
- **The dummy app pins `config.active_job.queue_adapter = :test`.** Do not remove it or let it drift back to the `:async` default. Attaching a screenshot enqueues Active Storage's analysis job, and `:async` runs it on a background thread that checks out its own connection — writes no test transaction covers, landing in the middle of whatever runs next. That is a suite that fails order-dependently in a test which never created a row, and it is miserable to trace back.
|
|
173
|
+
- Every user-facing change bumps `lib/ideasbugs/version.rb` and adds a `CHANGELOG.md` entry that says what it costs, not only what it adds.
|
|
174
|
+
- Commit messages are prose that explains the tradeoff — read `git log` before writing one.
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,19 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.7.8
|
|
4
|
+
|
|
5
|
+
- Adds `AGENTS.md`: install and integration instructions written for coding
|
|
6
|
+
agents — the request-shaped config lambdas, the `/feedback` mount path, why
|
|
7
|
+
the status strings are not an enum, and the mistakes agents actually make. It
|
|
8
|
+
ships inside the gem, so `cat "$(bundle show ideasbugs)/AGENTS.md"` works from
|
|
9
|
+
a host app.
|
|
10
|
+
- The dummy app pins `queue_adapter = :test` for the test suite. Attaching a
|
|
11
|
+
screenshot enqueues Active Storage's analysis job, and the default `:async`
|
|
12
|
+
adapter runs it on a background thread with its own database connection —
|
|
13
|
+
writes no test transaction covers, which is how a suite starts failing
|
|
14
|
+
order-dependently in a test that never created a row. No effect on the gem
|
|
15
|
+
itself.
|
|
16
|
+
|
|
3
17
|
## 0.7.7 (2026-08-01)
|
|
4
18
|
|
|
5
19
|
- Added `Ideasbugs::Seeds.load!` and a `rake ideasbugs:seed_demo` task that
|
data/README.md
CHANGED
|
@@ -64,6 +64,11 @@ duplicating them.
|
|
|
64
64
|
Ruby >= 3.2 · Rails >= 7.1 · Active Storage only if you want screenshots ·
|
|
65
65
|
CSRF token comes from `csrf_meta_tags`, already in a standard Rails layout.
|
|
66
66
|
|
|
67
|
+
Installing with a coding agent? Point it at [AGENTS.md](AGENTS.md) — the same
|
|
68
|
+
steps in the order an agent needs them, plus the gates it tends to get wrong and
|
|
69
|
+
the things it should not do. It ships inside the gem, so
|
|
70
|
+
`cat "$(bundle show ideasbugs)/AGENTS.md"` works from any app that bundles it.
|
|
71
|
+
|
|
67
72
|
## What you get
|
|
68
73
|
|
|
69
74
|
| | |
|
data/lib/ideasbugs/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: ideasbugs
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.7.
|
|
4
|
+
version: 0.7.8
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Yaroslav Shmarov
|
|
@@ -34,6 +34,7 @@ executables: []
|
|
|
34
34
|
extensions: []
|
|
35
35
|
extra_rdoc_files: []
|
|
36
36
|
files:
|
|
37
|
+
- AGENTS.md
|
|
37
38
|
- CHANGELOG.md
|
|
38
39
|
- MIT-LICENSE
|
|
39
40
|
- README.md
|