Skip to content

Epic/plugin arch#434

Open
Hercilio1 wants to merge 33 commits into
masterfrom
epic/plugin-arch
Open

Epic/plugin arch#434
Hercilio1 wants to merge 33 commits into
masterfrom
epic/plugin-arch

Conversation

@Hercilio1

@Hercilio1 Hercilio1 commented Jun 4, 2026

Copy link
Copy Markdown
Contributor

Plugin Architecture v1

Hercilio1 and others added 21 commits February 25, 2026 09:10
…#390)

# Important Notes

This PR covers the following deliveries:
- Plugin architecture core in stable mode (covered with unit tests).
- PoC implemented in `/baseapp-auth`, `/baseapp-comments`, and
`/baseapp-pages`, exploring the new plugin architecture.
- Follow-up stories will focus on stabilizing these changes (reviewing
the implementation and adding proper unit test coverage).
- PoC in `/comments` removing all concrete models (and their
migrations).


---

# Acceptance Criteria

## Description

Implement the core plugin engine for `baseapp-backend`, including plugin
discovery, loading, and enable/disable behavior. This story focuses on
the plug-and-play mechanics and ensuring the system is robust through
thorough unit and integration testing.

A `testproject/` environment will be used to validate the design by
creating a new app that follows the plugin structure and exercises the
full plugin lifecycle and registration features.

---

## This story is done when:

- The core plugin loading mechanism is implemented (discovery +
initialization).
- Plugins can be enabled/disabled via settings.
- Disabled plugins register nothing.
- A new plugin-based app is created under `testproject/` to validate:
  - Plugin discovery and load order  
  - Plugin lifecycle hooks being invoked as expected  
  - Registration behavior (and lack of it when disabled)
- Unit tests cover the plugin engine behavior (loading, toggling,
failure modes).
- Integration tests validate plugin behavior end-to-end using
`testproject/`.

---

## Notes

- This story is about the plugin engine core, not migrating existing
apps.
- The `testproject/` plugin app is the reference for validating behavior
and for future migrations.
- Prioritize predictable behavior and strong test coverage over adding
extra features.
- Try to use the root `pyproject.toml` to define entry points.

---

## Approvd

https://app.approvd.io/silverlogic/COP/stories/45020

---------

Co-authored-by: Hercilio Ortiz <ho@tsl.io>
Co-authored-by: Filipe de Castro <fc@tsl.io>
Co-authored-by: Alisson Patricio <eu@alisson.net>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
#399)

Description:

Refactor baseapp_profiles to comply with the BaseApp plugin
architecture, removing all cross-package model coupling and ensuring all
integration (settings, URLs, GraphQL, services) is registry-driven. The
goal is to make profiles a decoupled, plugin-based package that
communicates only via DocumentId, shared services, and named GraphQL
shared interfaces.



This story is done when:

Concrete vs extendable model responsibilities are clearly defined and
aligned with the plugin architecture.
All model-level coupling to other BaseApp apps (comments, follows,
reports, blocks, pages, auth) is removed.
No cross-package runtime imports remain.
A plugin.py exists and contributes settings and GraphQL mixins via the
plugin registry.
GraphQL interfaces are consumed by name only (no direct imports from
other packages).
Any cross-app behavior (e.g. profile creation, URL path generation) is
exposed or consumed via shared services.
The project uses only plugin_registry.get(...) and get_all_* for
settings, URLs, and GraphQL integration.


Notes:

Follow the baseapp_profiles section in
REFACTOR_PLUGIN_ARCHITECTURE_BY_APP.md as the source of truth for (ref:
https://github.com/silverlogic/baseapp-backend/blob/996589b1473aedf7982cd9f29c76416da9bd38e2/REFACTOR_PLUGIN_ARCHITECTURE_BY_APP.md#baseapp_profiles):
Database Migration expectations.
Database Coupling removal (mixins and FKs).
Settings and plugin registration requirements.
GraphQL shared interface rules.
Shared services exposure/consumption patterns.
This is a high-impact refactor because profiles are heavily used across
the ecosystem (auth, organizations, pages, comments, etc.). Migration
sequencing and decoupling must be carefully validated before merging.

---

Dev Notes:
- I decided to keep the Model-level coupling with profiles and rely on
migrations when the app is disabled. Otherwise, it would be extremelly
expensive to do the refactoring.

---------

Co-authored-by: Hercilio Ortiz <ho@tsl.io>
…403)

## Acceptance Criteria

### Description

Refactor `baseapp_pages` to comply with the BaseApp plugin architecture,
ensuring it is fully registry-driven and does not create cross-package
coupling. The goal is to make pages a clean, decoupled package that
communicates with other apps only via `DocumentId`, shared services, and
named GraphQL shared interfaces.

### This story is done when:

* Concrete vs extendable model responsibilities are clearly defined and
aligned with the plugin architecture.
* No model-level coupling to other BaseApp apps exists.
* All settings and GraphQL contributions are provided via `plugin.py`.
* No project-level hardcoded imports of pages GraphQL mixins remain.
* GraphQL interfaces are consumed strictly by name (no direct imports
from other packages).
* Any behavior consumed by other apps (e.g. `URLPath`) is exposed via
shared services instead of direct model imports.
* The project builds URLs and GraphQL schema exclusively via
`plugin_registry.get(...)` and `get_all_*` methods.

### Notes

* Follow the `baseapp_pages` section in
`REFACTOR_PLUGIN_ARCHITECTURE_BY_APP.md` as the source of truth:

