Product Decisions This Supports
- Build vs. buy (buy/adopt). Threaded comments with polymorphic attachment points, soft deletes, cascade cleanup, and scheduled pruning are pure commodity plumbing — roughly 2–4 engineer-weeks to build and a permanent maintenance tax. This package collapses that into a composer require, which is the single biggest decision it informs.
- One comment system vs. many. The
HasComments / Commenter split (and the fact that one model can be both) means a single table serves tickets, documents, CRM records, and public pages. This lets you defer the "do we need a separate discussion model per feature?" debate and standardize on one data shape early.
- Roadmap scoping. Nested-to-any-depth replies plus anonymous comments cover forum/Q&A and public-feedback surfaces. What is not included — moderation states, flagging, spam detection, mentions, reactions, rich text, notification delivery, per-thread permissions — is therefore explicitly in-house scope. Budget it as such rather than assuming "comments are done."
- Retention and compliance posture. Soft deletes, cleanup on commenter/model deletion, and
model:prune with configurable frequency and chunk size turn data-retention into a config value instead of an engineering project. This directly supports GDPR/erasure and storage-growth conversations.
- Notification and integration surface.
Commented, Replied, and CommentDeleted dispatched after commit means notifications, search indexing, webhooks, and moderation queues can be layered on without forking the package — a meaningful de-risking of future feature asks.
- Infrastructure decisions. Configurable connection/table/model supports multi-tenant or read-replica topologies and lets you isolate comment traffic from primary write paths.
- Guardrails as product rules. The refusal of a parent comment belonging to another model, and force-delete cascading to replies, encode correctness rules you would otherwise have to spec and test yourself.
When to Consider This Package
Adopt when most of these hold:
- You need comments or discussion threads on two or more distinct entities — the polymorphic design is where the payoff concentrates.
- Your team is small and has no appetite to own threading recursion, orphan cleanup, and pruning edge cases forever.
- You want nesting, soft deletes, and lifecycle cleanup as defaults, not as backlog items.
- You are comfortable with a package-owned table, ULID keys, and a config-driven connection/table/model.
- You can verify framework/PHP version compatibility and acceptable maintenance activity against your app (this is a v1.0.0 — first stable release, no migration history, unknown long-term maintenance signal). Treat a 1–2 day integration spike as mandatory.
Look elsewhere or build when:
- Moderation, abuse/spam handling, flagging, or rate limiting are first-class product requirements — none are in scope here.
- You need per-thread ACLs, complex tenant scoping, or audit-grade immutability (soft deletes are not an audit trail).
- You need real-time collaboration, presence, mentions, reactions, or bundled notifications.
- You expect high volume and deep nesting — "nested to any depth" is a UX and query-cost risk; you will need a flattening/pagination strategy above this layer.
- You must map onto an existing comment table or legacy data with its own schema.
- Rich-text authoring and sanitization are required out of the box — they are not.
How to Pitch It (Stakeholders)
To executives: A low-risk, commodity infrastructure adoption. Commenting, replies, deletion semantics, and data cleanup are solved problems we should not be paying engineers to re-solve. Expected saving is multiple engineer-weeks plus ongoing maintenance, with the remaining product work — moderation, permissions, notifications, UI — budgeted separately and visible. It also makes retention policy a configuration decision, which helps on compliance.
To engineering: Interfaces plus traits (CanComment/Commenter, HasComments/Commentable, usable together), a clean API (comment, reply, addComment, addReply), read helpers (rootComments, replies, authoredComments, isOn), ULID keys, soft deletes with FK cascade on force delete, cleanup on parent/commenter deletion, scheduled model:prune with configurable frequency and chunk size, and post-commit events. Configurable connection, table, and model. Cross-model parent assignment is rejected at the boundary.
Ask: approve a 1–2 day spike to validate version compatibility, migration/rollback behavior, and query performance under realistically deep threads. If it passes, adopt and treat moderation, permissions, rich text, and notifications as explicitly in-house scope.