1
1
import 'package:dart_frog/dart_frog.dart' ;
2
- import 'package:ht_api/src/config/dependency_container .dart' ;
2
+ import 'package:ht_api/src/config/database_connection .dart' ;
3
3
import 'package:ht_api/src/middlewares/error_handler.dart' ;
4
4
import 'package:ht_api/src/rbac/permission_service.dart' ;
5
5
import 'package:ht_api/src/services/auth_service.dart' ;
6
6
import 'package:ht_api/src/services/auth_token_service.dart' ;
7
7
import 'package:ht_api/src/services/dashboard_summary_service.dart' ;
8
+ import 'package:ht_api/src/services/database_seeding_service.dart' ;
9
+ import 'package:ht_api/src/services/default_user_preference_limit_service.dart' ;
10
+ import 'package:ht_api/src/services/jwt_auth_token_service.dart' ;
8
11
import 'package:ht_api/src/services/token_blacklist_service.dart' ;
9
12
import 'package:ht_api/src/services/user_preference_limit_service.dart' ;
10
13
import 'package:ht_api/src/services/verification_code_storage_service.dart' ;
14
+ import 'package:ht_data_client/ht_data_client.dart' ;
15
+ import 'package:ht_data_postgres/ht_data_postgres.dart' ;
11
16
import 'package:ht_data_repository/ht_data_repository.dart' ;
17
+ import 'package:ht_email_inmemory/ht_email_inmemory.dart' ;
12
18
import 'package:ht_email_repository/ht_email_repository.dart' ;
13
19
import 'package:ht_shared/ht_shared.dart' ;
14
20
import 'package:logging/logging.dart' ;
21
+ import 'package:postgres/postgres.dart' ;
15
22
import 'package:uuid/uuid.dart' ;
16
23
17
24
// --- Request ID Wrapper ---
@@ -59,6 +66,24 @@ class RequestId {
59
66
// --- Middleware Definition ---
60
67
final _log = Logger ('RootMiddleware' );
61
68
69
+ /// Creates a data repository for a given type [T] .
70
+ HtDataRepository <T > _createRepository <T >({
71
+ required Connection connection,
72
+ required String tableName,
73
+ required FromJson <T > fromJson,
74
+ required ToJson <T > toJson,
75
+ }) {
76
+ return HtDataRepository <T >(
77
+ dataClient: HtDataPostgresClient <T >(
78
+ connection: connection,
79
+ tableName: tableName,
80
+ fromJson: fromJson,
81
+ toJson: toJson,
82
+ log: _log,
83
+ ),
84
+ );
85
+ }
86
+
62
87
Handler middleware (Handler handler) {
63
88
// This is the root middleware for the entire API. It's responsible for
64
89
// providing all shared dependencies to the request context.
@@ -81,85 +106,133 @@ Handler middleware(Handler handler) {
81
106
return innerHandler (context.provide <RequestId >(() => requestId));
82
107
};
83
108
})
84
- // --- Dependency Providers ---
85
- // These providers inject all repositories and services into the context.
86
- // They read from the `DependencyContainer` which was populated at startup.
87
- // This is the first set of middleware to run for any request.
88
- .use (provider <Uuid >((_) => const Uuid ()))
89
- .use (
90
- provider <HtDataRepository <Headline >>(
91
- (_) => DependencyContainer .instance.headlineRepository,
92
- ),
93
- )
94
- .use (
95
- provider <HtDataRepository <Category >>(
96
- (_) => DependencyContainer .instance.categoryRepository,
97
- ),
98
- )
99
- .use (
100
- provider <HtDataRepository <Source >>(
101
- (_) => DependencyContainer .instance.sourceRepository,
102
- ),
103
- )
104
- .use (
105
- provider <HtDataRepository <Country >>(
106
- (_) => DependencyContainer .instance.countryRepository,
107
- ),
108
- )
109
- .use (
110
- provider <HtDataRepository <User >>(
111
- (_) => DependencyContainer .instance.userRepository,
112
- ),
113
- )
114
- .use (
115
- provider <HtDataRepository <UserAppSettings >>(
116
- (_) => DependencyContainer .instance.userAppSettingsRepository,
117
- ),
118
- )
119
- .use (
120
- provider <HtDataRepository <UserContentPreferences >>(
121
- (_) => DependencyContainer .instance.userContentPreferencesRepository,
122
- ),
123
- )
124
- .use (
125
- provider <HtDataRepository <AppConfig >>(
126
- (_) => DependencyContainer .instance.appConfigRepository,
127
- ),
128
- )
129
- .use (
130
- provider <HtEmailRepository >(
131
- (_) => DependencyContainer .instance.emailRepository,
132
- ),
133
- )
134
- .use (
135
- provider <TokenBlacklistService >(
136
- (_) => DependencyContainer .instance.tokenBlacklistService,
137
- ),
138
- )
139
- .use (
140
- provider <AuthTokenService >(
141
- (_) => DependencyContainer .instance.authTokenService,
142
- ),
143
- )
144
- .use (
145
- provider <VerificationCodeStorageService >(
146
- (_) => DependencyContainer .instance.verificationCodeStorageService,
147
- ),
148
- )
149
- .use (provider <AuthService >((_) => DependencyContainer .instance.authService))
150
- .use (
151
- provider <DashboardSummaryService >(
152
- (_) => DependencyContainer .instance.dashboardSummaryService,
153
- ),
154
- )
155
- .use (
156
- provider <PermissionService >(
157
- (_) => DependencyContainer .instance.permissionService,
158
- ),
159
- )
160
- .use (
161
- provider <UserPreferenceLimitService >(
162
- (_) => DependencyContainer .instance.userPreferenceLimitService,
163
- ),
109
+ // --- Dependency Provider ---
110
+ // This is the outermost middleware. It runs once per request, before any
111
+ // other middleware. It's responsible for initializing and providing all
112
+ // dependencies for the request.
113
+ .use ((handler) {
114
+ return (context) async {
115
+ // 1. Ensure the database connection is initialized.
116
+ await DatabaseConnectionManager .instance.init ();
117
+ final connection = await DatabaseConnectionManager .instance.connection;
118
+
119
+ // 2. Run database seeding (idempotent).
120
+ final seedingService = DatabaseSeedingService (
121
+ connection: connection,
122
+ log: _log,
123
+ );
124
+ await seedingService.createTables ();
125
+ await seedingService.seedGlobalFixtureData ();
126
+ await seedingService.seedInitialAdminAndConfig ();
127
+
128
+ // 3. Initialize Repositories.
129
+ final headlineRepository = _createRepository <Headline >(
130
+ connection: connection,
131
+ tableName: 'headlines' ,
132
+ fromJson: Headline .fromJson,
133
+ toJson: (h) => h.toJson (),
134
+ );
135
+ final categoryRepository = _createRepository <Category >(
136
+ connection: connection,
137
+ tableName: 'categories' ,
138
+ fromJson: Category .fromJson,
139
+ toJson: (c) => c.toJson (),
140
+ );
141
+ final sourceRepository = _createRepository <Source >(
142
+ connection: connection,
143
+ tableName: 'sources' ,
144
+ fromJson: Source .fromJson,
145
+ toJson: (s) => s.toJson (),
146
+ );
147
+ final countryRepository = _createRepository <Country >(
148
+ connection: connection,
149
+ tableName: 'countries' ,
150
+ fromJson: Country .fromJson,
151
+ toJson: (c) => c.toJson (),
152
+ );
153
+ final userRepository = _createRepository <User >(
154
+ connection: connection,
155
+ tableName: 'users' ,
156
+ fromJson: User .fromJson,
157
+ toJson: (u) => u.toJson (),
158
+ );
159
+ final userAppSettingsRepository = _createRepository <UserAppSettings >(
160
+ connection: connection,
161
+ tableName: 'user_app_settings' ,
162
+ fromJson: UserAppSettings .fromJson,
163
+ toJson: (s) => s.toJson (),
164
164
);
165
+ final userContentPreferencesRepository =
166
+ _createRepository <UserContentPreferences >(
167
+ connection: connection,
168
+ tableName: 'user_content_preferences' ,
169
+ fromJson: UserContentPreferences .fromJson,
170
+ toJson: (p) => p.toJson (),
171
+ );
172
+ final appConfigRepository = _createRepository <AppConfig >(
173
+ connection: connection,
174
+ tableName: 'app_config' ,
175
+ fromJson: AppConfig .fromJson,
176
+ toJson: (c) => c.toJson (),
177
+ );
178
+
179
+ // 4. Initialize Services.
180
+ const emailRepository = HtEmailRepository (
181
+ emailClient: HtEmailInMemoryClient (),
182
+ );
183
+ final tokenBlacklistService = InMemoryTokenBlacklistService ();
184
+ final AuthTokenService authTokenService = JwtAuthTokenService (
185
+ userRepository: userRepository,
186
+ blacklistService: tokenBlacklistService,
187
+ uuidGenerator: const Uuid (),
188
+ );
189
+ final verificationCodeStorageService =
190
+ InMemoryVerificationCodeStorageService ();
191
+ final authService = AuthService (
192
+ userRepository: userRepository,
193
+ authTokenService: authTokenService,
194
+ verificationCodeStorageService: verificationCodeStorageService,
195
+ emailRepository: emailRepository,
196
+ userAppSettingsRepository: userAppSettingsRepository,
197
+ userContentPreferencesRepository: userContentPreferencesRepository,
198
+ uuidGenerator: const Uuid (),
199
+ );
200
+ final dashboardSummaryService = DashboardSummaryService (
201
+ headlineRepository: headlineRepository,
202
+ categoryRepository: categoryRepository,
203
+ sourceRepository: sourceRepository,
204
+ );
205
+ const permissionService = PermissionService ();
206
+ final UserPreferenceLimitService userPreferenceLimitService =
207
+ DefaultUserPreferenceLimitService (
208
+ appConfigRepository: appConfigRepository,
209
+ );
210
+
211
+ // 5. Provide all dependencies to the inner handler.
212
+ return handler
213
+ .use (provider <Uuid >((_) => const Uuid ()))
214
+ .use (provider <HtDataRepository <Headline >>((_) => headlineRepository))
215
+ .use (provider <HtDataRepository <Category >>((_) => categoryRepository))
216
+ .use (provider <HtDataRepository <Source >>((_) => sourceRepository))
217
+ .use (provider <HtDataRepository <Country >>((_) => countryRepository))
218
+ .use (provider <HtDataRepository <User >>((_) => userRepository))
219
+ .use (provider <HtDataRepository <UserAppSettings >>(
220
+ (_) => userAppSettingsRepository))
221
+ .use (provider <HtDataRepository <UserContentPreferences >>(
222
+ (_) => userContentPreferencesRepository))
223
+ .use (provider <HtDataRepository <AppConfig >>((_) => appConfigRepository))
224
+ .use (provider <HtEmailRepository >((_) => emailRepository))
225
+ .use (provider <TokenBlacklistService >((_) => tokenBlacklistService))
226
+ .use (provider <AuthTokenService >((_) => authTokenService))
227
+ .use (provider <VerificationCodeStorageService >(
228
+ (_) => verificationCodeStorageService))
229
+ .use (provider <AuthService >((_) => authService))
230
+ .use (provider <DashboardSummaryService >((_) => dashboardSummaryService))
231
+ .use (provider <PermissionService >((_) => permissionService))
232
+ .use (provider <UserPreferenceLimitService >(
233
+ (_) => userPreferenceLimitService))
234
+ .call (context);
235
+ };
236
+ });
237
+ }
165
238
}
0 commit comments