[https://github.com/silverlogic/baseapp-backend/blob/996589b1473aedf7982cd9f29c76416da9bd38e2/REFACTOR_PLUGIN_ARCHITECTURE_BY_APP.md#baseapp_pages](https://github.com/silverlogic/baseapp-backend/blob/996589b1473aedf7982cd9f29c76416da9bd38e2/REFACTOR_PLUGIN_ARCHITECTURE_BY_APP.md#baseapp_pages)

* Includes:

  * Database migration expectations
  * Settings and plugin registration requirements
  * GraphQL shared interface rules
* Shared service exposure for `URLPath` (so `baseapp_profiles` stops
importing `URLPath` directly)

* Special attention:

* Replace direct import of `PermissionsInterface` from `baseapp_auth`
with named interface resolution via `graphql_shared_interface_registry`.
* If pages expose URL patterns, ensure they are contributed via plugin
callbacks and not hardcoded in the project.

### Approvd


[https://app.approvd.io/silverlogic/BA/stories/45726](https://app.approvd.io/silverlogic/BA/stories/45726)

---

Used the rest of the budget to also adapt the baseapp_organization

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

## Release Notes

* **New Features**
* Enhanced organization admin interface with name-based search and
streamlined display.
  * Service-based URL path generation for improved extensibility.

* **Refactor**
* Modernized plugin architecture for better feature composition and
conditional package handling.
  * Unified GraphQL interface registration patterns across modules.
  * Improved metadata resolution for conditional optional dependencies.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Co-authored-by: Hercilio Ortiz <ho@tsl.io>
…re and decouple cross app dependencies (#405)

## User Story

The BaseApp ecosystem needs to standardize how apps are structured and
integrated under the new plugin architecture. Several apps currently
contain tight coupling, inconsistent migration strategies, and direct
cross-app dependencies that limit extensibility and modularity.

This effort ensures that each app follows the plugin-driven
architecture, removes unnecessary coupling, and clearly defines shared
interfaces and services, enabling scalable and maintainable extension
across projects.


## Acceptance Criteria

This story is done when:

* Each targeted app (`baseapp_payments`, `baseapp_pdf`,
`baseapp_referrals`, `baseapp_message_templates`,
`baseapp_cloudflare_stream_field`) is reviewed and updated to keep only
non-extendable concrete models, so that extensibility is preserved where
needed.

* Migration folders are removed for apps that no longer contain concrete
models, so that unnecessary database artifacts are eliminated.

* All database coupling to other BaseApp apps (e.g., Profile, swapper
usage, shared mixins) is identified and removed or replaced with
decoupled approaches (such as DocumentId or project-owned models), so
that apps can operate independently.

* Each app clearly documents whether it has remaining database coupling
or confirms that it is fully decoupled, so that architectural boundaries
are explicit.

* Apps that should be plugin-driven are registered via entry points in
`pyproject.toml`, so that they can be dynamically discovered and
enabled.

* Each app contributes its required configuration (e.g.,
`INSTALLED_APPS`, GraphQL operations, URLs, middleware, auth backends)
through the plugin system, so that the project composes behavior through
registries instead of direct imports.

* All URL registrations are handled via plugin callbacks, so that
routing is modular and centrally orchestrated.

* Any shared GraphQL interfaces are registered via the shared interface
registry and consumed by name (not direct imports), so that cross-app
GraphQL dependencies remain loosely coupled.

* Any shared logic used by other apps is exposed through the shared
service registry, so that inter-app communication is standardized and
replaceable.

* All registrations (interfaces and services) are initialized in
`AppConfig.ready()`, so that plugin behavior is consistently
bootstrapped.

* The final structure ensures that no app relies on direct cross-package
imports for shared behavior, so that the system adheres to the plugin
architecture principles.


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **New Features**
* Added REST API endpoints for managing Stripe payments: subscriptions,
customers, payment methods, and products.
  * Introduced plugin system for modular configuration management.
  * Added API schema documentation support via drf-spectacular.

* **Bug Fixes & Refactoring**
  * Reorganized database migrations and models for improved flexibility.
  * Updated app configurations for consistency.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Co-authored-by: Hercilio Ortiz <ho@tsl.io>
…ening to plugin architecture and disable wagtail module (#409)

## User Story

The AST/BaseApp ecosystem needs to standardize how core apps are
structured and integrated under the plugin architecture. Some apps still
rely on direct imports, database coupling, or legacy configuration
patterns that limit modularity and extensibility.

This effort refactors `baseapp_notifications`, `baseapp_activity_log`,
and `baseapp_url_shortening` to follow the plugin-driven architecture,
removes cross-app coupling, introduces shared services where needed, and
disables `baseapp_wagtail` without removing its implementation, ensuring
the system remains flexible and maintainable.

---

## Acceptance Criteria

This story is done when:

* `baseapp_notifications` exposes its notification functionality as a
shared service (e.g. `send_notification`) through the shared service
registry, so that other apps (comments, reactions, chats) no longer rely
on direct imports.

* All consumers of notifications (comments, reactions, chats) use
`shared_service_registry.get_service("notifications")`, so that
inter-app communication is decoupled and consistent.

* `baseapp_notifications` is registered as a plugin and contributes its
GraphQL operations (mutations/subscriptions) and settings via the
registry, so that it integrates through the plugin system instead of
static configuration.

* `baseapp_activity_log` removes its coupling to Profile (or any other
baseapp app), so that it no longer depends on external models and
becomes independently reusable.

* `baseapp_activity_log` is registered as a plugin and contributes its
GraphQL queries via the registry, so that it follows the standardized
architecture.

* Any concrete models in `baseapp_notifications`,
`baseapp_activity_log`, and `baseapp_url_shortening` are reviewed and
removed if they should be extendable, so that database flexibility is
preserved.

* Migration folders are removed from any app that no longer contains
concrete models, so that unnecessary database artifacts are eliminated.

* `baseapp_url_shortening` contributes its URLs through the plugin
system (e.g. `v1_urlpatterns`) instead of direct inclusion, so that
routing is centrally managed via registry.

* `baseapp_url_shortening` is optionally registered as a plugin if it
should be dynamically enabled, so that it aligns with the plugin-driven
architecture.

* No app introduces or maintains direct cross-package imports for shared
behavior, so that all interactions happen through registries.

* `baseapp_wagtail` is disabled at the project level without removing
its internal code, so that it can be re-enabled in the future without
reimplementation.

* All plugin registrations and shared services are initialized in
`AppConfig.ready()`, so that the system bootstraps consistently across
apps.


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **New Features**
* Plugin-driven architecture for Activity Logs, Notifications, and URL
Shortening modules.
* Shared services pattern for centralized access to activity log and
notification functionality.

* **Refactor**
* Migrated core modules to plugin registry pattern for improved
extensibility.
* Notifications system restructured with abstract base classes and
dynamic service lookup.
  * GraphQL interfaces updated to support plugin-based discovery.
* Authentication backends now dynamically loaded via plugin
configuration.

* **Bug Fixes**
* Enhanced activity log filtering to respect proper user/profile
scoping.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Co-authored-by: Hercilio Ortiz <ho@tsl.io>
…ve cross app coupling (#416)

## User Story

The baseapp_comments app needs to align with the BaseApp plugin
architecture and remove tight coupling with other apps such as profiles,
reactions, reports, and notifications. The current implementation relies
on direct model relationships and shared mixins, which limits
extensibility and violates the modular design required by the plugin
system.

This effort refactors the comments system to use DocumentId-based
targeting, shared services, and registry-driven integrations, ensuring
that the app becomes fully decoupled, extensible, and consistent with
the plugin architecture.

---

## Acceptance Criteria

This story is done when:

- Concrete `Comment` and `CommentStats` models are removed or made
abstract/swappable when appropriate, so that the app supports
extensibility without enforcing rigid implementations.
- The migrations folder is removed if no concrete models remain, so that
unnecessary database artifacts are eliminated.
- All coupling to `baseapp_profiles` (e.g., profile FK via swapper) is
removed or replaced with a decoupled reference, so that the comments
system does not depend on profile models.
- All coupling to `baseapp_reactions` and `baseapp_reports` (via mixins
such as `ReactableModel` and `ReportableModel`) is removed or replaced
with a decoupled pattern, so that cross-app dependencies are eliminated.
- The `CommentableModel` pattern is removed and replaced with
DocumentId-based targeting, so that comments can attach to any entity
without direct model coupling.
- `CommentStats` is refactored to reference `DocumentId` instead of
`Comment`, including required migrations and data backfill, so that
statistics are aligned with the new decoupled model.
- All comment targets use `DocumentId` (via mixin or helper), so that
the system consistently identifies entities without direct foreign keys.
- The app is fully integrated with the plugin system (settings, GraphQL
operations, authentication backends, URLs), so that it is discovered and
configured via the registry.
- GraphQL shared interfaces are resolved by name using the shared
interface registry, so that no direct cross-package imports are
required.
- The existing `comments_count` shared service is properly registered
and consumed via the shared service registry, so that inter-app
communication is standardized.
- The app consumes external functionality (e.g., notifications,
reactions) via shared services instead of direct imports, so that
dependencies are loosely coupled.
- Signals (e.g., document creation handling) operate using `DocumentId`
and correctly maintain `CommentStats`, so that derived data remains
accurate.
- The final structure contains no direct cross-app model or service
dependencies, so that the app adheres to plugin architecture principles
and can be reused independently.

---

## Approvd

https://app.approvd.io/silverlogic/BA/stories/46103

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

# Release Notes

* **New Features**
* Introduced `CommentableMetadata` model for streamlined metadata
management
  * Added service-based architecture for accessing comment information

* **Bug Fixes**
  * Fixed comment ordering and counting calculations
  * Improved query optimization for reduced database load

* **Refactor**
* Restructured comment target storage system for better data
organization
  * Updated subscription routing to use optimized target references

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
…#420)

## User Story

The `baseapp_follows` app is already decoupled from direct database
dependencies, but it still needs to be aligned with the plugin
architecture and optimized for performance. Current queries involving
DocumentId may introduce inefficiencies such as N+1 patterns, which can
impact scalability and response times.

This effort ensures that all follow-related queries are optimized and
that the app fully adopts the plugin architecture, enabling better
performance, modularity, and consistency across the BaseApp ecosystem.

---

## Acceptance Criteria

This story is done when:

* All queries involving DocumentId in `baseapp_follows` are reviewed and
optimized, so that N+1 query patterns are eliminated.

* Query performance is improved through appropriate use of batching,
prefetching, or equivalent strategies, so that follow-related operations
scale efficiently.

* The app is fully integrated into the plugin architecture (settings,
GraphQL, URLs if applicable), so that it is discovered and configured
via the registry.

* All GraphQL resolvers avoid inefficient per-item database access, so
that list-based queries do not degrade performance.

* No direct cross-app imports are introduced or retained, so that the
app remains decoupled and modular.

* Any shared functionality exposed by `baseapp_follows` is provided
through the shared service registry (if applicable), so that other apps
can interact with it in a standardized way.

* The project consumes all contributions from `baseapp_follows` via
registry getters only, so that configuration is centralized and
consistent.

* Performance improvements are validated in representative scenarios, so
that the optimizations have measurable impact.

* The refactor does not introduce regressions in follow/unfollow
behavior or data consistency, so that existing functionality remains
intact.


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **New Features**
* DocumentId-based follow tracking enables follows across diverse model
types.
  * Plugin-based architecture for improved extensibility.
* FollowableMetadata service provides efficient follow count caching and
retrieval.

* **Bug Fixes**
* Optimized GraphQL query performance through request-scoped caching and
prefetching.

* **Refactor**
  * Migrated from Profile foreign keys to DocumentId references.
  * Replaced FollowStats model with swappable FollowableMetadata.
  * Updated GraphQL interfaces to use optimized field resolvers.

* **Tests**
* Added comprehensive test coverage for new resolver utilities and
migration helpers.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
…423)

User Story
The baseapp_ratings and baseapp_reports apps need to be aligned with the
BaseApp plugin architecture and updated to remove remaining coupling
patterns. While these apps are relatively self-contained, they still
rely on patterns such as direct Profile references or model inheritance
that limit extensibility and reuse.

This effort ensures both apps follow the plugin-driven architecture,
remove unnecessary coupling, and expose functionality through
standardized mechanisms such as registries and shared services where
appropriate.

Acceptance Criteria
This story is done when:

Concrete models in baseapp_ratings and baseapp_reports are reviewed and
removed if they should be extendable, so that flexibility is preserved
for project-level customization.

Migration folders are removed from apps that no longer contain concrete
models, so that unnecessary database artifacts are eliminated.

All coupling between baseapp_ratings and baseapp_profiles (e.g., Profile
FK via swapper) is removed or replaced with a decoupled reference (such
as DocumentId or project-owned models), so that the ratings system is
independent.

baseapp_reports remains free of coupling to other baseapp apps, and any
future dependency on Profile or external models is avoided or replaced
with a decoupled pattern, so that the app stays modular.

Both apps are registered as plugins and contribute their GraphQL
operations and settings via the registry, so that configuration is
centralized and dynamic.

Any URLs exposed by these apps are contributed via plugin callbacks, so
that routing is managed through the registry.

GraphQL shared interfaces are resolved by name only, so that no direct
cross-package imports are required.

If ratings expose reusable logic (e.g., average rating or counts), a
shared service is introduced and consumed via the shared service
registry, so that other apps can access this functionality without
direct imports.

If reports functionality needs to be consumed externally (e.g., report
counts or reportable checks), a shared service is introduced (e.g.,
get_report_count(document_id)), so that consumers like comments use
registry-based access instead of inheritance patterns.

Any existing inheritance-based coupling (e.g., ReportableModel) is
removed or replaced with service-based or DocumentId-based approaches,
so that apps interact through decoupled contracts.

All plugin registrations and optional shared services are initialized in
AppConfig.ready(), so that the system bootstraps consistently.

The final structure contains no direct cross-app dependencies and
adheres to plugin architecture principles, so that both apps are
reusable and maintainable.

Approvd
https://app.approvd.io/silverlogic/BA/stories/46317

Notes
It was decided to also cover baseapp_reactions in this story

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

## Release Notes

* **Architecture Improvements**
* Optimized data model architecture for ratings, reactions, and
reports—reducing database queries through metadata services and
efficient queryset annotations.
* Migrated from generic foreign key patterns to document-based targeting
for improved data consistency.

* **Plugin Integration**
* Enhanced plugin-based GraphQL schema contributions for ratings,
reactions, and reports interfaces.
* Enabled modular plugin registration for authentication backends and
shared services.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Co-authored-by: Hercilio Ortiz <ho@tsl.io>
…uple cross app dependencies (#431)

## Title

Refactor BaseApp Mentions to Plugin Architecture and Decouple Cross-App
Dependencies

---

## User Story

The `baseapp_mentions` app needs to be aligned with the BaseApp plugin
architecture and updated to remove any implicit coupling with other apps
such as profiles or content models. Mentions typically rely on
identifying users and linking them to content, but this must be handled
through decoupled mechanisms to ensure flexibility and reuse.

This effort refactors mentions to rely on DocumentId or project-owned
identity references, integrates it into the plugin system, and
standardizes how it interacts with other apps through shared services
and registries.

---

## Acceptance Criteria

This story is done when:

* Concrete models in `baseapp_mentions` are reviewed and removed if they
should be extendable, so that projects can define their own mention
implementations.

* The migrations folder is removed if no concrete models remain, so that
unnecessary database artifacts are eliminated.

* Any coupling to `baseapp_profiles` (e.g., user/profile references) is
removed or replaced with a decoupled identity reference (such as
DocumentId or project-owned models), so that the mentions system is
independent.

* Mentions are associated with target content using DocumentId or an
equivalent decoupled mechanism, so that they can reference any entity
without direct foreign keys.

* The app is registered as a plugin and contributes its settings and any
GraphQL operations via the registry, so that it integrates dynamically
into the project.

* Any URLs exposed by the mentions app are contributed via plugin
callbacks, so that routing is managed through the registry.

* GraphQL shared interfaces are resolved by name using the shared
interface registry, so that no direct cross-package imports are
required.

* Any interaction with other apps (e.g., notifications when a user is
mentioned) is handled through shared services, so that cross-app
communication is decoupled.

* The app consumes external functionality (e.g., notifications) via
`shared_service_registry.get_service(...)` instead of direct imports, so
that dependencies remain loosely coupled.

* A shared service is introduced only if mentions expose reusable
behavior (e.g., resolving mentions for a document), so that other apps
can interact with mentions through a standardized interface.

* All plugin registrations and optional shared services are initialized
in `AppConfig.ready()`, so that the app bootstraps consistently.

* The final structure contains no direct cross-app dependencies and
adheres to plugin architecture principles, so that the mentions system
is reusable and maintainable.


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **New Features**
* Introduced plugin-based mentions system with optimized query
performance through batched loading and prefetching.
  * Added comment visibility filtering and target-based comment queries.

* **Bug Fixes**
* Improved mentions data retrieval efficiency across paginated queries.

* **Documentation**
* Added comprehensive documentation for the mentions feature including
setup, configuration, and usage guidelines.

<!-- review_stack_entry_start -->

[![Review Change
Stack](https://storage.googleapis.com/coderabbit_public_assets/review-stack-in-coderabbit-ui.svg)](https://app.coderabbit.ai/change-stack/silverlogic/baseapp-backend/pull/431?utm_source=github_walkthrough&utm_medium=github&utm_campaign=change_stack)

<!-- review_stack_entry_end -->

<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Co-authored-by: Hercilio Ortiz <ho@tsl.io>
## Title

Refactor BaseApp Chats to Plugin Architecture and Remove Profile
Coupling

---

## User Story

The `baseapp_chats` app needs to be aligned with the BaseApp plugin
architecture and updated to remove its dependency on profile-based
models. The current implementation relies on direct foreign keys to
Profile and tightly coupled structures, which limits extensibility and
prevents reuse across different projects.

This effort refactors the chats system to use a decoupled identity
approach (e.g., DocumentId or project-owned models), integrates it into
the plugin architecture, and standardizes cross-app interactions through
shared services.

---

## Acceptance Criteria

This story is done when:

* Concrete models in `baseapp_chats` (e.g., Message, ChatRoom,
ChatRoomParticipant, UnreadMessageCount, MessageStatus) are reviewed and
removed if they should be extendable, so that projects can define their
own implementations.

* The migrations folder is removed if no concrete models remain, so that
unnecessary database artifacts are eliminated.

* All coupling to `baseapp_profiles` (e.g., FKs via swapper in
chat-related models) is removed or replaced with a decoupled identity
reference (such as DocumentId or project-owned models), so that the
chats system is independent.

* The app is registered as a plugin and contributes its GraphQL queries,
mutations, subscriptions, and settings via the registry, so that
configuration is centralized and dynamic.

* The root GraphQL schema consumes chats contributions via registry
getters only, so that no direct imports of chats GraphQL modules are
required.

* Any URLs exposed by the chats app are contributed via plugin
callbacks, so that routing is managed through the registry.

* GraphQL shared interfaces are resolved by name using the shared
interface registry, so that no direct cross-package imports are
required.

* The chats app consumes notifications via the shared service registry
(e.g., `shared_service_registry.get_service("notifications")`), so that
it no longer relies on direct imports from `baseapp_notifications`.

* No new direct cross-app dependencies are introduced, so that the chats
app remains modular and reusable.

* A shared service is introduced only if reusable chat functionality
(e.g., unread message counts) needs to be exposed to other apps, so that
inter-app communication remains intentional and standardized.

* All plugin registrations and optional shared services are initialized
in `AppConfig.ready()`, so that the app bootstraps consistently.

* The final structure adheres to plugin architecture principles and
allows the chats system to be reused independently of other baseapp
modules.


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **New Features**
* New chat participation cleanup service for automatic management of
user data during account removal.

* **Improvements**
* Enhanced GraphQL chat query performance with optimized data retrieval.
* Comprehensive documentation covering setup, configuration, real-time
messaging, and service integration.
  * Better message and participant tracking systems.

* **Refactor**
* Chat system restructured as extensible plugin component supporting
customizable implementations.

<!-- review_stack_entry_start -->

[![Review Change
Stack](https://storage.googleapis.com/coderabbit_public_assets/review-stack-in-coderabbit-ui.svg)](https://app.coderabbit.ai/change-stack/silverlogic/baseapp-backend/pull/432?utm_source=github_walkthrough&utm_medium=github&utm_campaign=change_stack)

<!-- review_stack_entry_end -->

<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Co-authored-by: Hercilio Ortiz <ho@tsl.io>
**User Story**
The baseapp_content_feed and baseapp_blocks apps need to be aligned with
the BaseApp plugin architecture and updated to remove remaining database
and inheritance-based coupling. Both apps currently depend on other
baseapp modules (e.g., profiles, reactions) and use patterns that limit
modularity and reuse.

This effort ensures both apps are fully decoupled, rely on DocumentId or
project-owned models where appropriate, and integrate through registries
and shared services, enabling a consistent and extensible architecture.

**Acceptance Criteria**
This story is done when:

- Concrete models in baseapp_content_feed and baseapp_blocks are
reviewed and removed if they should be extendable, so that projects can
define their own implementations.
- Migration folders are removed from apps that no longer contain
concrete models, so that unnecessary database artifacts are eliminated.
- All coupling between baseapp_content_feed and baseapp_profiles (e.g.,
Profile FK via swapper) is removed or replaced with a decoupled
reference (such as DocumentId or project-owned models), so that the app
becomes independent.
- All coupling between baseapp_content_feed and baseapp_reactions (e.g.,
ReactableModel inheritance) is removed, so that interaction with
reactions is handled through a shared service instead of inheritance.
- baseapp_content_feed consumes reactions data via a shared service
(e.g., reactions_count) obtained through the shared service registry, so
that cross-app interaction is standardized.
- All coupling between baseapp_blocks and baseapp_profiles (e.g., FK via
swapper) is removed or replaced with a decoupled reference, so that
blocks do not depend on profile models.
- Both apps are registered as plugins and contribute their GraphQL
operations and settings via the registry, so that they are dynamically
discovered and configured.
- Any URLs exposed by these apps are contributed via plugin callbacks,
so that routing is managed through the registry.
- GraphQL shared interfaces are resolved by name only using the shared
interface registry, so that no direct cross-package imports are
required.
- The project consumes GraphQL queries and mutations from these apps via
registry getters only, so that root configuration remains decoupled.
- Shared services are introduced only if reusable behavior is needed
(e.g., reactions count, block-related utilities), so that the system
avoids unnecessary coupling.
- All plugin registrations and optional shared services are initialized
in AppConfig.ready(), so that the apps bootstrap consistently.
- The final structure contains no direct cross-app model or inheritance
dependencies, so that both apps adhere to plugin architecture principles
and remain reusable.

**Approvd**
https://app.approvd.io/silverlogic/BA/stories/46424

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

## Release Notes

* **New Features**
* Plugin system now supports Blocks and Content Feed as configurable
components.
* Block counts are now managed through an optimized metadata service,
reducing database queries.

* **Improvements**
* GraphQL queries for block-related data are now more efficient with
automatic query optimization.

* **Refactoring**
* Block management architecture simplified and consolidated; legacy
count fields migrated to new metadata system.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Co-authored-by: Hercilio Ortiz <ho@tsl.io>
@coderabbitai

coderabbitai Bot commented Jun 4, 2026

Copy link
Copy Markdown

Important

Review skipped

Too many files!

This PR contains 300 files, which is 150 over the limit of 150.

To get a review, narrow the scope:
• coderabbit review --type committed # exclude uncommitted changes
• coderabbit review --dir # limit to a subdirectory
• coderabbit review --base # compare against a closer base

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 59c76e80-f378-4af0-a6c0-e55a7431b388

📥 Commits

Reviewing files that changed from the base of the PR and between 2e981ac and a75f306.

📒 Files selected for processing (300)
  • .coverage
  • .github/workflows/github-actions.yml
  • baseapp/activity_log/README.md
  • baseapp/activity_log/apps.py
  • baseapp/activity_log/context.py
  • baseapp/activity_log/graphql/filters.py
  • baseapp/activity_log/graphql/interfaces.py
  • baseapp/activity_log/graphql/object_types.py
  • baseapp/activity_log/graphql/shared_interfaces.py
  • baseapp/activity_log/models.py
  • baseapp/activity_log/permissions.py
  • baseapp/activity_log/plugin.py
  • baseapp/activity_log/services.py
  • baseapp/activity_log/tests/conftest.py
  • baseapp/activity_log/tests/integration/__init__.py
  • baseapp/activity_log/tests/integration/test_activity_log_without_baseapp_profiles.py
  • baseapp/content_feed/README.md
  • baseapp/content_feed/admin.py
  • baseapp/content_feed/apps.py
  • baseapp/content_feed/graphql/mutations.py
  • baseapp/content_feed/graphql/object_types.py
  • baseapp/content_feed/migrations/0002_contentpostimage.py
  • baseapp/content_feed/migrations/0003_alter_contentpostimage_image.py
  • baseapp/content_feed/migrations/0004_alter_contentpostimage_post.py
  • baseapp/content_feed/migrations/0005_contentpost_is_reactions_enabled_and_more.py
  • baseapp/content_feed/models.py
  • baseapp/content_feed/plugin.py
  • baseapp/content_feed/tests/conftest.py
  • baseapp/content_feed/tests/integration/__init__.py
  • baseapp/content_feed/tests/integration/test_content_post_create_without_baseapp_profiles.py
  • baseapp/content_feed/tests/test_mentions.py
  • baseapp_api_key/README.md
  • baseapp_api_key/admin.py
  • baseapp_api_key/apps.py
  • baseapp_api_key/graphql/consumers.py
  • baseapp_api_key/plugin.py
  • baseapp_api_key/tests/conftest.py
  • baseapp_api_key/tests/factories.py
  • baseapp_api_key/tests/helpers.py
  • baseapp_api_key/tests/integration/test_graphql_consumer_without_baseapp_profiles.py
  • baseapp_auth/admin.py
  • baseapp_auth/anonymization.py
  • baseapp_auth/graphql/object_types.py
  • baseapp_auth/models.py
  • baseapp_auth/pipeline.py
  • baseapp_auth/plugin.py
  • baseapp_auth/rest_framework/users/serializers.py
  • baseapp_auth/rest_framework/users/tasks.py
  • baseapp_auth/rest_framework/users/views.py
  • baseapp_auth/tests/conftest.py
  • baseapp_auth/tests/graphql/test_queries_me.py
  • baseapp_auth/tests/graphql/test_queries_user.py
  • baseapp_auth/tests/integration/test_auth_without_baseapp_pages.py
  • baseapp_auth/tests/integration/test_auth_without_baseapp_profiles.py
  • baseapp_auth/tests/integration/test_graphql_user_queries_with_activity_log.py
  • baseapp_blocks/README.md
  • baseapp_blocks/apps.py
  • baseapp_blocks/base.py
  • baseapp_blocks/graphql/interfaces.py
  • baseapp_blocks/graphql/mutations.py
  • baseapp_blocks/graphql/object_types.py
  • baseapp_blocks/migration_helpers/__init__.py
  • baseapp_blocks/migration_helpers/convert_legacy_block_counts_to_metadata_helper.py
  • baseapp_blocks/migrations/0001_initial.py
  • baseapp_blocks/migrations/0002_block_user.py
  • baseapp_blocks/migrations/0003_block_actor_block_target_alter_block_user.py
  • baseapp_blocks/migrations/0003_migrate_profiles.py
  • baseapp_blocks/migrations/0004_alter_block_unique_together_and_more.py
  • baseapp_blocks/models.py
  • baseapp_blocks/permissions.py
  • baseapp_blocks/plugin.py
  • baseapp_blocks/services.py
  • baseapp_blocks/tests/integration/__init__.py
  • baseapp_blocks/tests/test_block_count.py
  • baseapp_blocks/tests/test_block_lookup_service.py
  • baseapp_blocks/tests/test_graphql_mutations.py
  • baseapp_blocks/tests/test_graphql_queries_object_blocks.py
  • baseapp_blocks/tests/test_migration_helper_legacy_block_counts.py
  • baseapp_chats/README.md
  • baseapp_chats/apps.py
  • baseapp_chats/base.py
  • baseapp_chats/graphql/interfaces.py
  • baseapp_chats/graphql/mutations.py
  • baseapp_chats/graphql/object_types.py
  • baseapp_chats/graphql/shared_interfaces.py
  • baseapp_chats/graphql/subscriptions.py
  • baseapp_chats/migrations/0001_initial.py
  • baseapp_chats/migrations/0002_message_set_last_message_and_more.py
  • baseapp_chats/migrations/0003_alter_unreadmessagecount_room.py
  • baseapp_chats/migrations/0004_chatroomparticipant_has_archived_room.py
  • baseapp_chats/migrations/0005_remove_messagestatus_increment_unread_count_and_more.py
  • baseapp_chats/migrations/0006_remove_messagestatus_increment_unread_count_and_more.py
  • baseapp_chats/migrations/0007_messagestatus_increment_unread_count.py
  • baseapp_chats/migrations/0008_alter_chatroomparticipant_options.py
  • baseapp_chats/migrations/0009_remove_message_create_message_status_and_more.py
  • baseapp_chats/migrations/0010_message_deleted.py
  • baseapp_chats/migrations/0011_alter_chatroom_created_by_and_more.py
  • baseapp_chats/migrations/0012_chatroom_created_by_profile.py
  • baseapp_chats/migrations/0013_chatroom_insert_document_id_and_more.py
  • baseapp_chats/models.py
  • baseapp_chats/permissions.py
  • baseapp_chats/plugin.py
  • baseapp_chats/services.py
  • baseapp_chats/tests/test_chats_participation_service.py
  • baseapp_chats/tests/test_graphql_queries.py
  • baseapp_chats/tests/test_graphql_query_counts.py
  • baseapp_chats/tests/test_graphql_subscriptions.py
  • baseapp_chats/tests/test_mentions.py
  • baseapp_chats/tests/test_shared_interfaces.py
  • baseapp_chats/utils.py
  • baseapp_cloudflare_stream_field/README.md
  • baseapp_cloudflare_stream_field/apps.py
  • baseapp_cloudflare_stream_field/plugin.py
  • baseapp_comments/README.md
  • baseapp_comments/admin.py
  • baseapp_comments/apps.py
  • baseapp_comments/graphql/__init__.py
  • baseapp_comments/graphql/filters.py
  • baseapp_comments/graphql/interfaces.py
  • baseapp_comments/graphql/mutations.py
  • baseapp_comments/graphql/object_types.py
  • baseapp_comments/graphql/subscriptions.py
  • baseapp_comments/migration_helpers/__init__.py
  • baseapp_comments/migration_helpers/convert_comments_gfk_into_document_id_helper.py
  • baseapp_comments/migration_helpers/convert_legacy_commentable_fields_into_metadata_helper.py
  • baseapp_comments/migrations/0001_initial.py
  • baseapp_comments/migrations/0002_alter_comment_user.py
  • baseapp_comments/migrations/0003_alter_comment_comments_count.py
  • baseapp_comments/migrations/0004_remove_comment_snapshot_insert_and_more.py
  • baseapp_comments/migrations/0005_remove_comment_snapshot_insert_and_more.py
  • baseapp_comments/migrations/0006_remove_comment_snapshot_insert_and_more.py
  • baseapp_comments/migrations/0007_remove_comment_insert_insert_and_more.py
  • baseapp_comments/migrations/0008_comment_new_profile_commentevent_new_profile_and_more.py
  • baseapp_comments/migrations/0009_migrate_profiles.py
  • baseapp_comments/migrations/0010_drop_profile_content_type.py
  • baseapp_comments/migrations/0011_rename_new_profile_to_profile.py
  • baseapp_comments/migrations/0012_alter_comment_options.py
  • baseapp_comments/migrations/0013_alter_commentevent_id.py
  • baseapp_comments/migrations/0014_alter_commentevent_pgh_context_and_more.py
  • baseapp_comments/migrations/0015_alter_commentevent_pgh_context_and_more.py
  • baseapp_comments/migrations/0016_remove_commentevent_in_reply_to_and_more.py
  • baseapp_comments/migrations/0017_alter_comment_profile.py
  • baseapp_comments/migrations/0018_comment_insert_document_id_and_more.py
  • baseapp_comments/models.py
  • baseapp_comments/notifications.py
  • baseapp_comments/permissions.py
  • baseapp_comments/plugin.py
  • baseapp_comments/services.py
  • baseapp_comments/signals.py
  • baseapp_comments/tests/conftest.py
  • baseapp_comments/tests/factories.py
  • baseapp_comments/tests/integration/__init__.py
  • baseapp_comments/tests/integration/test_comment_create_without_baseapp_profiles.py
  • baseapp_comments/tests/integration/test_comment_query_with_baseapp_activity_log.py
  • baseapp_comments/tests/test_commentable_metadata_service.py
  • baseapp_comments/tests/test_comments_count.py
  • baseapp_comments/tests/test_graphql_mutations_create.py
  • baseapp_comments/tests/test_graphql_mutations_delete.py
  • baseapp_comments/tests/test_graphql_mutations_pin.py
  • baseapp_comments/tests/test_graphql_queries_object_comments.py
  • baseapp_comments/tests/test_graphql_subscriptions.py
  • baseapp_comments/tests/test_mentions.py
  • baseapp_comments/tests/test_migration_helper_convert_comments_gfk_into_document_id.py
  • baseapp_comments/tests/test_migration_helper_legacy_commentable_fields.py
  • baseapp_core/admin.py
  • baseapp_core/admin_helpers.py
  • baseapp_core/apps.py
  • baseapp_core/graphql/__init__.py
  • baseapp_core/graphql/models.py
  • baseapp_core/graphql/testing/test_resolve_document_content_object.py
  • baseapp_core/graphql/utils.py
  • baseapp_core/models.py
  • baseapp_core/pghelpers.py
  • baseapp_core/plugins/README.md
  • baseapp_core/plugins/__init__.py
  • baseapp_core/plugins/app_config.py
  • baseapp_core/plugins/base.py
  • baseapp_core/plugins/helpers.py
  • baseapp_core/plugins/readiness.py
  • baseapp_core/plugins/registry.py
  • baseapp_core/plugins/shared_graphql_interfaces.py
  • baseapp_core/plugins/shared_serializers.py
  • baseapp_core/plugins/shared_services.py
  • baseapp_core/plugins/tests/__init__.py
  • baseapp_core/plugins/tests/conftest.py
  • baseapp_core/plugins/tests/fixtures.py
  • baseapp_core/plugins/tests/test_app_config.py
  • baseapp_core/plugins/tests/test_helpers.py
  • baseapp_core/plugins/tests/test_plugin_activation_deactivation.py
  • baseapp_core/plugins/tests/test_plugin_base.py
  • baseapp_core/plugins/tests/test_plugin_registry.py
  • baseapp_core/plugins/tests/test_shared_graphql_interfaces.py
  • baseapp_core/plugins/tests/test_shared_registry_readiness.py
  • baseapp_core/plugins/tests/test_shared_services.py
  • baseapp_core/rest_framework/fields.py
  • baseapp_core/signals.py
  • baseapp_core/swappable.py
  • baseapp_core/swapper.py
  • baseapp_core/tests/settings.py
  • baseapp_core/tests/test_document_id_target_mixin.py
  • baseapp_core/tests/test_pghelpers.py
  • baseapp_core/tests/test_unique_document_target_mixin.py
  • baseapp_drf_view_action_permissions/tests/models.py
  • baseapp_e2e/README.md
  • baseapp_e2e/apps.py
  • baseapp_e2e/plugin.py
  • baseapp_e2e/tests/test_e2e_endpoints.py
  • baseapp_follows/README.md
  • baseapp_follows/apps.py
  • baseapp_follows/graphql/interfaces.py
  • baseapp_follows/graphql/object_types.py
  • baseapp_follows/migration_helpers/__init__.py
  • baseapp_follows/migration_helpers/convert_follow_profile_fks_into_document_id_helper.py
  • baseapp_follows/migration_helpers/seed_followable_metadata_from_follows_helper.py
  • baseapp_follows/migrations/0001_initial.py
  • baseapp_follows/migrations/0002_follow_new_actor_follow_new_target.py
  • baseapp_follows/migrations/0003_migrate_profiles.py
  • baseapp_follows/migrations/0004_alter_follow_unique_together_and_more.py
  • baseapp_follows/migrations/0005_rename_new_actor_follow_actor_and_more.py
  • baseapp_follows/migrations/0006_alter_follow_actor_alter_follow_target.py
  • baseapp_follows/migrations/0007_alter_follow_unique_together.py
  • baseapp_follows/migrations/0008_create_followstats_remap_fks.py
  • baseapp_follows/models.py
  • baseapp_follows/plugin.py
  • baseapp_follows/services.py
  • baseapp_follows/tests/conftest.py
  • baseapp_follows/tests/test_follow_count.py
  • baseapp_follows/tests/test_graphql_queries_object_follows.py
  • baseapp_follows/tests/test_migration_helper_convert_follow_profile_fks_into_document_id.py
  • baseapp_follows/tests/test_migration_helper_seed_followable_metadata_from_follows.py
  • baseapp_mentions/README.md
  • baseapp_mentions/admin.py
  • baseapp_mentions/apps.py
  • baseapp_mentions/graphql/interfaces.py
  • baseapp_mentions/graphql/shared_interfaces.py
  • baseapp_mentions/migrations/0001_initial.py
  • baseapp_mentions/models.py
  • baseapp_mentions/plugin.py
  • baseapp_mentions/services.py
  • baseapp_mentions/tests/test_graphql.py
  • baseapp_mentions/tests/test_graphql_queries_object_mentions.py
  • baseapp_mentions/tests/test_service_resolve_mentioned_profiles.py
  • baseapp_mentions/tests/test_service_update_mentions.py
  • baseapp_message_templates/README.md
  • baseapp_message_templates/apps.py
  • baseapp_message_templates/plugin.py
  • baseapp_notifications/README.md
  • baseapp_notifications/__init__.py
  • baseapp_notifications/apps.py
  • baseapp_notifications/base.py
  • baseapp_notifications/graphql/interfaces.py
  • baseapp_notifications/migrations/0001_initial.py
  • baseapp_notifications/migrations/0002_notificationsetting.py
  • baseapp_notifications/migrations/0003_rename_notification_recipient_unread_baseapp_not_recipie_8567c3_idx.py
  • baseapp_notifications/migrations/0004_notification_insert_document_id_and_more.py
  • baseapp_notifications/models.py
  • baseapp_notifications/plugin.py
  • baseapp_notifications/services.py
  • baseapp_notifications/tasks.py
  • baseapp_notifications/tests/conftest.py
  • baseapp_notifications/tests/fixtures.py
  • baseapp_notifications/tests/test_utils.py
  • baseapp_notifications/utils.py
  • baseapp_organizations/README.md
  • baseapp_organizations/admin.py
  • baseapp_organizations/apps.py
  • baseapp_organizations/graphql/mutations.py
  • baseapp_organizations/migrations/0002_organization_name.py
  • baseapp_organizations/migrations/0003_alter_organization_profile.py
  • baseapp_organizations/models.py
  • baseapp_organizations/plugin.py
  • baseapp_organizations/services.py
  • baseapp_organizations/tests/test_graphql_mutations_create.py
  • baseapp_pages/README.md
  • baseapp_pages/admin.py
  • baseapp_pages/apps.py
  • baseapp_pages/graphql/__init__.py
  • baseapp_pages/graphql/interfaces.py
  • baseapp_pages/graphql/object_types.py
  • baseapp_pages/meta.py
  • baseapp_pages/migrations/0003_remove_page_snapshot_insert_and_more.py
  • baseapp_pages/migrations/0004_alter_page_comments_count_and_more.py
  • baseapp_pages/migrations/0010_delete_page.py
  • baseapp_pages/models.py
  • baseapp_pages/plugin.py
  • baseapp_pages/services.py
  • baseapp_pages/tests/test_pages_services.py
  • baseapp_payments/README.md
  • baseapp_payments/apps.py
  • baseapp_payments/migrations/0001_initial.py
  • baseapp_payments/migrations/0002_create_template_emails.py
  • baseapp_payments/migrations/0005_customer_created_customer_modified_and_more.py
  • baseapp_payments/models.py
  • baseapp_payments/plugin.py
  • baseapp_payments/utils.py
  • baseapp_payments/views.py
  • baseapp_pdf/README.md
  • baseapp_pdf/apps.py
  • baseapp_pdf/plugin.py
  • baseapp_profiles/README.md

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch epic/plugin-arch

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@Hercilio1 Hercilio1 marked this pull request as ready for review June 8, 2026 19:42
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants