Repository navigation
feat(lists): delete icon to remove contacts from a list - #8
Conversation
Adds a trash icon to each contact row on the list detail page, backed by a confirmation dialog and a new DELETE /api/internal/contacts/[id] route. The route reuses hardDeleteContact so the contact and its send/event history are removed via cascade, and writes a contact.delete audit log entry. The existing GDPR delete flow is unchanged.
🚦 Pre-merge checks ·
|
| Check | Status | Explanation |
|---|---|---|
| Rate limiting not detected | 1 potential issue(s) detected (max risk 45/100): app/api/internal/contacts/[id]/route.ts:5. | |
| PII in logs | 1 potential issue(s) detected (max risk 70/100): app/api/internal/contacts/[id]/route.ts:20. | |
| Source changes without matching tests | 6 root-cause issue(s) detected (max risk 65/100): app/api/internal/contacts/[id]/route.ts:5, app/api/internal/contacts/[id]/route.ts:15, app/(dashboard)/lists/[id]/page.tsx:33, app/(dashboard)/lists/[id]/page.tsx:163, app/(dashboard)/lists/[id]/page.tsx:107. | |
| Release Notes Curator | 1 finding(s) on changed lines. |
✅ Passed checks (161)
| Check | Status | Explanation |
|---|---|---|
| Too many files changed | ✅ Passed | Changed 2 file(s), within the limit of 50. |
| Too many lines changed | ✅ Passed | Changed 159 line(s), within the limit of 1000. |
| Too many unrelated chapters | ✅ Passed | 2 chapter(s) detected, within the limit of 6. |
| Generated files hiding real changes | ✅ Passed | Generated-file volume (0 lines) does not obscure the 159 hand-written line(s). |
| Missing PR context | ✅ Passed | PR context looks sufficient. |
| Mixed concerns (refactor + behavior change) | ✅ Passed | PR is single behavior feature (new DELETE route + delete UI), no renames, moves, or cleanup refactor. |
| Migration + app logic + UI combined in one PR | ✅ Passed | No migration files present; only app logic and UI changes with zero fan-in. |
| Sensitive data in logs | ✅ Passed | No sensitive data in logs issues detected. |
| Log injection | ✅ Passed | No log injection issues detected. |
| Missing audit logging | ✅ Passed | No missing audit logging issues detected. |
| Removed observability | ✅ Passed | No removed observability issues detected. |
| Silent exception swallowing | ✅ Passed | No silent exception swallowing issues detected. |
| Unhandled promise rejection | ✅ Passed | No unhandled promise rejection issues remaining after verification. |
| Circuit breaker not detected | ✅ Passed | No circuit breaker not detected issues detected. |
| Stack trace leakage | ✅ Passed | No stack trace leakage issues detected. |
| Possible TOCTOU in critical path | ✅ Passed | No possible toctou in critical path issues detected. |
| Idempotency key not detected | ✅ Passed | No idempotency key not detected issues detected. |
| Possible non-atomic read-modify-write | ✅ Passed | No possible non-atomic read-modify-write issues detected. |
| Optimistic locking not detected | ✅ Passed | No optimistic locking not detected issues detected. |
| Rate limiting removed | ✅ Passed | No rate limiting removed issues detected. |
| Batch size limit not detected | ✅ Passed | No batch size limit not detected issues detected. |
| Pagination not detected | ✅ Passed | No pagination not detected issues detected. |
| Prompt injection risk | ✅ Passed | No LLM/AI-integration code touched by this diff. |
| LLM output used in a dangerous sink | ✅ Passed | No LLM/AI-integration code touched by this diff. |
| Sensitive data in prompt or system-prompt leakage | ✅ Passed | No LLM/AI-integration code touched by this diff. |
| Over-privileged LLM tool / excessive agency | ✅ Passed | No LLM/AI-integration code touched by this diff. |
| Missing validation on an LLM-driven decision | ✅ Passed | No LLM/AI-integration code touched by this diff. |
| Unbounded LLM usage (denial-of-wallet) | ✅ Passed | No LLM/AI-integration code touched by this diff. |
| Table exposed without row-level security | ✅ Passed | No row-level-security-related code touched by this diff. |
| Over-broad row-level security policy | ✅ Passed | No row-level-security-related code touched by this diff. |
| Code path that bypasses row-level security | ✅ Passed | No row-level-security-related code touched by this diff. |
| Privileged database credential reachable from the client | ✅ Passed | No row-level-security-related code touched by this diff. |
| Privileged query without row-level scoping | ✅ Passed | No row-level-security-related code touched by this diff. |
| Row-level security enabled with no policy | ✅ Passed | No row-level-security-related code touched by this diff. |
| Template-default gradient styling | ✅ Passed | No added frontend pages or design-slop markers in this diff. |
| Interchangeable AI marketing copy | ✅ Passed | No added frontend pages or design-slop markers in this diff. |
| Placeholder content shipped to users | ✅ Passed | No added frontend pages or design-slop markers in this diff. |
| Emoji standing in for an icon system | ✅ Passed | No added frontend pages or design-slop markers in this diff. |
| Call-to-action that goes nowhere | ✅ Passed | No added frontend pages or design-slop markers in this diff. |
| Templated page composition | ✅ Passed | No added frontend pages or design-slop markers in this diff. |
| Color outside the brand palette | ✅ Passed | No color outside the brand palette issues detected across 1 changed UI file(s). |
| Hardcoded style bypassing design tokens | ✅ Passed | No hardcoded style bypassing design tokens issues detected across 1 changed UI file(s). |
| Typography outside the brand type system | ✅ Passed | No typography outside the brand type system issues detected across 1 changed UI file(s). |
| One-off UI instead of the shared component | ✅ Passed | No one-off ui instead of the shared component issues detected across 1 changed UI file(s). |
| Copy that does not match brand voice | ✅ Passed | Not in scope for this repo's brand baseline. |
| Screen does not match the rest of the product | ✅ Passed | No screen does not match the rest of the product issues detected across 1 changed UI file(s). |
| Merge-blocking marker left in the change | ✅ Passed | No pending-work markers added by this diff. |
| Known-defect marker shipped in code | ✅ Passed | No pending-work markers added by this diff. |
| Untracked TODO without an issue reference | ✅ Passed | No pending-work markers added by this diff. |
| Test disabled or left pending | ✅ Passed | No pending-work markers added by this diff. |
| PII or internals leaked in error response | ✅ Passed | No pii or internals leaked in error response issues detected. |
| PII stored without application-level encryption | ✅ Passed | No pii stored without application-level encryption issues detected. |
| User data stored without retention controls | ✅ Passed | No user data stored without retention controls issues detected. |
| PII sent to external / cross-border destination | ✅ Passed | No pii sent to external / cross-border destination issues detected. |
| Lockfile resolution / integrity tampered | ✅ Passed | No lockfile resolution / integrity tampered issues detected. |
| Dependency runs install-time lifecycle script | ✅ Passed | No dependency runs install-time lifecycle script issues detected. |
| Possible dependency-confusion attack | ✅ Passed | No possible dependency-confusion attack issues detected. |
| Lockfile resolves a dependency the manifest does not declare | ✅ Passed | No lockfile resolves a dependency the manifest does not declare issues detected. |
| Checked-in build artefact modified without source change | ✅ Passed | No checked-in build artefact modified without source change issues detected. |
| Dockerfile build-step is insecure | ✅ Passed | No dockerfile build-step is insecure issues detected. |
| External artefact pulled in without integrity pinning | ✅ Passed | No external artefact pulled in without integrity pinning issues detected. |
| Changed export, importer not updated | ✅ Passed | No changed export with an un-updated importer detected. |
| Missing security-team review on sensitive path | ✅ Passed | No missing security-team review on sensitive path issues detected. |
| Migration missing rollback / down step | ✅ Passed | No migration missing rollback / down step issues detected. |
| Frontend importing database client directly | ✅ Passed | No frontend importing database client directly issues detected. |
| Route handler bypassing service layer | ✅ Passed | No route handler bypassing service layer issues detected. |
| Backend service importing UI module | ✅ Passed | No backend service importing ui module issues remaining after verification. |
| Cross-context internals import | ✅ Passed | No cross-context internals import issues detected. |
| Workspace package rule violation | ✅ Passed | No workspace package rule violation issues detected. |
| Inconsistent logging pattern | ✅ Passed | No inconsistent logging pattern issues detected. |
| Inconsistent error handling | ✅ Passed | No inconsistent error handling issues detected. |
| Endpoint missing input validation | ✅ Passed | No endpoint missing input validation issues remaining after verification. |
| Multi-write without transaction wrapper | ✅ Passed | No multi-write without transaction wrapper issues detected. |
| New feature shipped without feature flag | ✅ Passed | No new feature shipped without feature flag issues detected. |
| Module placed in the wrong workspace package | ✅ Passed | No module placed in the wrong workspace package issues detected. |
| Hallucinated import (package not installed) | ✅ Passed | No hallucinated import (package not installed) issues detected. |
| Nonexistent package (not found in registry) | ✅ Passed | No nonexistent package (not found in registry) issues detected. |
| Call to function that does not exist | ✅ Passed | No call to function that does not exist issues detected. |
| Generic placeholder identifier in production logic | ✅ Passed | No generic placeholder identifier in production logic issues remaining after verification. |
| Repetitive boilerplate (duplicated block) | ✅ Passed | No repetitive boilerplate (duplicated block) issues detected. |
| Overbroad try/catch swallowing all exceptions | ✅ Passed | No overbroad try/catch swallowing all exceptions issues detected. |
| TODO / FIXME on critical path | ✅ Passed | No todo / fixme on critical path issues detected. |
| Comment contradicts or fabricates code behaviour | ✅ Passed | No comment contradicts or fabricates code behaviour issues detected. |
| Abstraction defined but never used | ✅ Passed | No abstraction defined but never used issues detected. |
| Code style differs from rest of codebase | ✅ Passed | No code style differs from rest of codebase issues detected. |
| Established pattern ignored | ✅ Passed | No established pattern ignored issues detected. |
| Unhandled edge case (null / empty / zero / boundary) | ✅ Passed | No unhandled edge case (null / empty / zero / boundary) issues detected. |
| Insecure training-data / doc-example pattern | ✅ Passed | No insecure training-data / doc-example pattern issues detected. |
| Dead code (defined but never referenced) | ✅ Passed | No dead code (defined but never referenced) issues detected. |
| Deprecated API call | ✅ Passed | No deprecated api call issues detected. |
| API pattern from wrong library version | ✅ Passed | No api pattern from wrong library version issues detected. |
| API endpoint removed | ✅ Passed | No api endpoint removed issues detected. |
| HTTP method changed (GET ↔ POST etc.) | ✅ Passed | No http method changed (get ↔ post etc.) issues detected. |
| New required field added to request | ✅ Passed | No new required field added to request issues remaining after verification. |
| Field removed from response schema | ✅ Passed | No field removed from response schema issues detected. |
| Response field type changed | ✅ Passed | No response field type changed issues detected. |
| HTTP status code changed | ✅ Passed | No http status code changed issues detected. |
| Auth requirement added / removed / changed | ✅ Passed | No auth requirement added / removed / changed issues detected. |
| Error response shape changed | ✅ Passed | No error response shape changed issues detected. |
| Pagination behaviour changed | ✅ Passed | No pagination behaviour changed issues detected. |
| Outbound webhook payload schema changed | ✅ Passed | No outbound webhook payload schema changed issues detected. |
| GraphQL field removed without deprecation | ✅ Passed | No graphql field removed without deprecation issues detected. |
| GraphQL enum value removed | ✅ Passed | No graphql enum value removed issues detected. |
| Vendor API consumer | ✅ Passed | This PR does not touch call sites of an open vendor API change. |
| SQL injection | ✅ Passed | No sql injection issues detected. |
| Cross-site scripting (XSS) | ✅ Passed | No cross-site scripting (xss) issues detected. |
| Path traversal | ✅ Passed | No path traversal issues detected. |
| Command injection | ✅ Passed | No command injection issues detected. |
| Insecure deserialization | ✅ Passed | No insecure deserialization issues detected. |
| Weak cryptography | ✅ Passed | No weak cryptography issues detected. |
| Hardcoded secret | ✅ Passed | No hardcoded secret issues detected. |
| Insecure randomness for security material | ✅ Passed | No insecure randomness for security material issues detected. |
| Unsafe file upload | ✅ Passed | No unsafe file upload issues detected. |
| Missing input validation | ✅ Passed | No missing input validation issues detected. |
| Unsafe CORS configuration | ✅ Passed | No unsafe cors configuration issues detected. |
| Unsafe / open redirect | ✅ Passed | No unsafe / open redirect issues detected. |
| Missing CSRF protection | ✅ Passed | No missing csrf protection issues detected. |
| Unsafe cookie / session settings | ✅ Passed | No unsafe cookie / session settings issues detected. |
| Sensitive data exposure | ✅ Passed | No sensitive data exposure issues detected. |
| Invisible Unicode / Trojan Source characters | ✅ Passed | No invisible unicode / trojan source characters issues detected. |
| API key in source | ✅ Passed | No api key in source detected. |
| Access token in source | ✅ Passed | No access token in source detected. |
| Private key in source | ✅ Passed | No private key in source detected. |
| Database connection URL with embedded credentials | ✅ Passed | No database connection url with embedded credentials detected. |
| Cloud credential in source | ✅ Passed | No cloud credential in source detected. |
| Webhook signing secret in source | ✅ Passed | No webhook signing secret in source detected. |
| OAuth client secret in source | ✅ Passed | No oauth client secret in source detected. |
| JWT signing secret in source | ✅ Passed | No jwt signing secret in source detected. |
| Hardcoded password | ✅ Passed | No hardcoded password detected. |
| Auth middleware removed from route | ✅ Passed | No auth middleware removed from route issues detected. |
| Route protection changed (protected → public) | ✅ Passed | No route protection changed (protected → public) issues detected. |
| Permission / RBAC check removed | ✅ Passed | No permission / rbac check removed issues detected. |
| Required role weakened | ✅ Passed | No required role weakened issues detected. |
| Admin-only route exposed to lower privilege | ✅ Passed | No admin-only route exposed to lower privilege issues detected. |
| Token validation skipped in middleware chain | ✅ Passed | No token validation skipped in middleware chain issues detected. |
| JWT verification weakened or changed | ✅ Passed | No jwt verification weakened or changed issues detected. |
| Session expiration / TTL changed | ✅ Passed | No session expiration / ttl changed issues detected. |
| Password reset flow changed | ✅ Passed | No password reset flow changed issues detected. |
| OAuth callback / redirect handling changed | ✅ Passed | No oauth callback / redirect handling changed issues detected. |
| Webhook endpoint missing signature verification | ✅ Passed | No webhook endpoint missing signature verification issues detected. |
| Public route touches private/PII data | ✅ Passed | No public route touches private/pii data issues detected. |
| Frontend performance issue | ✅ Passed | No additional explanation was reported. |
| Frontend security issue | ✅ Passed | No additional explanation was reported. |
| Frontend correctness issue | ✅ Passed | No additional explanation was reported. |
| Accessibility issue | ✅ Passed | No additional explanation was reported. |
| Frontend maintainability issue | ✅ Passed | No additional explanation was reported. |
| Code correctness issue | ✅ Passed | No additional explanation was reported. |
| Runtime error risk | ✅ Passed | No runtime error risk issues remaining after verification. |
| Resource leak risk | ✅ Passed | No additional explanation was reported. |
| Data integrity risk | ✅ Passed | No additional explanation was reported. |
| Maintainability issue | ✅ Passed | No additional explanation was reported. |
| Co-change coupling | ✅ Passed | No additional explanation was reported. |
| Redundant alias / duplicate import | ✅ Passed | No additional explanation was reported. |
| Redundant type construct | ✅ Passed | No additional explanation was reported. |
| Unnecessary type assertion | ✅ Passed | No additional explanation was reported. |
| Module smell | ✅ Passed | No additional explanation was reported. |
| Dead export (no callers) | ✅ Passed | No additional explanation was reported. |
| Code duplication / DRY violation | ✅ Passed | No additional explanation was reported. |
| Intent vs. implementation | ✅ Passed | The delete icon, confirmation dialog, and backing delete API match everything the PR promised. Requirements: 8 implemented. (Intent from PR description.) |
| Complexity Guard | ✅ Passed | No additional explanation was reported. |
| Bundle Size Monitor | ✅ Passed | No additional explanation was reported. |
This comment is updated automatically whenever Autter reviews a new PR revision.
|
🤖 Release Notes CuratorImpact: minor — Adds new user-facing ability to remove contacts from a list. Changelog:
Custom agent · runs after review · configured in Autter |
| @@ -0,0 +1,34 @@ | |||
| import { NextRequest, NextResponse } from 'next/server' | |||
There was a problem hiding this comment.
🟠 [deterministic] Biome: lint/style/useImportType — Risk: 55/100
Some named imports are only used as types.
🛠 AI fix prompt (copy & paste into your coding agent)
Fix the Biome `lint/style/useImportType` issue at app/api/internal/contacts/[id]/route.ts:1: Some named imports are only used as types.
Flagged by Autter security & observability checks.
| req: NextRequest, | ||
| { params }: { params: { id: string } } | ||
| ) { | ||
| const result = await hardDeleteContact(params.id) |
There was a problem hiding this comment.
🟠 [ai] Unthrottled contact deletion can amplify database work — Risk: 52/100
This new DELETE route is session-authenticated by the global middleware, but it has no route-level rate limit and immediately calls hardDeleteContact. That helper loads every send for the contact and then every related event before cascading the deletion, so repeated requests for contacts with large histories can drive unbounded database reads and delete work from one authenticated session. The repository's explicit limiter is attached by withApiAuth for API-key routes, and public form submissions use an IP token bucket; neither covers this internal route. Add an appropriately keyed limit for this expensive operation before merge.
⚠ Downstream affected — if this fails, it cascades to the usage that depends on this file:
- Dependent files:
app/api/internal/contacts/[id]/route.ts,lib/gdpr/index.ts,middleware.ts,lib/api-auth.ts
🛠 AI fix prompt (copy & paste into your coding agent)
Protect DELETE /api/internal/contacts/[id] with a server-side per-authenticated-user rate limit appropriate for destructive, history-dependent work, and reject over-limit requests before calling hardDeleteContact.
Flagged by Autter security & observability checks.
| if (contacts.length === 1 && page > 1) { | ||
| setPage(page - 1) | ||
| } else { | ||
| fetchContacts() |
There was a problem hiding this comment.
🟡 [ai] Post-delete refresh failures leave stale UI or report a false deletion failure — Risk: 32/100
Once DELETE succeeds, a failed contacts GET is swallowed by fetchContacts() and leaves the deleted contact in the displayed array, while a thrown list-info refresh at line 182 reaches this handler's catch and shows Failed to delete contact even though the destructive operation has already completed. In the latter case, the user is told deletion failed and may retry an irreversible operation; in the former, the deleted row remains actionable and a retry returns 404. Keep the delete result separate from refresh errors, remove the deleted row/update counts locally after success, and report refresh failure as a refresh issue rather than a delete failure.
⚠ Downstream affected — if this fails, it cascades to the usage that depends on this file:
- Dependent files:
app/(dashboard)/lists/[id]/page.tsx,app/api/internal/contacts/[id]/route.ts
🛠 AI fix prompt (copy & paste into your coding agent)
Separate the successful DELETE outcome from subsequent refreshes. Remove the deleted contact and update pagination/counts immediately, then handle contact/list refresh errors with a distinct refresh warning rather than reporting that deletion failed.
Flagged by Autter security & observability checks.
🧪 Autter test runAutter checked This PR changes 2 source files. No project test command ran for the touched workspace. It wrote 1 temporary test for changed files that had no matching test, so the new behavior is still checked. It also executed 1 check from the PR's test plan. Targeted agent checks: Autter ran targeted checks against the files this PR changed — it executed uncovered test-plan items and, where a changed file had no matching test, wrote a temporary test to verify the new behavior. Execution summary: 2 checks executed · 2 passed. Project test commandsNo project test commands were detected in this repository. Autter targeted verification2 tests executed · 2 passed. Critical feature verificationPlan: Delete a contact from a list in the dashboard, including server-side persistence and audit logging — On staging, use the authenticated dashboard to create a disposable list and one synthetic contact, then delete that contact from /lists/{listId}. Verify the confirmation UI, DELETE API result, removal from subsequent contact queries, updated list counts, and contact.delete audit event. This exercises the browser-to-API-to-Postgres boundary without sending email. (Configured APP_URL is https://app.autter.dev (production; do not use for this destructive test). The safe target must be an isolated staging deployment running this PR with its own staging database. No staging URL or authenticated test identity is configured in this session.)
Run could not complete: The only configured APP_URL is production https://app.autter.dev; no staging target or authenticated staging test identity is supplied (ADMIN_EMAIL and ADMIN_PASSWORD are unset), and the documented local target http://localhost:3000 is not running. Contact deletion is irreversible, so there is no safe configured target on which to execute this scenario. Code-level simulationsRevision
Tests for this change Autter wrote 1 temporary test for changed files that had none (1 passed, 0 failed). 1 changed source file stayed unchecked. Changed files with no execution-backed check
Change coverage (is each changed file's behavior verified by a test?)
🤖 Coverage-check evidenceapp/(dashboard)/lists/[id]/page.tsx app/api/internal/contacts/[id]/route.ts Temporary tests are written under Test plan (from the PR description)
🤖 Agent-executed checks✅ Run ⬜ items could not be verified automatically and still need a manual check. |
|
Autter's deep review traced 1 finding(s) to file(s) this PR does not change — they can't be shown as inline comments, but the change still affects them: 🟠 [deterministic] Product walk mission blocked: Verify that / loads without a demonstrated runtime failure. (risk 55/100)
The browser controller stopped with http_5xx_observed. Failed deterministic assertions: no_console_errors, no_http_5xx. |
Autter product walkAutter opened the app, but the product walk failed before it could confirm this change. The browser controller stopped with http_5xx_observed. Failed deterministic assertions: no_console_errors, no_http_5xx. |
There was a problem hiding this comment.
Autter approved #8 with notes: the merge gate is clear, and 11 non-blocking finding(s) remain as review detail. (Also detected: 9 finding(s) dismissed as likely false positives by verification.)
Autter task listNo concrete follow-up tasks were generated for this PR. Generated from PR diff, blast radius, and context. Issues foundNo unresolved code findings remain for this revision — 9 finding(s) dismissed as likely false positives by verification. Dismissed findings stay listed with their verdicts in the Autter review dashboard. 15 additional non-blocking finding(s) are available in the Autter review. |
What
Adds a trash icon to every contact row on the list detail page (
/lists/[id]) so a contact can be removed without going through the GDPR flow....menu.API
New route:
DELETE /api/internal/contacts/[id]hardDeleteContactfromlib/gdpr, socampaign_sendsandcampaign_eventscascade away with the contact.contact.deleteaudit log entry with the email, list id, and how many sends and events were removed.404when the contact does not exist.Route sits under
/api/internal, so the existing session middleware guard applies.Notes
...menu.tsc --noEmitandnext lintare clean. Existing warnings elsewhere are pre-existing.Need help on this PR? Tag
@codesmith-botwith what you need. Autofix is disabled.Summary
Summary generated by Autter.
Why this change
The list detail view lacked a lightweight way to remove a single contact, leaving only the GDPR delete flow that requires email confirmation and deletes all related data. This change adds a per-row removal action for routine list management.
What changes for users
The contacts table on
app/(dashboard)/lists/[id]/page.tsxnow shows a delete (Trash2) icon with a confirmation dialog that removes the contact viaDELETE /api/internal/contacts/[id]. After deletion the contacts list and counts refresh with success or error toasts.Implementation and review notes
app/api/internal/contacts/[id]/route.ts(+34 lines) backs the delete action; check auth, validation, andNextResponse.jsonerror shape.app/(dashboard)/lists/[id]/page.tsx(+103/-22) withdeleteTarget/deletingstate, rowTrash2action, and confirmationDialog.gdpr-deleteandgdpr-exporthandlers inListDetailPage.Changes
DELETE /api/internal/contacts/[id]inapp/api/internal/contacts/[id]/route.tsto delete a single contact by ID withNextResponse.jsonerror handling.app/(dashboard)/lists/[id]/page.tsxto add per-rowTrash2delete action in the contacts table.deleteTargetanddeletingstate plus confirmationDialogfor the non-GDPR removal flow, distinct from existinggdprDeleteContactandgdpr-exportlogic.meta, and list counts with success and destructivetoastfeedback.Acceptance Criteria
DELETE /api/internal/contacts/[id]and removes the contact from the list on success.npx tsc --noEmitandnpm run lintpass.Test Plan
/lists/[id]and confirm a delete icon appears in each contact row.npx tsc --noEmitandnpm run lint.Rollback Plan
68b2768e65de7ba98a80b2e80a94e62a515ede75to remove the new route and UI action, then redeploy the web app.lib/db/schema.tsordrizzle/migrations/.Related Issues
Written for commit 68b2768. Summary will update on new commits.