Skip to content

Commit 6f7c55e

Browse files
authored
Merge pull request #11 from dotkernel/core-structure
added core structure page
2 parents c7f5dc2 + 598944c commit 6f7c55e

3 files changed

Lines changed: 160 additions & 0 deletions

File tree

docs/book/v1/core/introduction.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ A: At `src/Core`.
3636

3737
## See also
3838

39+
- [Structure of the Core Submodule](structure.md)
3940
- [Benefits of the Core Submodule](benefits.md)
4041
- [Creating a Core Submodule](creation.md)
4142
- [Using the Core Submodule](usage.md)

docs/book/v1/core/structure.md

Lines changed: 158 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,158 @@
1+
# Structure of the Core Submodule
2+
3+
## Summary
4+
5+
Maps what lives inside the Core submodule — its five modules and the kind of code each one holds — and shows where the boundary falls between Core and the applications that include it.
6+
7+
## Details
8+
9+
[Core](introduction.md) is not a single directory of loose classes.
10+
It is organized into five modules, each a PSR-4 namespace mapped under `src/Core/src/`, so the shared codebase is grouped by domain rather than by file type.
11+
12+
Every application that includes the submodule gets all five, and every application sees exactly the same definitions.
13+
14+
```text
15+
┌───────────┐ ┌───────────┐ ┌───────────┐
16+
│ API │ │ Admin │ │ Queue │
17+
│ handlers │ │ templates │ │ consumers │
18+
│ HAL, HTTP │ │ forms, UI │ │ workers │
19+
└─────┬─────┘ └─────┬─────┘ └─────┬─────┘
20+
│ │ │
21+
└───────────────┼───────────────┘
22+
│ each includes Core
23+
24+
┌─────────────────────┐
25+
│ Core │
26+
│ entities · repos │
27+
│ enums · DBAL types │
28+
└──────────┬──────────┘
29+
30+
┌─────────────────┐
31+
│ database │
32+
└─────────────────┘
33+
```
34+
35+
Note that every arrow points one way.
36+
The applications know about Core; Core knows nothing about any application.
37+
Core contains no handler, no template, no route and no middleware — which is what makes it safe to include everywhere.
38+
39+
### The five modules
40+
41+
| Module | Namespace | Holds |
42+
| --- | --- | --- |
43+
| App | `Core\App` | The base entity and its traits, the abstract repository, DBAL enum and UUID types, table-prefix and entity-listener wiring, data fixtures, shared services (`MailService`, `IpService`), the paginator helper and shared messages |
44+
| Admin | `Core\Admin` | The `Admin`, `AdminRole`, `AdminLogin` and `AdminIdentity` entities with their repositories, plus the admin role and status enums |
45+
| User | `Core\User` | The `User`, `UserDetail`, `UserAvatar`, `UserRole` and `UserResetPassword` entities with their repositories, the user status and role enums, and the avatar event listener |
46+
| Security | `Core\Security` | OAuth2 persistence — the access token, refresh token, auth code, client and scope entities, plus the repositories the authorization server requires |
47+
| Setting | `Core\Setting` | The `Setting` entity, its identifier enum and repository, for platform-wide configuration kept in the database |
48+
49+
`Core\App` is the one module that is not a domain in its own right.
50+
It holds the pieces the other four build on — the abstract entity every entity extends, the abstract repository every repository extends, and the Doctrine infrastructure that makes UUID identifiers and enum columns work.
51+
52+
### How the modules are registered
53+
54+
Each module ships its own [ConfigProvider](../config-provider/introduction.md), and every application registers all five in `config/config.php`:
55+
56+
```php
57+
// Dotkernel modules
58+
Core\Admin\ConfigProvider::class,
59+
Core\App\ConfigProvider::class,
60+
Core\Security\ConfigProvider::class,
61+
Core\Setting\ConfigProvider::class,
62+
Core\User\ConfigProvider::class,
63+
```
64+
65+
This is why including the submodule is enough to get the whole domain layer: the entities, repositories and DBAL types register themselves, exactly as they do in every other application on the platform.
66+
67+
The PSR-4 map in `composer.json` points at the submodule path, so it needs no change when a plain `src/Core` folder becomes a submodule mounted at the same location:
68+
69+
```json
70+
"autoload": {
71+
"psr-4": {
72+
"Core\\Admin\\": "src/Core/src/Admin/src/",
73+
"Core\\App\\": "src/Core/src/App/src/",
74+
"Core\\Security\\": "src/Core/src/Security/src/",
75+
"Core\\Setting\\": "src/Core/src/Setting/src/",
76+
"Core\\User\\": "src/Core/src/User/src/"
77+
}
78+
}
79+
```
80+
81+
### Where the boundary falls
82+
83+
The question that comes up on almost every feature is whether the new code belongs in Core or in the application.
84+
The dividing line is delivery: Core describes what the data *is*, the application describes how it is *delivered*.
85+
86+
```text
87+
application (API / Admin / Queue)
88+
┌──────────────────────────────────────────────────┐
89+
│ Handler / Consumer HTTP or message entry │
90+
│ InputFilter / Form validates this interface │
91+
│ Service this application's flow │
92+
└────────────────────────┬─────────────────────────┘
93+
│ depends on
94+
Core ▼
95+
┌──────────────────────────────────────────────────┐
96+
│ Service (shared) MailService, IpService │
97+
│ Repository querying and persistence │
98+
│ Entity + Enum the model itself │
99+
└──────────────────────────────────────────────────┘
100+
```
101+
102+
Use this as a checklist:
103+
104+
- **Belongs in Core** — entities and the state changes intrinsic to them, repositories, enums, DBAL types, data fixtures, Doctrine listeners and factories, and any service that behaves identically no matter which application calls it.
105+
- **Belongs in the application** — handlers and consumers, middleware, routes, input filters and forms, templates, HAL resources, OpenAPI annotations, and the services that express that application's own workflows.
106+
- **Never in Core** — anything that imports a PSR-7 message, a template renderer, a session, a HAL type or a Messenger envelope.
107+
If Core would need to know how the request arrived, the code is on the wrong side of the line.
108+
109+
The service layer is the case worth understanding properly, because it sits on both sides: shared services such as `MailService` live in Core, while application-specific ones do not.
110+
API and Admin each have their own `UserService`, both operating on the same `Core\User\Entity\User` through the same `Core\User\Repository\UserRepository`.
111+
That is deliberate rather than duplication — the two applications present the same operation very differently while the model underneath stays single.
112+
[The Service Layer](../services.md) covers the reasoning in full.
113+
114+
### Core owns the schema
115+
116+
Because the entities live in Core, Doctrine generates migrations from Core's mappings.
117+
That makes the schema a shared asset, and it needs a single owner.
118+
119+
Decide once which application is responsible for generating and running migrations — normally the API — and keep it there.
120+
Two applications generating migrations independently against the same mappings will produce conflicting histories, and reconciling them after the fact is considerably harder than agreeing the convention up front.
121+
122+
## FAQ
123+
124+
**Q: How many modules does Core contain?**
125+
126+
A: Five — `Core\App`, `Core\Admin`, `Core\User`, `Core\Security` and `Core\Setting`, each mapped under `src/Core/src/`.
127+
128+
**Q: What is `Core\App` for, if it isn't a domain?**
129+
130+
A: It holds the foundations the other modules build on: the abstract entity and repository, the DBAL enum and UUID types, the Doctrine wiring, data fixtures and the shared services.
131+
132+
**Q: Do I have to register each Core module separately?**
133+
134+
A: Yes. All five ConfigProviders are listed in each application's `config/config.php`, which is what makes the entities and DBAL types available.
135+
136+
**Q: How do I decide whether new code goes in Core or in my application?**
137+
138+
A: Ask whether it describes the data or the delivery. Entities, repositories, enums and DBAL types describe the data and belong in Core; handlers, templates, input filters and application-specific services describe delivery and stay in the application.
139+
140+
**Q: Why do API and Admin each have their own `UserService` if Core is meant to prevent duplication?**
141+
142+
A: Because they are different workflows over the same model. Both use `Core\User\Entity\User` and `Core\User\Repository\UserRepository`, so the data has one definition even though the two applications present it differently.
143+
144+
**Q: Which application should run the Doctrine migrations?**
145+
146+
A: One of them, chosen deliberately — usually the API. Because Core owns the entities, migrations generated independently by two applications will conflict.
147+
148+
**Q: Does the `composer.json` autoload section change when Core becomes a submodule?**
149+
150+
A: No. The submodule is mounted at the same `src/Core` path, so the PSR-4 map continues to resolve. Run `composer dump-autoload` after the switch.
151+
152+
## See also
153+
154+
- [Introduction](introduction.md)
155+
- [Creating a Core Submodule](creation.md)
156+
- [Using the Core Submodule](usage.md)
157+
- [The Service Layer](../services.md)
158+
- [Architecture Overview](../architecture.md)

mkdocs.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ nav:
2323
- "Usage": v1/queue/usage.md
2424
- Core:
2525
- "Introduction": v1/core/introduction.md
26+
- "Structure": v1/core/structure.md
2627
- "Creation": v1/core/creation.md
2728
- "Usage": v1/core/usage.md
2829
- "Benefits": v1/core/benefits.md

0 commit comments

Comments
 (0)