Feature Implementation Plan: disable-coffee-bean¶
📋 Todo Checklist¶
- [ ] Add
DISABLEDstatus toCoffeeBeanStatusenum. - [ ] Update
CoffeeBeanRepositoryto exclude disabled beans from API queries. - [ ] Update
CrawlUrlRepositoryto exclude URLs of disabled beans from crawling. - [ ] Update the Admin CRUD controllers so that beans can be disabled/enabled from the UI.
- [ ] Create a Symfony console command to disable a bean.
- [ ] Write tests for the new functionality.
- [ ] Final Review and Testing.
🔍 Analysis & Investigation¶
Codebase Structure¶
- Entity:
src/Entity/CoffeeBean.phpis the core entity. It already has astatusfield linked to theCoffeeBeanStatusenum. - Enum:
src/Enum/CoffeeBeanStatus.phpdefines the possible states for aCoffeeBean. This is the ideal place to add aDISABLEDstate. - Repository:
src/Repository/CoffeeBeanRepository.phpis responsible for all database queries related toCoffeeBeanentities. Key methods likefindByRequestandfindDtoByIdmust be updated to filter out disabled beans. - Crawler Logic:
src/Repository/CrawlUrlRepository.phpcontains the methodfindUrlsToCrawl, which is the choke point for selecting which URLs get scheduled for crawling. This is the best place to prevent re-crawling. - Admin Interface: There is no dedicated admin UI. A Symfony console command is the most appropriate and straightforward way to provide administrators with the ability to disable a bean.
Current Architecture¶
The system uses a standard Symfony setup with Doctrine ORM. API responses are driven by repositories that fetch entities
and map them to DTOs. A Symfony Messenger-based queue system handles crawling, with CrawlerScheduler dispatching
messages and CrawlUrlRepository providing the URLs to be crawled.
The most effective and non-destructive way to "disable" a bean is to extend the existing status system. Adding a
DISABLED status to the CoffeeBeanStatus enum is a clean, logical extension of the current architecture. This
approach preserves all data for historical purposes while effectively hiding the disabled entity from public view and
preventing it from being re-processed.
Dependencies & Integration Points¶
- Doctrine ORM: The repositories will need updated DQL queries to filter by the new status.
- Symfony Console: To create the admin command for disabling beans.
- API Endpoints: All public-facing API endpoints that return
CoffeeBeandata will be implicitly affected by the repository changes.
Considerations & Challenges¶
- Comprehensive Filtering: It is critical to identify all public-facing query methods in
CoffeeBeanRepositoryand ensure they are updated to exclude disabled beans. Missing one could lead to data leakage. - Crawler Exclusion: The logic to prevent re-crawling must be robust. The
CrawlUrlRepositoryshould be modified to join theCoffeeBeanentity and check its status. - Idempotency: The disable command should be idempotent. Running it multiple times on the same bean should have no adverse effects.
📝 Implementation Plan¶
Prerequisites¶
- None. This plan builds on existing application structure.
Step-by-Step Implementation¶
-
Step 1: Extend
CoffeeBeanStatusEnum- File to modify:
src/Enum/CoffeeBeanStatus.php - Changes needed: Add a new
DISABLEDcase to the enum.
- File to modify:
-
Step 2: Update
CoffeeBeanRepositoryto Exclude Disabled Beans- File to modify:
src/Repository/CoffeeBeanRepository.php - Changes needed: Add a condition to all public query-building methods to filter out beans with the
DISABLEDstatus.- In
executeCoffeeBeanQuery(which powersfindByRequest), add the followingandWhereclause to both the$idsQband$countQbquery builders: - In
findDtoById, add the sameandWhereclause to the query builder to ensure a disabled bean cannot be fetched directly via the API. - In
findSimilarityCandidates, add the sameandWhereclause.
- In
- File to modify:
-
Step 3: Update
CrawlUrlRepositoryto Exclude Disabled URLs- File to modify:
src/Repository/CrawlUrlRepository.php - Changes needed: Modify the
findUrlsToCrawlmethod to join theCoffeeBeanentity and exclude URLs where the associated bean is disabled.// Inside findUrlsToCrawl method $qb = $this->createQueryBuilder('cu') ->leftJoin('cu.coffeeBean', 'cb') // Add this join ->where('cu.roasterCrawlConfig = :config') // Add this condition ->andWhere('cb.status IS NULL OR cb.status != :disabledStatus') ->setParameter('config', $config) ->setParameter('disabledStatus', CoffeeBeanStatus::DISABLED);
- File to modify:
-
Step 4: Create Admin Command to Disable a
CoffeeBean- File to create:
src/Command/DisableCoffeeBeanCommand.php - Changes needed:
- Create a new Symfony command named
app:coffee-bean:disable. - The command should accept one argument: the UUID of the
CoffeeBeanto disable. - Inject the
CoffeeBeanRepositoryandEntityManagerInterface. - In the
executemethod:- Find the
CoffeeBeanby its ID. - If not found, output an error.
- Set the bean's status:
$coffeeBean->setStatus(CoffeeBeanStatus::DISABLED); - Persist the change:
$this->entityManager->flush(); - Output a success message.
- Find the
- Create a new Symfony command named
- File to create:
Testing Strategy¶
- Unit/Integration Tests:
CoffeeBeanRepositoryTest:- Create a disabled
CoffeeBeanin the test database. - Assert that
findByRequestandfindDtoByIddo not return the disabled bean.
- Create a disabled
CrawlUrlRepositoryTest:- Create a
CrawlUrllinked to a disabledCoffeeBean. - Assert that
findUrlsToCrawldoes not return this URL.
- Create a
DisableCoffeeBeanCommandTest:- Write a command test that executes
app:coffee-bean:disable. - Assert that the command runs successfully and that the
CoffeeBean's status is updated toDISABLEDin the database.
- Write a command test that executes
- Manual Testing:
- Run the
app:coffee-bean:disablecommand on a knownCoffeeBeanID. - Verify via the API that the disabled bean no longer appears in lists or when queried by ID.
- Trigger the crawler scheduler and verify in the logs that the URL associated with the disabled bean is not scheduled for crawling.
- Run the
🎯 Success Criteria¶
- An administrator can successfully disable a
CoffeeBeanusing the UI. - Disabled
CoffeeBeanentities are no longer returned by any public-facing API endpoints. - The
CrawlUrlassociated with a disabledCoffeeBeanis no longer included in scheduled crawls. - No automation changes the data for disabled beans.
- All data related to the disabled bean is preserved in the database.
- The new functionality is covered by automated tests.