moicle 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (78) hide show
  1. package/README.md +201 -0
  2. package/assets/agents/developers/flutter-mobile-dev.md +69 -0
  3. package/assets/agents/developers/go-backend-dev.md +57 -0
  4. package/assets/agents/developers/laravel-backend-dev.md +123 -0
  5. package/assets/agents/developers/react-frontend-dev.md +69 -0
  6. package/assets/agents/developers/remix-fullstack-dev.md +69 -0
  7. package/assets/agents/utilities/api-designer.md +76 -0
  8. package/assets/agents/utilities/clean-architect.md +83 -0
  9. package/assets/agents/utilities/code-reviewer.md +76 -0
  10. package/assets/agents/utilities/db-designer.md +68 -0
  11. package/assets/agents/utilities/devops.md +71 -0
  12. package/assets/agents/utilities/docs-writer.md +75 -0
  13. package/assets/agents/utilities/perf-optimizer.md +87 -0
  14. package/assets/agents/utilities/refactor.md +173 -0
  15. package/assets/agents/utilities/security-audit.md +203 -0
  16. package/assets/agents/utilities/test-writer.md +139 -0
  17. package/assets/architecture/clean-architecture.md +143 -0
  18. package/assets/architecture/flutter-mobile.md +304 -0
  19. package/assets/architecture/go-backend.md +217 -0
  20. package/assets/architecture/laravel-backend.md +303 -0
  21. package/assets/architecture/monorepo.md +162 -0
  22. package/assets/architecture/react-frontend.md +268 -0
  23. package/assets/architecture/remix-fullstack.md +272 -0
  24. package/assets/commands/bootstrap.md +98 -0
  25. package/assets/commands/brainstorm.md +440 -0
  26. package/assets/skills/feature-workflow/SKILL.md +298 -0
  27. package/assets/skills/hotfix-workflow/SKILL.md +368 -0
  28. package/assets/templates/flutter/CLAUDE.md +454 -0
  29. package/assets/templates/go-gin/CLAUDE.md +244 -0
  30. package/assets/templates/monorepo/CLAUDE.md +362 -0
  31. package/assets/templates/react-vite/CLAUDE.md +304 -0
  32. package/assets/templates/remix/CLAUDE.md +304 -0
  33. package/bin/cli.js +76 -0
  34. package/dist/commands/disable.d.ts +3 -0
  35. package/dist/commands/disable.d.ts.map +1 -0
  36. package/dist/commands/disable.js +188 -0
  37. package/dist/commands/disable.js.map +1 -0
  38. package/dist/commands/enable.d.ts +3 -0
  39. package/dist/commands/enable.d.ts.map +1 -0
  40. package/dist/commands/enable.js +191 -0
  41. package/dist/commands/enable.js.map +1 -0
  42. package/dist/commands/install.d.ts +3 -0
  43. package/dist/commands/install.d.ts.map +1 -0
  44. package/dist/commands/install.js +290 -0
  45. package/dist/commands/install.js.map +1 -0
  46. package/dist/commands/list.d.ts +3 -0
  47. package/dist/commands/list.d.ts.map +1 -0
  48. package/dist/commands/list.js +75 -0
  49. package/dist/commands/list.js.map +1 -0
  50. package/dist/commands/postinstall.d.ts +2 -0
  51. package/dist/commands/postinstall.d.ts.map +1 -0
  52. package/dist/commands/postinstall.js +25 -0
  53. package/dist/commands/postinstall.js.map +1 -0
  54. package/dist/commands/status.d.ts +3 -0
  55. package/dist/commands/status.d.ts.map +1 -0
  56. package/dist/commands/status.js +118 -0
  57. package/dist/commands/status.js.map +1 -0
  58. package/dist/commands/uninstall.d.ts +3 -0
  59. package/dist/commands/uninstall.d.ts.map +1 -0
  60. package/dist/commands/uninstall.js +178 -0
  61. package/dist/commands/uninstall.js.map +1 -0
  62. package/dist/index.d.ts +11 -0
  63. package/dist/index.d.ts.map +1 -0
  64. package/dist/index.js +11 -0
  65. package/dist/index.js.map +1 -0
  66. package/dist/types.d.ts +47 -0
  67. package/dist/types.d.ts.map +1 -0
  68. package/dist/types.js +2 -0
  69. package/dist/types.js.map +1 -0
  70. package/dist/utils/config.d.ts +13 -0
  71. package/dist/utils/config.d.ts.map +1 -0
  72. package/dist/utils/config.js +95 -0
  73. package/dist/utils/config.js.map +1 -0
  74. package/dist/utils/symlink.d.ts +24 -0
  75. package/dist/utils/symlink.d.ts.map +1 -0
  76. package/dist/utils/symlink.js +313 -0
  77. package/dist/utils/symlink.js.map +1 -0
  78. package/package.json +55 -0
