Skip to content

refactor: restructure server to DDD bounded contexts with FCIS#9

Merged
phibkro merged 13 commits into
mainfrom
worktree-ddd-restructure
Mar 20, 2026
Merged

refactor: restructure server to DDD bounded contexts with FCIS#9
phibkro merged 13 commits into
mainfrom
worktree-ddd-restructure

Conversation

@phibkro

@phibkro phibkro commented Mar 20, 2026

Copy link
Copy Markdown
Member

Summary

  • Restructure apps/server/src/App/ from flat layer-by-layer organization into 8 colocated bounded contexts with Functional Core, Imperative Shell (FCIS) layering
  • 546 PHP files reorganized across Admission, Interview, Organization, Survey, Identity, Scheduling, Operations, Content + Shared Kernel + Support
  • All 1011 tests pass at every commit (atomic migrations per context)
  • Zero behavioral changes — purely structural refactoring

Bounded Contexts

Context Entities Files Responsibility
Admission Application, AdmissionPeriod, InfoMeeting, ... 66 Application lifecycle
Interview Interview, InterviewSchema, InterviewScore, ... 65 Scheduling, conducting, scoring
Organization Department, Team, FieldOfStudy, UserGroup, ... 82 Structural hierarchy
Survey Survey, SurveyQuestion, SurveyTaken, ... 51 Questionnaire lifecycle
Identity User, Role, PasswordReset, AccessRule, ... 68 Auth, roles, access control
Scheduling School, SchoolCapacity 25 Assistant-to-school assignment
Operations Receipt, AssistantHistory, Signature, ... 39 Administrative records
Content Article, Sponsor, Feedback, SocialEvent, ... 52 CMS, static pages
Shared Semester, interfaces 14 Cross-context contracts
Support Mailer, SMS, Google, utilities 43 Infrastructure

Layer Structure per Context

{Context}/
  Domain/Rules/          # Pure PHP (zero framework deps)
  Domain/ValueObjects/
  Domain/Events/
  Infrastructure/Entity/ # Doctrine entities
  Infrastructure/Repository/
  Infrastructure/Subscriber/
  Api/Resource/          # API Platform DTOs
  Api/State/             # Providers + Processors
  Controller/            # Legacy Twig (deprecated)
  Form/                  # Legacy forms (deprecated)

Key Changes

  • All targetEntity short strings converted to ::class syntax
  • Symfony config updated: per-context service autodiscovery, Doctrine mappings, API Platform paths
  • DQL inline FQCNs updated in repository classes
  • Route loading entries added per context
  • Security config updated for UserChecker namespace

Test plan

  • All 1011 tests pass at every commit
  • Container lint passes (lint:container --env=test)
  • Unit tests (183), Controller tests (102), Availability tests (182), API tests (544)
  • Manual smoke test of staging environment

🤖 Generated with Claude Code

phibkro and others added 13 commits March 20, 2026 14:32
Create empty directory trees for 8 bounded contexts (Admission, Interview,
Organization, Survey, Identity, Scheduling, Operations, Content) plus
Shared and Support under src/App/. Update Doctrine, API Platform, and
services.yaml with per-context entity mappings, resource paths, and
autodiscovery blocks. No PHP files moved yet.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Move Semester, interfaces (DepartmentSemester, Period, Team, TeamMembership),
SemesterRepository, SemesterUtil, and Semester API/State/Controller/Form.
Convert all targetEntity short strings to ::class syntax across all entities.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Move 43 files (Mailer, SMS, Google, Slack, FileUploader, LogService,
GeoLocation, BetaRedirecter, FilterService, Sorter, Utils, EventSubscribers,
BaseController, FileBrowserController, GitHubController, DashboardResource,
Statistics, Twig extensions, Form types, DataFixtures) into the App\Support
namespace hierarchy. Update all use statements across ~170 files including
55 controllers extending BaseController. Update services.yaml with new
FQCNs for service definitions, bindings, and autodiscovery blocks.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Move 52 files (entities, repositories, API resources, state processors/providers,
controllers, forms, Twig extensions, events, subscribers) from flat App\ namespace
into App\Content\ bounded context structure.

Key changes:
- Entities/repos → App\Content\Infrastructure\Entity/ and Repository/
- API resources/state → App\Content\Api\Resource/ and State/
- Controllers → App\Content\Controller/
- Forms → App\Content\Form/
- Twig extensions → App\Content\Twig/
- ContentModeManager → App\Content\Infrastructure\
- SupportTicketCreatedEvent → App\Content\Domain\Events\
- SupportTicketSubscriber → App\Content\Infrastructure\Subscriber\
- Added route loading for Content and Support controllers in routes.yaml
- Added cross-context use statements for Department, User, Role, Semester
- Removed unused $env binding from Content subscriber config

All 1011 tests pass (183 unit + 102 controller + 182 availability + 544 API).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Move 41 files (entities, repositories, services, events, subscribers,
API resources, state processors/providers, controllers, forms) from
scattered App\ namespaces into the App\Operations\ bounded context.

