profileShare

rasmusjy / splitapp-backend-clean-onion

Read-only snapshot

No repository description.

main default branch 429 files Expires Sep 13, 2026, 9:06 AM
arhitektuur.md 11,794 bytes
1 # SplitApp Onion Arhitektuur — joonis ja võrdlus TalTech-i loenguga
2
3 ## 1. Sibula-joonis (ringid seestpoolt väljapoole)
4
5 ```
6 ┌─────────────────────────────────────────────────┐
7 │ WebApp (Presentation) │
8 │ MVC Controllers · API Controllers (v1) │
9 │ Areas/Admin · Areas/Identity · Views │
10 │ ViewModels · Program.cs (DI Composition Root) │
11 │ ┌───────────────────────────────────────────┐ │
12 │ │ App.BLL (Application Services) │ │
13 │ │ TripService · ExpenseService · │ │
14 │ │ SettlementService · AdminServices │ │
15 │ │ (kasutab IAppUnitOfWork liidese kaudu) │ │
16 │ │ ┌─────────────────────────────────────┐ │ │
17 │ │ │ App.Domain (Core / Süda) │ │ │
18 │ │ │ Entities: Trip, Expense, ... │ │ │
19 │ │ │ Enums, AppUser, AppRole │ │ │
20 │ │ │ Contracts: IAppUnitOfWork, │ │ │
21 │ │ │ ITripRepository, ... │ │ │
22 │ │ │ ┌───────────────────────────────┐ │ │ │
23 │ │ │ │ Base.Domain · Base.Contracts │ │ │ │
24 │ │ │ │ BaseEntity · IBaseRepository │ │ │ │
25 │ │ │ │ IUnitOfWork · LangStr │ │ │ │
26 │ │ │ └───────────────────────────────┘ │ │ │
27 │ │ └─────────────────────────────────────┘ │ │
28 │ └───────────────────────────────────────────┘ │
29 └─────────────────────────────────────────────────┘
30 ▲ ▲
31 │ │
32 │ ┌────────────────────────────────────┐ │
33 │ │ App.DAL.EF (Infrastructure) │ │
34 │ │ AppDbContext · AppUnitOfWork │─── implementeerib ───┘
35 │ │ Repositories · Migrations │ IAppUnitOfWork,
36 │ │ Seeding · ServiceCollectionExt │ ITripRepository
37 │ └────────────────────────────────────┘
38 │ ▲
39 │ │ plugitav (saab vahetada nt Dapperi vastu)
40
41 │ ┌────────────────────────────────────┐
42 └────│ App.DTO · App.Resources │
43 │ v1 DTOs · Mappers · .resx │
44 └────────────────────────────────────┘
45 ```
46
47 **Tähtis**: Infrastructure (DAL.EF) on **väljaspool** sibulat ja **osutab sissepoole** — just nagu TalTech-i loengus: *"Infrastructure -> Domain <- Application <- Web"*.
48
49 ---
50
51 ## 2. Sõltuvuste graaf (nooled = `ProjectReference`)
52
53 ```
54 Base.Domain ◄──── Base.Contracts
55 ▲ ▲
56 │ │
57 └──── App.Domain ─┤
58 ▲ │
59 ┌────────┼───────┴─────────┐
60 │ │ │
61 App.DTO App.BLL App.DAL.EF
62 ▲ ▲ ▲
63 │ │ │
64 └────────┴──── WebApp ─────┘
65 (Composition Root)
66 ```
67
68 **Tähelepanu**: `App.BLL` **ei viita** `App.DAL.EF`-le. BLL näeb ainult liideseid (`IAppUnitOfWork`), mis elavad Domain-is. See ongi Onion-i **"Dependency Inversion"** — täpselt nagu loengus kirjeldatud.
69
70 ---
71
72 ## 3. Võrdlus TalTech-i loengu nõuetega
73
74 | TalTech-i Clean/Onion nõue | SplitApp teostus | Vastab? |
75 |---|---|---|
76 | **"Who owns the interfaces"** → liidesed elavad Domain-is | `IAppUnitOfWork`, `ITripRepository` jt asuvad [App.Domain/Contracts/](SplitApp/App.Domain/Contracts/) | Jah |
77 | **Entities in Domain** (mitte DAL-is) | Kõik entiteedid [App.Domain/](SplitApp/App.Domain/), POCO, ilma EF-atribuutideta | Jah |
78 | **Infrastructure → Domain** (pöördsuund) | `App.DAL.EF` viitab `App.Domain`-le, mitte vastupidi | Jah |
79 | **Application ← Web, Application → Domain** | `WebApp → App.BLL → App.Domain` | Jah |
80 | **Infrastructure pluginatav** | BLL kasutab ainult liideseid; EF-i saaks teoreetiliselt Dapperi vastu vahetada | Jah |
81 | **Repository pattern** | [BaseRepository.cs](SplitApp/App.DAL.EF/Repositories/BaseRepository.cs) + spetsiifilised repod | Jah |
82 | **Unit of Work** (`SaveChangesAsync()` atomic commit) | [AppUnitOfWork.cs](SplitApp/App.DAL.EF/AppUnitOfWork.cs), lazy-load repod | Jah |
83 | **DTOs** ("dumb objects, no logic") | [App.DTO/v1/](SplitApp/App.DTO/v1/) + Mappers | Jah |
84 | **Mappers** entiteet↔DTO | Staatilised mapper-klassid [App.DTO/Mappers/](SplitApp/App.DTO/Mappers/) | Jah |
85 | **Dependency Injection** (konstruktori kaudu) | Teenused `AddScoped`-ina Program.cs-is, konstruktori-injection | Jah |
86 | **DI Composition Root** välimises ringis | Ainult [Program.cs](SplitApp/WebApp/Program.cs) teab konkreetseid implementatsioone | Jah |
87 | **SOLID → DIP**: kõrgemad kihid sõltuvad abstraktsioonidest | BLL sõltub `IAppUnitOfWork`-ist, mitte `AppUnitOfWork`-ist | Jah |
88 | **ViewModelid** (mitte entiteedid vaadetes) | [WebApp/Models/](SplitApp/WebApp/Models/) sisaldab ViewModel-eid | Jah |
89
90 ---
91
92 ## 4. Lisaväärtused üle loengu miinimumi
93
94 - **Versioneeritud API** (`[ApiVersion("1.0")]`, `api/v{version}/...`) — Asp.Versioning
95 - **JWT + Cookie hübriid-autentimine** — MVC ja REST samaaegselt
96 - **Admin Area** eraldi teenustega (12 AdminService-t)
97 - **Lokaliseerimine** läbi `LangStr` (Domain-is) + .resx ([App.Resources/](SplitApp/App.Resources/))
98 - **DataProtection** võtmed DB-s (`PersistKeysToDbContext`)
99 - **PostgreSQL + Docker** tootmiseks
100 - **Swagger** versioonidega ([ConfigureSwaggerOptions.cs](SplitApp/WebApp/ConfigureSwaggerOptions.cs))
101
102 ---
103
104 ## 5. Projektide detailne kirjeldus
105
106 ### Sisemine südamik
107
108 **[Base.Domain](SplitApp/Base.Domain/)** — `BaseEntity` (Guid Id, CreatedAt, UpdatedAt), `LangStr` (mitmekeelne string, implitsiitne cast `string ↔ LangStr`).
109
110 **[Base.Contracts](SplitApp/Base.Contracts/)** — generic abstraktsioonid:
111 - `IBaseRepository<T>` — CRUD (GetAllAsync, GetByIdAsync, Add, Update, RemoveAsync, ExistsAsync)
112 - `IUnitOfWork` — `SaveChangesAsync()`
113 - `IBaseEntity`
114
115 **[App.Domain](SplitApp/App.Domain/)** — puhas äridomeen, POCO entiteedid:
116 - **Trip, Expense, ExpenseSplit** — reisid ja kulud
117 - **TripParticipant, TripInvitation** — osavõtjad ja kutsed
118 - **SettlementPlan, SettlementPayment** — arveldused
119 - **TripPoll, TripPollOption, TripPollVote** — küsitlused
120 - **TripWishlistItem, TripWishlistVote** — sooviste nimekiri
121 - **BudgetCategory, Currency, SplitPreset** — abi-entiteedid
122 - **Identity/** — `AppUser`, `AppRole`
123 - **Contracts/** — `IAppUnitOfWork` + repo-liidesed (`ITripRepository` jne)
124 - **Enumid**: `ETripStatus`, `EParticipantRole`, `ESplitMethod`, `ESettlementStatus`, `EPaymentStatus`, `EInvitationStatus`, `EWishlistPriority`, `EWishlistCategory`
125
126 ### Infrastructure — DAL
127
128 **[App.DAL.EF](SplitApp/App.DAL.EF/)** — EF Core + PostgreSQL (Npgsql):
129 - **[AppDbContext.cs](SplitApp/App.DAL.EF/AppDbContext.cs)** — `IdentityDbContext<AppUser, AppRole, Guid>`, ~13 DbSet, UTC DateTime converter, unique indexid, `DeleteBehavior.Restrict`, `LangStr` JSON-seerimine.
130 - **[AppUnitOfWork.cs](SplitApp/App.DAL.EF/AppUnitOfWork.cs)** — lazy-load repod, generic `GetRepository<T>()`.
131 - **[Repositories/](SplitApp/App.DAL.EF/Repositories/)** — `BaseRepository<T>` + spetsiifilised (nt `TripRepository` `GetUserTripsAsync`, `GetByIdWithDetailsAsync`).
132 - **Migrations/** — EF Core migreeringud.
133 - **Seeding/** — `InitialData.cs`, `AppDataInit.cs`.
134 - **[ServiceCollectionExtensions.cs](SplitApp/App.DAL.EF/ServiceCollectionExtensions.cs)** — `AddDalServices()` DI registreerimine, `NoTrackingWithIdentityResolution`, SplitQuery käitumine.
135
136 ### Application Layer — BLL
137
138 **[App.BLL](SplitApp/App.BLL/)** — ärieteenused, sõltub **ainult** Domain-ist (mitte DAL-ist otse):
139 - **Services**: `TripService`, `ExpenseService`, `SettlementService`, `InvitationService`, `PollService`, `WishlistService`, `BudgetCategoryService`, `SplitPresetService`
140 - **Admin services** — 12 eraldi admin teenust (`BudgetCategoryAdminService`, `CurrencyAdminService` jne)
141 - **Helpers/** — `CurrencyConverter` jt
142
143 ### DTO kiht
144
145 **[App.DTO](SplitApp/App.DTO/)** — API- ja teenuste-tasemel andmeobjektid:
146 - **v1/** — versioneeritud API DTO-d (`TripDto`, `TripCreateDto`, `TripUpdateDto`, `ExpenseDto`, `SettlementPlanDto`, `BudgetCategoryDto`)
147 - **v1/Identity/** — `LoginInfo`, `RegisterInfo`, `JWTResponse`, `TokenRefreshInfo`
148 - **Mappers/** — staatilised mapper-klassid (`TripMapper` jt)
149
150 ### Presentation — WebApp
151
152 **MVC Controllers** [Controllers/](SplitApp/WebApp/Controllers/) — Razor Views:
153 `TripsController`, `ExpensesController`, `BudgetController`, `MembersController`, `PollsClientController`, `WishlistClientController`, `SettlementController`
154
155 **API Controllers** [ApiControllers/](SplitApp/WebApp/ApiControllers/) — REST API:
156 - `[ApiVersion("1.0")]` + `api/v{version:apiVersion}/[controller]`
157 - JWT Bearer autentimine
158
159 **Areas**:
160 - **Admin** — 13 admin-controllerit (Users, Currencies, Trips, Expenses, Polls, Wishlist, SettlementPlans jne)
161 - **Identity** — Razor Pages (Register jne)
162
163 **Models/** — **ViewModelid** (õppejõu nõue, mitte ViewBag/ViewData)
164
165 **[Program.cs](SplitApp/WebApp/Program.cs)** — DI konfig:
166 - Identity (`AppUser`, `AppRole`)
167 - JWT Bearer + Cookie autentimine (SlidingExpiration)
168 - `AddDataProtection().PersistKeysToDbContext<AppDbContext>()`
169 - Request localization
170 - Swagger + API versioning
171 - `InvariantDecimalModelBinderProvider` — kümnendkoha parser
172
173 ---
174
175 ## Kokkuvõte
176
177 **SplitApp on korrektne Clean/Onion Architecture** täpselt nii, nagu TalTech-i loeng "architecture1" kirjeldab:
178
179 > *"The entire difference between N-tier and Clean Architecture is who owns the interfaces."*
180
181 Meie projektis **liidesed kuuluvad Domain-ile** (`App.Domain.Contracts`), Infrastructure (`App.DAL.EF`) asub välimises ringis ja **osutab sissepoole**, mistõttu BLL-i äriloogika ei tea midagi EF Core-ist ega PostgreSQL-ist. See on just see "pööratud sõltuvus", mida Onion nõuab.
182