@@ -0,0 +1,454 @@
1
+ # CLAUDE.md - Flutter Mobile App Template
2
+
3
+ ## Project Overview
4
+
5
+ Cross-platform mobile application built with:
6
+ - **Flutter 3.x** - UI toolkit
7
+ - **Dart** - Programming language
8
+ - **Riverpod** - State management
9
+ - **GoRouter** - Navigation
10
+ - **Dio** - HTTP client
11
+ - **Freezed** - Code generation for immutable classes
12
+
13
+ ## Quick Start
14
+
15
+ ```bash
16
+ # Install dependencies
17
+ flutter pub get
18
+
19
+ # Generate code (freezed, json_serializable)
20
+ dart run build_runner build --delete-conflicting-outputs
21
+
22
+ # Run development
23
+ flutter run
24
+
25
+ # Run on specific device
26
+ flutter run -d chrome
27
+ flutter run -d ios
28
+ flutter run -d android
29
+
30
+ # Build release
31
+ flutter build apk
32
+ flutter build ios
33
+ flutter build web
34
+
35
+ # Run tests
36
+ flutter test
37
+ ```
38
+
39
+ ## Project Structure
40
+
41
+ ```
42
+ {project_name}/
43
+ ├── lib/
44
+ │ ├── core/ # Core utilities
45
+ │ │ ├── config/
46
+ │ │ │ └── app_config.dart
47
+ │ │ ├── constants/
48
+ │ │ │ └── api_constants.dart
49
+ │ │ ├── network/
50
+ │ │ │ ├── api_client.dart
51
+ │ │ │ └── api_exceptions.dart
52
+ │ │ ├── router/
53
+ │ │ │ └── app_router.dart
54
+ │ │ └── theme/
55
+ │ │ └── app_theme.dart
56
+ │ ├── features/ # Feature modules
57
+ │ │ └── {feature}/
58
+ │ │ ├── data/
59
+ │ │ │ ├── models/
60
+ │ │ │ ├── repositories/
61
+ │ │ │ └── datasources/
62
+ │ │ ├── domain/
63
+ │ │ │ └── entities/
64
+ │ │ ├── presentation/
65
+ │ │ │ ├── providers/
66
+ │ │ │ ├── screens/
67
+ │ │ │ └── widgets/
68
+ │ │ └── {feature}.dart # Barrel file
69
+ │ ├── shared/ # Shared components
70
+ │ │ ├── widgets/
71
+ │ │ └── utils/
72
+ │ └── main.dart
73
+ ├── test/
74
+ ├── android/
75
+ ├── ios/
76
+ ├── web/
77
+ ├── pubspec.yaml
78
+ └── analysis_options.yaml
79
+ ```
80
+
81
+ ## Key Patterns and Conventions
82
+
83
+ ### File Naming
84
+ - Use `snake_case.dart` for all Dart files
85
+ - Feature barrel files: `{feature}.dart`
86
+ - Widgets: `{name}_widget.dart`
87
+ - Screens: `{name}_screen.dart`
88
+ - Providers: `{name}_provider.dart`
89
+
90
+ ### Model Pattern (Freezed)
91
+
92
+ ```dart
93
+ // features/users/data/models/user_model.dart
94
+ import 'package:freezed_annotation/freezed_annotation.dart';
95
+
96
+ part 'user_model.freezed.dart';
97
+ part 'user_model.g.dart';
98
+
99
+ @freezed
100
+ class UserModel with _$UserModel {
101
+ const factory UserModel({
102
+ required String id,
103
+ required String name,
104
+ required String email,
105
+ @JsonKey(name: 'created_at') DateTime? createdAt,
106
+ }) = _UserModel;
107
+
108
+ factory UserModel.fromJson(Map<String, dynamic> json) =>
109
+ _$UserModelFromJson(json);
110
+ }
111
+
112
+ @freezed
113
+ class UserListResponse with _$UserListResponse {
114
+ const factory UserListResponse({
115
+ required List<UserModel> data,
116
+ required int total,
117
+ required int page,
118
+ required int limit,
119
+ @JsonKey(name: 'total_pages') required int totalPages,
120
+ }) = _UserListResponse;
121
+
122
+ factory UserListResponse.fromJson(Map<String, dynamic> json) =>
123
+ _$UserListResponseFromJson(json);
124
+ }
125
+ ```
126
+
127
+ ### Repository Pattern
128
+
129
+ ```dart
130
+ // features/users/data/repositories/user_repository.dart
131
+ import 'package:riverpod_annotation/riverpod_annotation.dart';
132
+
133
+ part 'user_repository.g.dart';
134
+
135
+ @riverpod
136
+ UserRepository userRepository(UserRepositoryRef ref) {
137
+ return UserRepository(ref.watch(apiClientProvider));
138
+ }
139
+
140
+ class UserRepository {
141
+ final ApiClient _apiClient;
142
+
143
+ UserRepository(this._apiClient);
144
+
145
+ Future<UserListResponse> getUsers({
146
+ int page = 1,
147
+ int limit = 10,
148
+ String? search,
149
+ }) async {
150
+ final response = await _apiClient.get(
151
+ '/users',
152
+ queryParameters: {
153
+ 'page': page,
154
+ 'limit': limit,
155
+ if (search != null) 'search': search,
156
+ },
157
+ );
158
+ return UserListResponse.fromJson(response.data);
159
+ }
160
+
161
+ Future<UserModel> getUserById(String id) async {
162
+ final response = await _apiClient.get('/users/$id');
163
+ return UserModel.fromJson(response.data);
164
+ }
165
+
166
+ Future<UserModel> createUser(CreateUserDto data) async {
167
+ final response = await _apiClient.post('/users', data: data.toJson());
168
+ return UserModel.fromJson(response.data);
169
+ }
170
+ }
171
+ ```
172
+
173
+ ### Provider Pattern (Riverpod)
174
+
175
+ ```dart
176
+ // features/users/presentation/providers/users_provider.dart
177
+ import 'package:riverpod_annotation/riverpod_annotation.dart';
178
+
179
+ part 'users_provider.g.dart';
180
+
181
+ @riverpod
182
+ class UsersNotifier extends _$UsersNotifier {
183
+ @override
184
+ Future<UserListResponse> build({int page = 1}) async {
185
+ final repository = ref.watch(userRepositoryProvider);
186
+ return repository.getUsers(page: page);
187
+ }
188
+
189
+ Future<void> refresh() async {
190
+ state = const AsyncLoading();
191
+ state = await AsyncValue.guard(() => ref.read(userRepositoryProvider).getUsers());
192
+ }
193
+
194
+ Future<void> createUser(CreateUserDto data) async {
195
+ await ref.read(userRepositoryProvider).createUser(data);
196
+ ref.invalidateSelf();
197
+ }
198
+ }
199
+
200
+ // Simple state provider
201
+ @riverpod
202
+ class SelectedUser extends _$SelectedUser {
203
+ @override
204
+ UserModel? build() => null;
205
+
206
+ void select(UserModel user) => state = user;
207
+ void clear() => state = null;
208
+ }
209
+ ```
210
+
211
+ ### Screen Pattern
212
+
213
+ ```dart
214
+ // features/users/presentation/screens/users_screen.dart
215
+ import 'package:flutter/material.dart';
216
+ import 'package:flutter_riverpod/flutter_riverpod.dart';
217
+
218
+ class UsersScreen extends ConsumerWidget {
219
+ const UsersScreen({super.key});
220
+
221
+ @override
222
+ Widget build(BuildContext context, WidgetRef ref) {
223
+ final usersAsync = ref.watch(usersNotifierProvider());
224
+
225
+ return Scaffold(
226
+ appBar: AppBar(
227
+ title: const Text('Users'),
228
+ actions: [
229
+ IconButton(
230
+ icon: const Icon(Icons.add),
231
+ onPressed: () => context.push('/users/new'),
232
+ ),
233
+ ],
234
+ ),
235
+ body: usersAsync.when(
236
+ loading: () => const Center(child: CircularProgressIndicator()),
237
+ error: (error, stack) => Center(child: Text('Error: $error')),
238
+ data: (response) => RefreshIndicator(
239
+ onRefresh: () => ref.read(usersNotifierProvider().notifier).refresh(),
240
+ child: ListView.builder(
241
+ itemCount: response.data.length,
242
+ itemBuilder: (context, index) {
243
+ final user = response.data[index];
244
+ return UserListTile(
245
+ user: user,
246
+ onTap: () => context.push('/users/${user.id}'),
247
+ );
248
+ },
249
+ ),
250
+ ),
251
+ ),
252
+ );
253
+ }
254
+ }
255
+ ```
256
+
257
+ ### Widget Pattern
258
+
259
+ ```dart
260
+ // features/users/presentation/widgets/user_list_tile.dart
261
+ import 'package:flutter/material.dart';
262
+
263
+ class UserListTile extends StatelessWidget {
264
+ final UserModel user;
265
+ final VoidCallback? onTap;
266
+
267
+ const UserListTile({
268
+ super.key,
269
+ required this.user,
270
+ this.onTap,
271
+ });
272
+
273
+ @override
274
+ Widget build(BuildContext context) {
275
+ return ListTile(
276
+ leading: CircleAvatar(
277
+ child: Text(user.name[0].toUpperCase()),
278
+ ),
279
+ title: Text(user.name),
280
+ subtitle: Text(user.email),
281
+ trailing: const Icon(Icons.chevron_right),
282
+ onTap: onTap,
283
+ );
284
+ }
285
+ }
286
+ ```
287
+
288
+ ### Router Configuration
289
+
290
+ ```dart
291
+ // core/router/app_router.dart
292
+ import 'package:go_router/go_router.dart';
293
+ import 'package:riverpod_annotation/riverpod_annotation.dart';
294
+
295
+ part 'app_router.g.dart';
296
+
297
+ @riverpod
298
+ GoRouter appRouter(AppRouterRef ref) {
299
+ return GoRouter(
300
+ initialLocation: '/',
301
+ routes: [
302
+ GoRoute(
303
+ path: '/',
304
+ builder: (context, state) => const HomeScreen(),
305
+ ),
306
+ GoRoute(
307
+ path: '/users',
308
+ builder: (context, state) => const UsersScreen(),
309
+ routes: [
310
+ GoRoute(
311
+ path: 'new',
312
+ builder: (context, state) => const CreateUserScreen(),
313
+ ),
314
+ GoRoute(
315
+ path: ':id',
316
+ builder: (context, state) {
317
+ final id = state.pathParameters['id']!;
318
+ return UserDetailScreen(userId: id);
319
+ },
320
+ ),
321
+ ],
322
+ ),
323
+ ],
324
+ );
325
+ }
326
+ ```
327
+
328
+ ## Adding New Feature
329
+
330
+ 1. Create feature directory structure:
331
+ ```bash
332
+ mkdir -p lib/features/{feature}/{data/{models,repositories,datasources},domain/entities,presentation/{providers,screens,widgets}}
333
+ ```
334
+
335
+ 2. Create model with Freezed (`data/models/{entity}_model.dart`)
336
+ 3. Create repository (`data/repositories/{entity}_repository.dart`)
337
+ 4. Create providers (`presentation/providers/{entity}_provider.dart`)
338
+ 5. Create screens (`presentation/screens/{entity}_screen.dart`)
339
+ 6. Create barrel file (`{feature}.dart`)
340
+ 7. Add routes in `app_router.dart`
341
+ 8. Run code generation: `dart run build_runner build`
342
+
343
+ ## API Client
344
+
345
+ ```dart
346
+ // core/network/api_client.dart
347
+ import 'package:dio/dio.dart';
348
+ import 'package:riverpod_annotation/riverpod_annotation.dart';
349
+
350
+ part 'api_client.g.dart';
351
+
352
+ @riverpod
353
+ ApiClient apiClient(ApiClientRef ref) {
354
+ return ApiClient(baseUrl: AppConfig.apiBaseUrl);
355
+ }
356
+
357
+ class ApiClient {
358
+ final Dio _dio;
359
+
360
+ ApiClient({required String baseUrl}) : _dio = Dio(BaseOptions(
361
+ baseUrl: baseUrl,
362
+ connectTimeout: const Duration(seconds: 10),
363
+ receiveTimeout: const Duration(seconds: 10),
364
+ )) {
365
+ _dio.interceptors.add(LogInterceptor());
366
+ }
367
+
368
+ void setAuthToken(String token) {
369
+ _dio.options.headers['Authorization'] = 'Bearer $token';
370
+ }
371
+
372
+ Future<Response> get(String path, {Map<String, dynamic>? queryParameters}) {
373
+ return _dio.get(path, queryParameters: queryParameters);
374
+ }
375
+
376
+ Future<Response> post(String path, {dynamic data}) {
377
+ return _dio.post(path, data: data);
378
+ }
379
+ }
380
+ ```
381
+
382
+ ## Configuration
383
+
384
+ ### pubspec.yaml
385
+ ```yaml
386
+ dependencies:
387
+ flutter:
388
+ sdk: flutter
389
+ flutter_riverpod: ^2.4.0
390
+ riverpod_annotation: ^2.3.0
391
+ go_router: ^13.0.0
392
+ dio: ^5.4.0
393
+ freezed_annotation: ^2.4.0
394
+ json_annotation: ^4.8.0
395
+
396
+ dev_dependencies:
397
+ flutter_test:
398
+ sdk: flutter
399
+ build_runner: ^2.4.0
400
+ riverpod_generator: ^2.3.0
401
+ freezed: ^2.4.0
402
+ json_serializable: ^6.7.0
403
+ flutter_lints: ^3.0.0
404
+ ```
405
+
406
+ ### Environment Config
407
+ ```dart
408
+ // core/config/app_config.dart
409
+ class AppConfig {
410
+ static const String apiBaseUrl = String.fromEnvironment(
411
+ 'API_BASE_URL',
412
+ defaultValue: 'http://localhost:8080/api',
413
+ );
414
+
415
+ static const bool isProduction = bool.fromEnvironment('PRODUCTION');
416
+ }
417
+ ```
418
+
419
+ Run with environment:
420
+ ```bash
421
+ flutter run --dart-define=API_BASE_URL=https://api.example.com
422
+ ```
423
+
424
+ ## Testing
425
+
426
+ ```dart
427
+ // test/features/users/users_provider_test.dart
428
+ import 'package:flutter_test/flutter_test.dart';
429
+ import 'package:flutter_riverpod/flutter_riverpod.dart';
430
+ import 'package:mocktail/mocktail.dart';
431
+
432
+ class MockUserRepository extends Mock implements UserRepository {}
433
+
434
+ void main() {
435
+ late MockUserRepository mockRepository;
436
+
437
+ setUp(() {
438
+ mockRepository = MockUserRepository();
439
+ });
440
+
441
+ test('fetches users successfully', () async {
442
+ when(() => mockRepository.getUsers()).thenAnswer(
443
+ (_) async => UserListResponse(data: [testUser], total: 1, page: 1, limit: 10, totalPages: 1),
444
+ );
445
+
446
+ final container = ProviderContainer(
447
+ overrides: [userRepositoryProvider.overrideWithValue(mockRepository)],
448
+ );
449
+
450
+ final result = await container.read(usersNotifierProvider().future);
451
+ expect(result.data.length, 1);
452
+ });
453
+ }
454
+ ```
@@ -0,0 +1,244 @@
1
+ # CLAUDE.md - Go + Gin Backend Template
2
+
3
+ ## Project Overview
4
+
5
+ Backend API service built with:
6
+ - **Go 1.22+** - Programming language
7
+ - **Gin** - HTTP web framework
8
+ - **GORM** - ORM for database operations
9
+ - **Redis** - Caching and session storage
10
+ - **Viper** - Configuration management
11
+
12
+ ## Quick Start
13
+
14
+ ```bash
15
+ # Install dependencies
16
+ go mod download
17
+
18
+ # Run development server
19
+ go run cmd/api/main.go
20
+
21
+ # Build for production
22
+ go build -o bin/api cmd/api/main.go
23
+
24
+ # Run tests
25
+ go test ./...
26
+ ```
27
+
28
+ ## Project Structure
29
+
30
+ ```
31
+ {project_name}/
32
+ ├── cmd/
33
+ │ └── api/
34
+ │ └── main.go # Application entry point
35
+ ├── internal/
36
+ │ ├── config/ # Configuration loading (Viper)
37
+ │ │ └── config.go
38
+ │ ├── middleware/ # HTTP middlewares
39
+ │ │ ├── auth.go
40
+ │ │ ├── cors.go
41
+ │ │ └── logger.go
42
+ │ └── modules/ # Feature modules
43
+ │ ├── router/
44
+ │ │ └── router.go # Route registration
45
+ │ └── {module}/
46
+ │ ├── controllers/
47
+ │ │ └── controller.go
48
+ │ ├── models/
49
+ │ │ └── entity.go
50
+ │ ├── usecases/
51
+ │ │ └── usecase.go
52
+ │ └── init.go
53
+ ├── pkg/ # Shared packages
54
+ │ ├── database/
55
+ │ │ └── database.go
56
+ │ ├── queue/
57
+ │ │ └── redis.go
58
+ │ └── response/
59
+ │ └── response.go
60
+ ├── config.yaml # Configuration file
61
+ ├── go.mod
62
+ └── go.sum
63
+ ```
64
+
65
+ ## Key Patterns and Conventions
66
+
67
+ ### File Naming
68
+ - Use `snake_case.go` for all Go files
69
+ - One struct per file when possible
70
+
71
+ ### Module Structure
72
+ Each module follows the layered architecture:
73
+ - **controllers/**: HTTP handlers, request/response mapping
74
+ - **usecases/**: Business logic
75
+ - **models/**: GORM models and DTOs
76
+
77
+ ### Module Init Pattern
78
+
79
+ ```go
80
+ // internal/modules/{module}/init.go
81
+ package module
82
+
83
+ func Init(r *gin.Engine, db *gorm.DB) {
84
+ repo := NewRepository(db)
85
+ uc := NewUseCase(repo)
86
+ ctrl := NewController(uc)
87
+
88
+ group := r.Group("/api/{module}")
89
+ {
90
+ group.GET("/", ctrl.List)
91
+ group.GET("/:id", ctrl.Get)
92
+ group.POST("/", ctrl.Create)
93
+ group.PUT("/:id", ctrl.Update)
94
+ group.DELETE("/:id", ctrl.Delete)
95
+ }
96
+ }
97
+ ```
98
+
99
+ ### Response Format
100
+
101
+ ```go
102
+ // Success response
103
+ c.JSON(http.StatusOK, gin.H{
104
+ "data": result,
105
+ })
106
+
107
+ // Error response
108
+ c.JSON(http.StatusBadRequest, gin.H{
109
+ "error": "validation failed",
110
+ "details": errors,
111
+ })
112
+
113
+ // Paginated response
114
+ c.JSON(http.StatusOK, gin.H{
115
+ "data": items,
116
+ "total": total,
117
+ "page": page,
118
+ "limit": limit,
119
+ "total_pages": totalPages,
120
+ })
121
+ ```
122
+
123
+ ### GORM Model Pattern
124
+
125
+ ```go
126
+ type Entity struct {
127
+ ID string `gorm:"type:char(36);primaryKey" json:"id"`
128
+ Name string `gorm:"type:varchar(255);not null" json:"name"`
129
+ Status string `gorm:"type:varchar(50);default:'active'" json:"status"`
130
+ CreatedAt time.Time `json:"created_at"`
131
+ UpdatedAt time.Time `json:"updated_at"`
132
+ }
133
+
134
+ func (e *Entity) BeforeCreate(tx *gorm.DB) error {
135
+ e.ID = uuid.New().String()
136
+ return nil
137
+ }
138
+ ```
139
+
140
+ ## Adding New Module
141
+
142
+ 1. Create module directory structure:
143
+ ```bash
144
+ mkdir -p internal/modules/{module}/{controllers,models,usecases}
145
+ ```
146
+
147
+ 2. Create model (`models/entity.go`):
148
+ ```go
149
+ type Entity struct {
150
+ ID string `gorm:"primaryKey" json:"id"`
151
+ Name string `json:"name"`
152
+ }
153
+ ```
154
+
155
+ 3. Create usecase (`usecases/usecase.go`):
156
+ ```go
157
+ type UseCase struct {
158
+ db *gorm.DB
159
+ }
160
+
161
+ func (uc *UseCase) List() ([]models.Entity, error) {
162
+ var items []models.Entity
163
+ return items, uc.db.Find(&items).Error
164
+ }
165
+ ```
166
+
167
+ 4. Create controller (`controllers/controller.go`):
168
+ ```go
169
+ type Controller struct {
170
+ uc *usecases.UseCase
171
+ }
172
+
173
+ func (ctrl *Controller) List(c *gin.Context) {
174
+ items, err := ctrl.uc.List()
175
+ if err != nil {
176
+ c.JSON(500, gin.H{"error": err.Error()})
177
+ return
178
+ }
179
+ c.JSON(200, gin.H{"data": items})
180
+ }
181
+ ```
182
+
183
+ 5. Create init.go and register in router
184
+
185
+ ## API Endpoints Pattern
186
+
187
+ | Method | Path | Description |
188
+ |--------|------|-------------|
189
+ | GET | /api/{resource}/ | List all items |
190
+ | GET | /api/{resource}/:id | Get single item |
191
+ | POST | /api/{resource}/ | Create item |
192
+ | PUT | /api/{resource}/:id | Update item |
193
+ | DELETE | /api/{resource}/:id | Delete item |
194
+
195
+ ### Query Parameters for List
196
+ - `page` - Page number (default: 1)
197
+ - `limit` - Items per page (default: 10)
198
+ - `search` - Search term
199
+ - `sort_by` - Sort field
200
+ - `order` - Sort order (asc/desc)
201
+
202
+ ## Configuration
203
+
204
+ ### config.yaml
205
+ ```yaml
206
+ server:
207
+ port: 8080
208
+ mode: debug # debug, release, test
209
+
210
+ database:
211
+ type: mysql # mysql, postgres, sqlite
212
+ host: localhost
213
+ port: 3306
214
+ user: root
215
+ password: ""
216
+ dbname: {project_name}
217
+
218
+ redis:
219
+ address: localhost:6379
220
+ password: ""
221
+ db: 0
222
+
223
+ jwt:
224
+ secret: your-secret-key
225
+ expiry: 24h
226
+ ```
227
+
228
+ ### Environment Variables
229
+ - `CONFIG_PATH` - Path to config file (default: ./config.yaml)
230
+ - `GIN_MODE` - Gin mode (debug/release)
231
+
232
+ ## Testing
233
+
234
+ ```go
235
+ // Use testify for assertions
236
+ func TestController_List(t *testing.T) {
237
+ router := setupTestRouter()
238
+ w := httptest.NewRecorder()
239
+ req, _ := http.NewRequest("GET", "/api/items/", nil)
240
+ router.ServeHTTP(w, req)
241
+
242
+ assert.Equal(t, 200, w.Code)
243
+ }
244
+ ```