Add cross-context use statements for entities that previously relied on
same-namespace resolution (User, Department, School, Semester).
Exclude Domain/Rules/ from service autodiscovery (ReceiptStatistics is
a pure value object, not a service).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Move 25 files: School/SchoolCapacity entities, repositories, domain rules
(Assistant/School), SbsData service, API resources/state providers/processors,
controllers, and form types into the App\Scheduling namespace hierarchy.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Move 76 files from flat App\* namespaces to structured Admission context:
- Entities (5) -> Admission/Infrastructure/Entity/
- Repositories (5) -> Admission/Infrastructure/Repository/
- Services (6) -> Admission/Infrastructure/
- API Resources (12) -> Admission/Api/Resource/
- State Providers/Processors (22) -> Admission/Api/State/
- Controllers (7) -> Admission/Controller/
- Forms (11) -> Admission/Form/
- Events, Subscribers, Validators, Commands -> respective subdirs

All 1011 tests pass (2995 assertions).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Move 65 files across entities, repository, services, events, subscriber,
value objects, validators, commands, API resources, state processors/providers,
controllers, and forms into the App\Interview namespace following the DDD
directory structure (Api/, Domain/, Infrastructure/, Controller/, Form/).

Key changes:
- Entities to Interview/Infrastructure/Entity/
- API resources to Interview/Api/Resource/, state to Interview/Api/State/
- Events to Interview/Domain/Events/, InterviewStatusType to Domain/ValueObjects/
- Services (InterviewManager, InterviewCounter, InterviewNotificationManager) to Infrastructure/
- Update all cross-context references (User entity, Application, fixtures, tests)
- Update DQL inline FQCNs in InterviewRepository
- Add route entry for Interview/Controller/
- Exclude Infrastructure/Entity/ from service autodiscovery (InterviewDistribution has non-service constructor)
- Remove unused $env binding from Interview subscriber service definition
- Remove unused SmsSenderInterface binding from App\EventSubscriber\ (InterviewSubscriber was the only consumer)

All 1011 tests pass (2995 assertions).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…mespace

Move 82 files (entities, repositories, services, events, subscribers,
commands, API resources, state providers/processors, controllers, forms,
Twig extensions) from App\Entity/Service/Controller/etc to App\Organization.

Key fixes beyond namespace updates:
- Add explicit `use App\Entity\User` to 4 Organization entities that
  previously relied on same-namespace resolution
- Add `use App\Organization\Infrastructure\Entity\*` to User and AccessRule
  entities for moved cross-context references
- Update DQL inline FQCNs in DepartmentRepository
- Update Twig controller() FQCN in control_panel/index.html.twig
- Fix services.yaml: remove unused MailerInterface binding from
  App\EventSubscriber, add it to Organization subscribers, remove unused
  $env binding, update Twig extension registration
- Add organization route entry in routes.yaml

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Move 68 files (User, Role, PasswordReset, AccessRule, UnhandledAccessRule
entities + repositories, services, events, subscribers, command, security,
validators, API resources/state, controllers, and forms) from App\Entity,
App\Service, App\Role, App\Security, App\Controller, etc. to the
App\Identity namespace.

Update 130+ files across all contexts with new use statements, fix DQL
inline FQCNs in UserRepository, update security.yaml entity class and
user_checker references, update services.yaml autodiscovery and bindings,
and add Identity controller route entry.

All 1011 tests pass with 2995 assertions (matches baseline).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Remove references to old flat directory structure now that all code
lives in bounded contexts:

- services.yaml: remove App\ catch-all, App\EventSubscriber\, App\Validator\Constraints\
- doctrine.yaml: remove App: mapping (src/App/Entity)
- api_platform.yaml: remove src/App/Entity and src/App/ApiResource paths
- routes.yaml: remove src/App/Controller/ route import
- phpunit.xml.dist: remove stale src/App/AssistantScheduling/Webapp exclude
- phpstan.neon: remove stale src/App/AutoMapper/ exclude
- Remove .gitkeep files from directories that now contain actual files
- Remove dead src/App/AssistantScheduling/Webapp and src/App/Google/.gitignore

All 1011 tests pass (2995 assertions).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- PasswordResetType: \App\Entity\PasswordReset → \App\Identity\Infrastructure\Entity\PasswordReset
- AccessControlService: instanceof \App\Entity\Role → \App\Identity\Infrastructure\Entity\Role
- User.php docblock: update FQCN comment

Note: Two DQL references to App\Entity\ApplicationStatistic in
ApplicationRepository and InterviewRepository are pre-existing dead code
(no such entity exists). Left as-is — not introduced by this restructure.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@phibkro phibkro merged commit 692f84d into main Mar 20, 2026
0 of 2 checks passed
@phibkro phibkro deleted the worktree-ddd-restructure branch March 20, 2026 19:46
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.

1 participant