@famgia/omnify-ai-guides 2.0.15
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.
- package/README.md +105 -0
- package/dist/chunk-RCTEXK7C.js +549 -0
- package/dist/chunk-RCTEXK7C.js.map +1 -0
- package/dist/config/rules.yaml +524 -0
- package/dist/index.cjs +587 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +55 -0
- package/dist/index.d.ts +55 -0
- package/dist/index.js +26 -0
- package/dist/index.js.map +1 -0
- package/dist/knowledge/agents/architect.md.stub +150 -0
- package/dist/knowledge/agents/developer.md.stub +190 -0
- package/dist/knowledge/agents/reviewer.md.stub +134 -0
- package/dist/knowledge/agents/tester.md.stub +196 -0
- package/dist/knowledge/checklists/backend.md.stub +112 -0
- package/dist/knowledge/checklists/react.md.stub +108 -0
- package/dist/knowledge/claude-rules/laravel-controllers.md.stub +57 -0
- package/dist/knowledge/claude-rules/laravel-migrations.md.stub +47 -0
- package/dist/knowledge/claude-rules/laravel-tests.md.stub +52 -0
- package/dist/knowledge/claude-rules/naming.md.stub +369 -0
- package/dist/knowledge/claude-rules/performance.md.stub +256 -0
- package/dist/knowledge/claude-rules/php-standards.md.stub +305 -0
- package/dist/knowledge/claude-rules/react-components.md.stub +67 -0
- package/dist/knowledge/claude-rules/schema-yaml.md.stub +83 -0
- package/dist/knowledge/claude-rules/security.md.stub +164 -0
- package/dist/knowledge/cursor-rules/antd-deprecations.mdc.stub +62 -0
- package/dist/knowledge/cursor-rules/basemodel-readonly.mdc.stub +66 -0
- package/dist/knowledge/cursor-rules/baserequest-readonly.mdc.stub +74 -0
- package/dist/knowledge/cursor-rules/baseresource-readonly.mdc.stub +78 -0
- package/dist/knowledge/cursor-rules/laravel-controller.mdc.stub +421 -0
- package/dist/knowledge/cursor-rules/laravel-request.mdc.stub +112 -0
- package/dist/knowledge/cursor-rules/laravel-resource.mdc.stub +73 -0
- package/dist/knowledge/cursor-rules/laravel-review.mdc.stub +69 -0
- package/dist/knowledge/cursor-rules/laravel-testing.mdc.stub +138 -0
- package/dist/knowledge/cursor-rules/laravel.mdc.stub +138 -0
- package/dist/knowledge/cursor-rules/migrations-workflow.mdc.stub +224 -0
- package/dist/knowledge/cursor-rules/model-editable.mdc.stub +120 -0
- package/dist/knowledge/cursor-rules/omnify-migrations.mdc.stub +109 -0
- package/dist/knowledge/cursor-rules/omnify-schema.mdc.stub +358 -0
- package/dist/knowledge/cursor-rules/omnify.mdc.stub +58 -0
- package/dist/knowledge/cursor-rules/react-design.mdc.stub +693 -0
- package/dist/knowledge/cursor-rules/react-form.mdc.stub +292 -0
- package/dist/knowledge/cursor-rules/react-services.mdc.stub +304 -0
- package/dist/knowledge/cursor-rules/react.mdc.stub +336 -0
- package/dist/knowledge/cursor-rules/request-editable.mdc.stub +111 -0
- package/dist/knowledge/cursor-rules/resource-editable.mdc.stub +125 -0
- package/dist/knowledge/cursor-rules/schema-create.mdc.stub +440 -0
- package/dist/knowledge/cursor-rules/validation-rules.mdc.stub +181 -0
- package/dist/knowledge/laravel/README.md.stub +59 -0
- package/dist/knowledge/laravel/architecture.md.stub +424 -0
- package/dist/knowledge/laravel/authentication.md.stub +588 -0
- package/dist/knowledge/laravel/controller.md.stub +484 -0
- package/dist/knowledge/laravel/datetime.md.stub +334 -0
- package/dist/knowledge/laravel/migrations-team.md.stub +376 -0
- package/dist/knowledge/laravel/openapi.md.stub +449 -0
- package/dist/knowledge/laravel/request.md.stub +450 -0
- package/dist/knowledge/laravel/resource.md.stub +516 -0
- package/dist/knowledge/laravel/service.md.stub +503 -0
- package/dist/knowledge/laravel/testing.md.stub +1504 -0
- package/dist/knowledge/omnify/antdesign-guide.md.stub +401 -0
- package/dist/knowledge/omnify/config-guide.md.stub +405 -0
- package/dist/knowledge/omnify/japan-guide.md.stub +186 -0
- package/dist/knowledge/omnify/laravel-guide.md.stub +61 -0
- package/dist/knowledge/omnify/partial-schema-guide.md.stub +353 -0
- package/dist/knowledge/omnify/react-form-guide.md.stub +225 -0
- package/dist/knowledge/omnify/schema-guide.md.stub +144 -0
- package/dist/knowledge/omnify/typescript-guide.md.stub +337 -0
- package/dist/knowledge/react/README.md.stub +221 -0
- package/dist/knowledge/react/antd-guide.md +528 -0
- package/dist/knowledge/react/antd-guide.md.stub +528 -0
- package/dist/knowledge/react/checklist.md.stub +108 -0
- package/dist/knowledge/react/datetime-guide.md.stub +137 -0
- package/dist/knowledge/react/design-philosophy.md.stub +363 -0
- package/dist/knowledge/react/i18n-guide.md.stub +211 -0
- package/dist/knowledge/react/laravel-integration.md.stub +181 -0
- package/dist/knowledge/react/service-pattern.md.stub +180 -0
- package/dist/knowledge/react/tanstack-query.md.stub +339 -0
- package/dist/knowledge/react/types-guide.md +669 -0
- package/dist/knowledge/react/types-guide.md.stub +669 -0
- package/dist/knowledge/workflows/bug-fix.md.stub +201 -0
- package/dist/knowledge/workflows/code-review.md.stub +164 -0
- package/dist/knowledge/workflows/new-feature.md.stub +327 -0
- package/dist/plugin-M95GyBll.d.cts +191 -0
- package/dist/plugin-M95GyBll.d.ts +191 -0
- package/dist/plugin.cjs +573 -0
- package/dist/plugin.cjs.map +1 -0
- package/dist/plugin.d.cts +2 -0
- package/dist/plugin.d.ts +2 -0
- package/dist/plugin.js +15 -0
- package/dist/plugin.js.map +1 -0
- package/package.json +53 -0
|
@@ -0,0 +1,334 @@
|
|
|
1
|
+
# DateTime Handling Guide
|
|
2
|
+
|
|
3
|
+
> **Related:** [README](./README.md) | [Resource Guide](./resource-guide.md)
|
|
4
|
+
|
|
5
|
+
## Golden Rule: "Store UTC, Respond UTC, Accept UTC"
|
|
6
|
+
|
|
7
|
+
```
|
|
8
|
+
Database (UTC) ← Carbon (UTC) → API Response (ISO 8601 UTC)
|
|
9
|
+
↑
|
|
10
|
+
API Request (UTC)
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
## Configuration
|
|
16
|
+
|
|
17
|
+
### 1. Set Application Timezone to UTC
|
|
18
|
+
|
|
19
|
+
**`config/app.php`:**
|
|
20
|
+
|
|
21
|
+
```php
|
|
22
|
+
'timezone' => 'UTC',
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
> ⚠️ NEVER change this to local timezone. Always use UTC.
|
|
26
|
+
|
|
27
|
+
### 2. Database Timezone
|
|
28
|
+
|
|
29
|
+
**MySQL** - Ensure UTC:
|
|
30
|
+
|
|
31
|
+
```sql
|
|
32
|
+
SET GLOBAL time_zone = '+00:00';
|
|
33
|
+
SET time_zone = '+00:00';
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
Or in `my.cnf`:
|
|
37
|
+
```ini
|
|
38
|
+
[mysqld]
|
|
39
|
+
default-time-zone = '+00:00'
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
---
|
|
43
|
+
|
|
44
|
+
## Carbon Usage Rules
|
|
45
|
+
|
|
46
|
+
### Always Use Carbon (Never raw DateTime)
|
|
47
|
+
|
|
48
|
+
```php
|
|
49
|
+
use Illuminate\Support\Carbon;
|
|
50
|
+
|
|
51
|
+
// ✅ Correct
|
|
52
|
+
$now = Carbon::now(); // Current UTC time
|
|
53
|
+
$date = Carbon::parse($input); // Parse with UTC
|
|
54
|
+
|
|
55
|
+
// ❌ Wrong
|
|
56
|
+
$now = new \DateTime(); // Don't use raw DateTime
|
|
57
|
+
$now = date('Y-m-d H:i:s'); // Don't use date()
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
### API Response Format
|
|
61
|
+
|
|
62
|
+
**Always return ISO 8601 with Z suffix:**
|
|
63
|
+
|
|
64
|
+
```php
|
|
65
|
+
// In Model - cast dates properly
|
|
66
|
+
protected $casts = [
|
|
67
|
+
'email_verified_at' => 'datetime',
|
|
68
|
+
'scheduled_at' => 'datetime',
|
|
69
|
+
'created_at' => 'datetime',
|
|
70
|
+
'updated_at' => 'datetime',
|
|
71
|
+
];
|
|
72
|
+
|
|
73
|
+
// In Resource - format as ISO 8601 UTC
|
|
74
|
+
public function toArray($request): array
|
|
75
|
+
{
|
|
76
|
+
return [
|
|
77
|
+
'id' => $this->id,
|
|
78
|
+
'title' => $this->title,
|
|
79
|
+
'scheduled_at' => $this->scheduled_at?->toISOString(), // "2024-01-15T10:30:00.000000Z"
|
|
80
|
+
'created_at' => $this->created_at?->toISOString(),
|
|
81
|
+
'updated_at' => $this->updated_at?->toISOString(),
|
|
82
|
+
];
|
|
83
|
+
}
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
### Accepting Date Input
|
|
87
|
+
|
|
88
|
+
```php
|
|
89
|
+
// In FormRequest
|
|
90
|
+
public function rules(): array
|
|
91
|
+
{
|
|
92
|
+
return [
|
|
93
|
+
'scheduled_at' => ['required', 'date'], // Accepts ISO 8601
|
|
94
|
+
];
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// In Controller - Carbon auto-parses UTC
|
|
98
|
+
public function store(StoreEventRequest $request): JsonResponse
|
|
99
|
+
{
|
|
100
|
+
$event = Event::create([
|
|
101
|
+
'title' => $request->title,
|
|
102
|
+
'scheduled_at' => Carbon::parse($request->scheduled_at), // Already UTC
|
|
103
|
+
]);
|
|
104
|
+
|
|
105
|
+
return new EventResource($event);
|
|
106
|
+
}
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
---
|
|
110
|
+
|
|
111
|
+
## Common Patterns
|
|
112
|
+
|
|
113
|
+
### Compare Dates
|
|
114
|
+
|
|
115
|
+
```php
|
|
116
|
+
use Illuminate\Support\Carbon;
|
|
117
|
+
|
|
118
|
+
// Current UTC time
|
|
119
|
+
$now = Carbon::now();
|
|
120
|
+
|
|
121
|
+
// Check if past
|
|
122
|
+
if ($event->scheduled_at->isPast()) {
|
|
123
|
+
// Event has passed
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
// Check if within range
|
|
127
|
+
$start = Carbon::parse($request->start_date);
|
|
128
|
+
$end = Carbon::parse($request->end_date);
|
|
129
|
+
|
|
130
|
+
Event::whereBetween('scheduled_at', [$start, $end])->get();
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
### Query by Date Range
|
|
134
|
+
|
|
135
|
+
```php
|
|
136
|
+
// Frontend sends UTC strings
|
|
137
|
+
// "2024-01-01T00:00:00Z" to "2024-01-31T23:59:59Z"
|
|
138
|
+
|
|
139
|
+
public function index(Request $request)
|
|
140
|
+
{
|
|
141
|
+
$query = Event::query();
|
|
142
|
+
|
|
143
|
+
if ($request->filled('start_date')) {
|
|
144
|
+
$query->where('scheduled_at', '>=', Carbon::parse($request->start_date));
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
if ($request->filled('end_date')) {
|
|
148
|
+
$query->where('scheduled_at', '<=', Carbon::parse($request->end_date));
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
return EventResource::collection($query->paginate());
|
|
152
|
+
}
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
### Display for Specific Timezone (if needed)
|
|
156
|
+
|
|
157
|
+
```php
|
|
158
|
+
// Only when generating reports for specific timezone
|
|
159
|
+
$userTimezone = 'Asia/Tokyo';
|
|
160
|
+
|
|
161
|
+
$localTime = $event->scheduled_at->setTimezone($userTimezone);
|
|
162
|
+
// Keep original as UTC, create copy for display
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
---
|
|
166
|
+
|
|
167
|
+
## Model Setup
|
|
168
|
+
|
|
169
|
+
### Recommended Model Structure
|
|
170
|
+
|
|
171
|
+
```php
|
|
172
|
+
<?php
|
|
173
|
+
|
|
174
|
+
namespace App\Models;
|
|
175
|
+
|
|
176
|
+
use Illuminate\Database\Eloquent\Model;
|
|
177
|
+
use Illuminate\Support\Carbon;
|
|
178
|
+
|
|
179
|
+
class Event extends Model
|
|
180
|
+
{
|
|
181
|
+
protected $fillable = [
|
|
182
|
+
'title',
|
|
183
|
+
'scheduled_at',
|
|
184
|
+
];
|
|
185
|
+
|
|
186
|
+
protected $casts = [
|
|
187
|
+
'scheduled_at' => 'datetime',
|
|
188
|
+
];
|
|
189
|
+
|
|
190
|
+
// Accessor for formatted date (if needed internally)
|
|
191
|
+
public function getScheduledAtFormattedAttribute(): string
|
|
192
|
+
{
|
|
193
|
+
return $this->scheduled_at?->toISOString() ?? '';
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
// Scope for upcoming events
|
|
197
|
+
public function scopeUpcoming($query)
|
|
198
|
+
{
|
|
199
|
+
return $query->where('scheduled_at', '>', Carbon::now());
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
// Scope for past events
|
|
203
|
+
public function scopePast($query)
|
|
204
|
+
{
|
|
205
|
+
return $query->where('scheduled_at', '<', Carbon::now());
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
### Resource Format
|
|
211
|
+
|
|
212
|
+
```php
|
|
213
|
+
<?php
|
|
214
|
+
|
|
215
|
+
namespace App\Http\Resources;
|
|
216
|
+
|
|
217
|
+
use Illuminate\Http\Resources\Json\JsonResource;
|
|
218
|
+
|
|
219
|
+
class EventResource extends JsonResource
|
|
220
|
+
{
|
|
221
|
+
public function toArray($request): array
|
|
222
|
+
{
|
|
223
|
+
return [
|
|
224
|
+
'id' => $this->id,
|
|
225
|
+
'title' => $this->title,
|
|
226
|
+
'scheduled_at' => $this->scheduled_at?->toISOString(),
|
|
227
|
+
'is_past' => $this->scheduled_at?->isPast() ?? false,
|
|
228
|
+
'created_at' => $this->created_at?->toISOString(),
|
|
229
|
+
'updated_at' => $this->updated_at?->toISOString(),
|
|
230
|
+
];
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
---
|
|
236
|
+
|
|
237
|
+
## Migration Example
|
|
238
|
+
|
|
239
|
+
```php
|
|
240
|
+
Schema::create('events', function (Blueprint $table) {
|
|
241
|
+
$table->id();
|
|
242
|
+
$table->string('title');
|
|
243
|
+
$table->timestamp('scheduled_at'); // Use timestamp, not datetime
|
|
244
|
+
$table->timestamps(); // created_at, updated_at
|
|
245
|
+
});
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
> **Note:** `timestamp` columns in MySQL are stored as UTC internally.
|
|
249
|
+
|
|
250
|
+
---
|
|
251
|
+
|
|
252
|
+
## Anti-Patterns ❌
|
|
253
|
+
|
|
254
|
+
```php
|
|
255
|
+
// ❌ DON'T: Set local timezone in config
|
|
256
|
+
'timezone' => 'Asia/Tokyo', // Wrong!
|
|
257
|
+
|
|
258
|
+
// ❌ DON'T: Use raw PHP date functions
|
|
259
|
+
$date = date('Y-m-d H:i:s');
|
|
260
|
+
$date = new \DateTime();
|
|
261
|
+
|
|
262
|
+
// ❌ DON'T: Return formatted local time in API
|
|
263
|
+
return ['created_at' => $this->created_at->format('Y/m/d H:i')];
|
|
264
|
+
|
|
265
|
+
// ❌ DON'T: Store timezone offset in database
|
|
266
|
+
$event->scheduled_at = '2024-01-15 19:30:00+09:00';
|
|
267
|
+
|
|
268
|
+
// ❌ DON'T: Convert to local timezone before storing
|
|
269
|
+
$event->scheduled_at = Carbon::parse($input)->setTimezone('Asia/Tokyo');
|
|
270
|
+
```
|
|
271
|
+
|
|
272
|
+
## Correct Patterns ✅
|
|
273
|
+
|
|
274
|
+
```php
|
|
275
|
+
// ✅ DO: Keep UTC timezone
|
|
276
|
+
'timezone' => 'UTC',
|
|
277
|
+
|
|
278
|
+
// ✅ DO: Use Carbon everywhere
|
|
279
|
+
$now = Carbon::now();
|
|
280
|
+
$date = Carbon::parse($input);
|
|
281
|
+
|
|
282
|
+
// ✅ DO: Return ISO 8601 UTC in API
|
|
283
|
+
return ['created_at' => $this->created_at?->toISOString()];
|
|
284
|
+
|
|
285
|
+
// ✅ DO: Store as UTC
|
|
286
|
+
$event->scheduled_at = Carbon::parse($input); // Input should be UTC from frontend
|
|
287
|
+
```
|
|
288
|
+
|
|
289
|
+
---
|
|
290
|
+
|
|
291
|
+
## API Contract with Frontend
|
|
292
|
+
|
|
293
|
+
| Direction | Format | Example |
|
|
294
|
+
| -------------- | ------------- | ------------------------------- |
|
|
295
|
+
| API → Frontend | ISO 8601 UTC | `"2024-01-15T10:30:00.000000Z"` |
|
|
296
|
+
| Frontend → API | ISO 8601 UTC | `"2024-01-15T10:30:00.000Z"` |
|
|
297
|
+
| Database | UTC Timestamp | `2024-01-15 10:30:00` |
|
|
298
|
+
|
|
299
|
+
---
|
|
300
|
+
|
|
301
|
+
## Testing with Dates
|
|
302
|
+
|
|
303
|
+
```php
|
|
304
|
+
use Illuminate\Support\Carbon;
|
|
305
|
+
|
|
306
|
+
public function test_creates_event_with_correct_date(): void
|
|
307
|
+
{
|
|
308
|
+
Carbon::setTestNow('2024-01-15 10:00:00'); // Freeze time in UTC
|
|
309
|
+
|
|
310
|
+
$response = $this->postJson('/api/events', [
|
|
311
|
+
'title' => 'Test Event',
|
|
312
|
+
'scheduled_at' => '2024-01-20T15:00:00.000Z',
|
|
313
|
+
]);
|
|
314
|
+
|
|
315
|
+
$response->assertCreated();
|
|
316
|
+
|
|
317
|
+
$this->assertDatabaseHas('events', [
|
|
318
|
+
'title' => 'Test Event',
|
|
319
|
+
'scheduled_at' => '2024-01-20 15:00:00', // Stored as UTC
|
|
320
|
+
]);
|
|
321
|
+
}
|
|
322
|
+
```
|
|
323
|
+
|
|
324
|
+
---
|
|
325
|
+
|
|
326
|
+
## Checklist
|
|
327
|
+
|
|
328
|
+
- [ ] `config/app.php` timezone is `UTC`
|
|
329
|
+
- [ ] MySQL timezone is UTC
|
|
330
|
+
- [ ] All models use `datetime` cast for date fields
|
|
331
|
+
- [ ] All Resources return `->toISOString()` for dates
|
|
332
|
+
- [ ] Never use raw `date()` or `DateTime` - always Carbon
|
|
333
|
+
- [ ] Never convert to local timezone before storing
|
|
334
|
+
- [ ] API documentation specifies UTC format
|
|
@@ -0,0 +1,376 @@
|
|
|
1
|
+
# Migration Team Workflow Guide
|
|
2
|
+
|
|
3
|
+
> Best practices for managing database migrations in team development environments.
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
Omnify follows **international standards** for database migration management:
|
|
8
|
+
|
|
9
|
+
1. **Schema as Source of Truth** - YAML schemas define the database structure
|
|
10
|
+
2. **Simple File Tracking** - Lock file tracks migrations for regeneration
|
|
11
|
+
3. **CI Validation** - Automated checks ensure sync between schema and migrations
|
|
12
|
+
4. **Git for Conflict Resolution** - Standard Git workflow handles merge conflicts
|
|
13
|
+
|
|
14
|
+
## Migration Tracking System
|
|
15
|
+
|
|
16
|
+
### Lock File Structure
|
|
17
|
+
|
|
18
|
+
The `.omnify.lock` file tracks all generated migrations:
|
|
19
|
+
|
|
20
|
+
```json
|
|
21
|
+
{
|
|
22
|
+
"version": 2,
|
|
23
|
+
"migrations": [
|
|
24
|
+
{
|
|
25
|
+
"fileName": "2026_01_13_100000_create_users_table.php",
|
|
26
|
+
"timestamp": "2026_01_13_100000",
|
|
27
|
+
"tableName": "users",
|
|
28
|
+
"type": "create",
|
|
29
|
+
"generatedAt": "2026-01-13T10:00:00Z",
|
|
30
|
+
"schemas": ["User"],
|
|
31
|
+
"checksum": "sha256..."
|
|
32
|
+
}
|
|
33
|
+
]
|
|
34
|
+
}
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
### Key Fields
|
|
38
|
+
|
|
39
|
+
| Field | Purpose |
|
|
40
|
+
|-------|---------|
|
|
41
|
+
| `fileName` | Full migration filename |
|
|
42
|
+
| `timestamp` | Timestamp prefix for regeneration |
|
|
43
|
+
| `tableName` | Table name for lookup |
|
|
44
|
+
| `type` | Migration type (create/alter/drop/pivot) |
|
|
45
|
+
| `checksum` | SHA-256 hash for integrity verification |
|
|
46
|
+
|
|
47
|
+
## CI/CD Integration
|
|
48
|
+
|
|
49
|
+
### GitHub Actions Example
|
|
50
|
+
|
|
51
|
+
```yaml
|
|
52
|
+
# .github/workflows/migration-check.yml
|
|
53
|
+
name: Migration Check
|
|
54
|
+
|
|
55
|
+
on: [push, pull_request]
|
|
56
|
+
|
|
57
|
+
jobs:
|
|
58
|
+
validate:
|
|
59
|
+
runs-on: ubuntu-latest
|
|
60
|
+
steps:
|
|
61
|
+
- uses: actions/checkout@v4
|
|
62
|
+
|
|
63
|
+
- name: Setup Node.js
|
|
64
|
+
uses: actions/setup-node@v4
|
|
65
|
+
with:
|
|
66
|
+
node-version: '20'
|
|
67
|
+
|
|
68
|
+
- name: Install dependencies
|
|
69
|
+
run: npm ci
|
|
70
|
+
|
|
71
|
+
- name: Check migrations sync
|
|
72
|
+
run: npx omnify generate --check
|
|
73
|
+
|
|
74
|
+
- name: Test migrations (optional)
|
|
75
|
+
run: |
|
|
76
|
+
php artisan migrate:fresh --force
|
|
77
|
+
php artisan migrate:status
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
### CI Check Mode
|
|
81
|
+
|
|
82
|
+
```bash
|
|
83
|
+
# Check if migrations are in sync (for CI)
|
|
84
|
+
npx omnify generate --check
|
|
85
|
+
|
|
86
|
+
# Exit codes:
|
|
87
|
+
# 0 = All migrations in sync ✅
|
|
88
|
+
# 1 = Schema changes detected or migration issues ❌
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
Output example:
|
|
92
|
+
```
|
|
93
|
+
Omnify v1.0.113 - Generating Outputs
|
|
94
|
+
|
|
95
|
+
✔ Loading schemas from schemas
|
|
96
|
+
✔ Validating schemas...
|
|
97
|
+
✔ Checking for changes...
|
|
98
|
+
|
|
99
|
+
CI Check Mode Results:
|
|
100
|
+
Schemas: 12
|
|
101
|
+
Tracked migrations: 15
|
|
102
|
+
Migrations on disk: 15
|
|
103
|
+
Schema changes: 0
|
|
104
|
+
|
|
105
|
+
✅ All migrations in sync
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
## Team Development Workflow
|
|
109
|
+
|
|
110
|
+
### Standard Workflow
|
|
111
|
+
|
|
112
|
+
```
|
|
113
|
+
┌─────────────────────────────────────────────────────────────┐
|
|
114
|
+
│ 1. Edit YAML Schema │
|
|
115
|
+
│ schemas/module/Model.yaml │
|
|
116
|
+
└─────────────────────────────────────────────────────────────┘
|
|
117
|
+
│
|
|
118
|
+
▼
|
|
119
|
+
┌─────────────────────────────────────────────────────────────┐
|
|
120
|
+
│ 2. Generate Migrations │
|
|
121
|
+
│ npx omnify generate │
|
|
122
|
+
└─────────────────────────────────────────────────────────────┘
|
|
123
|
+
│
|
|
124
|
+
▼
|
|
125
|
+
┌─────────────────────────────────────────────────────────────┐
|
|
126
|
+
│ 3. Commit Both │
|
|
127
|
+
│ git add schemas/ {{LARAVEL_ROOT}}database/migrations/ .omnify.lock │
|
|
128
|
+
│ git commit -m "feat: add phone field to User" │
|
|
129
|
+
└─────────────────────────────────────────────────────────────┘
|
|
130
|
+
│
|
|
131
|
+
▼
|
|
132
|
+
┌─────────────────────────────────────────────────────────────┐
|
|
133
|
+
│ 4. CI Validates │
|
|
134
|
+
│ GitHub Actions runs: npx omnify generate --check │
|
|
135
|
+
└─────────────────────────────────────────────────────────────┘
|
|
136
|
+
│
|
|
137
|
+
▼
|
|
138
|
+
┌─────────────────────────────────────────────────────────────┐
|
|
139
|
+
│ 5. Merge & Deploy │
|
|
140
|
+
│ php artisan migrate │
|
|
141
|
+
└─────────────────────────────────────────────────────────────┘
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
### Parallel Development
|
|
145
|
+
|
|
146
|
+
When multiple developers work on different schemas:
|
|
147
|
+
|
|
148
|
+
```
|
|
149
|
+
Developer A Developer B
|
|
150
|
+
│ │
|
|
151
|
+
Edit User.yaml Edit Product.yaml
|
|
152
|
+
(add phone) (add sku)
|
|
153
|
+
│ │
|
|
154
|
+
omnify generate omnify generate
|
|
155
|
+
│ │
|
|
156
|
+
Creates: Creates:
|
|
157
|
+
alter_users_add_phone.php alter_products_add_sku.php
|
|
158
|
+
│ │
|
|
159
|
+
└──────────┬───────────────────┘
|
|
160
|
+
│
|
|
161
|
+
Git Merge
|
|
162
|
+
│
|
|
163
|
+
Both migrations exist ✅
|
|
164
|
+
(different tables, no conflict)
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
### Same Schema Conflict
|
|
168
|
+
|
|
169
|
+
When multiple developers edit the SAME schema:
|
|
170
|
+
|
|
171
|
+
```
|
|
172
|
+
Developer A Developer B
|
|
173
|
+
│ │
|
|
174
|
+
Edit User.yaml Edit User.yaml
|
|
175
|
+
(add phone) (add address)
|
|
176
|
+
│ │
|
|
177
|
+
omnify generate omnify generate
|
|
178
|
+
│ │
|
|
179
|
+
└──────────┬───────────────────┘
|
|
180
|
+
│
|
|
181
|
+
Git Merge
|
|
182
|
+
│
|
|
183
|
+
⚠️ YAML Conflict!
|
|
184
|
+
│
|
|
185
|
+
┌──────────┴──────────┐
|
|
186
|
+
│ │
|
|
187
|
+
Resolve YAML Keep both migrations
|
|
188
|
+
(merge both fields) (Laravel runs both)
|
|
189
|
+
│ │
|
|
190
|
+
└──────────┬──────────┘
|
|
191
|
+
│
|
|
192
|
+
Result:
|
|
193
|
+
User.yaml has phone + address
|
|
194
|
+
Both migrations exist
|
|
195
|
+
Laravel runs in timestamp order ✅
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
## Handling Common Scenarios
|
|
199
|
+
|
|
200
|
+
### Scenario 1: Accidentally Deleted Migration
|
|
201
|
+
|
|
202
|
+
**Problem:** Migration file deleted but lock file still tracks it.
|
|
203
|
+
|
|
204
|
+
**Detection:**
|
|
205
|
+
```bash
|
|
206
|
+
npx omnify generate
|
|
207
|
+
|
|
208
|
+
⚠️ Migration file issues detected:
|
|
209
|
+
Missing files (1):
|
|
210
|
+
- 2026_01_13_100000_create_users_table.php
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
**Solutions:**
|
|
214
|
+
```bash
|
|
215
|
+
# Option 1: Restore from git
|
|
216
|
+
git checkout -- {{LARAVEL_ROOT}}database/migrations/omnify/
|
|
217
|
+
|
|
218
|
+
# Option 2: Reset and regenerate (destructive!)
|
|
219
|
+
npx omnify reset --migrations
|
|
220
|
+
npx omnify generate --force
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
### Scenario 2: Stale Migration from Old Branch
|
|
224
|
+
|
|
225
|
+
**Problem:** Branch created 1 month ago, merged today with old timestamp.
|
|
226
|
+
|
|
227
|
+
**Detection:**
|
|
228
|
+
```bash
|
|
229
|
+
npx omnify generate
|
|
230
|
+
|
|
231
|
+
⚠️ Stale migrations detected (old timestamp, not in lock file):
|
|
232
|
+
- 2026_01_04_100000_add_phone_to_users_table.php
|
|
233
|
+
These may be from merged branches. Review before running migrate.
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
**Action:**
|
|
237
|
+
1. Review the migration - is it independent or dependent?
|
|
238
|
+
2. If independent: Keep as-is, Laravel runs in timestamp order
|
|
239
|
+
3. If dependent: Consider renaming with new timestamp
|
|
240
|
+
|
|
241
|
+
### Scenario 3: CI Fails with "Schema changes detected"
|
|
242
|
+
|
|
243
|
+
**Problem:** Someone edited schema but forgot to run generate.
|
|
244
|
+
|
|
245
|
+
**Detection:**
|
|
246
|
+
```bash
|
|
247
|
+
npx omnify generate --check
|
|
248
|
+
|
|
249
|
+
❌ Schema changes detected - run "npx omnify generate" to update migrations
|
|
250
|
+
```
|
|
251
|
+
|
|
252
|
+
**Solution:**
|
|
253
|
+
```bash
|
|
254
|
+
# Locally
|
|
255
|
+
npx omnify generate
|
|
256
|
+
git add .
|
|
257
|
+
git commit --amend # or new commit
|
|
258
|
+
git push --force # or regular push
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
## Best Practices
|
|
262
|
+
|
|
263
|
+
### DO ✅
|
|
264
|
+
|
|
265
|
+
1. **Always commit schema + migrations together**
|
|
266
|
+
```bash
|
|
267
|
+
git add schemas/ {{LARAVEL_ROOT}}database/migrations/omnify/ .omnify.lock
|
|
268
|
+
git commit -m "feat: add field to schema"
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
2. **Use CI to validate migrations**
|
|
272
|
+
```bash
|
|
273
|
+
npx omnify generate --check
|
|
274
|
+
```
|
|
275
|
+
|
|
276
|
+
3. **Pull and migrate before starting new work**
|
|
277
|
+
```bash
|
|
278
|
+
git pull
|
|
279
|
+
php artisan migrate
|
|
280
|
+
```
|
|
281
|
+
|
|
282
|
+
4. **Review stale migration warnings**
|
|
283
|
+
- Check dependencies before merging old branches
|
|
284
|
+
|
|
285
|
+
### DON'T ❌
|
|
286
|
+
|
|
287
|
+
1. **Don't manually edit migrations in `omnify/` folder**
|
|
288
|
+
- They will be overwritten!
|
|
289
|
+
|
|
290
|
+
2. **Don't ignore CI failures**
|
|
291
|
+
- Always run `npx omnify generate` if CI fails
|
|
292
|
+
|
|
293
|
+
3. **Don't commit migrations without schemas**
|
|
294
|
+
- Schema is source of truth
|
|
295
|
+
|
|
296
|
+
4. **Don't skip stale warnings without review**
|
|
297
|
+
- Old timestamps might run before dependent migrations
|
|
298
|
+
|
|
299
|
+
## Migration Validation
|
|
300
|
+
|
|
301
|
+
### Check Commands
|
|
302
|
+
|
|
303
|
+
```bash
|
|
304
|
+
# Full check (for CI)
|
|
305
|
+
npx omnify generate --check
|
|
306
|
+
|
|
307
|
+
# Generate with stale warnings (default)
|
|
308
|
+
npx omnify generate
|
|
309
|
+
|
|
310
|
+
# Generate without stale warnings
|
|
311
|
+
npx omnify generate --no-warn-stale
|
|
312
|
+
|
|
313
|
+
# Force regenerate everything
|
|
314
|
+
npx omnify generate --force
|
|
315
|
+
```
|
|
316
|
+
|
|
317
|
+
### Validation Checks
|
|
318
|
+
|
|
319
|
+
| Check | Description | Exit Code |
|
|
320
|
+
|-------|-------------|-----------|
|
|
321
|
+
| Schema sync | Schema matches generated migrations | 1 if mismatch |
|
|
322
|
+
| Missing files | Migration files exist on disk | 1 if missing |
|
|
323
|
+
| Modified files | Files match stored checksum | Warning only |
|
|
324
|
+
| Stale files | Old timestamp, not tracked | Warning only |
|
|
325
|
+
|
|
326
|
+
## Troubleshooting
|
|
327
|
+
|
|
328
|
+
### "Missing migration files"
|
|
329
|
+
|
|
330
|
+
```bash
|
|
331
|
+
# Check what's missing
|
|
332
|
+
npx omnify generate --check
|
|
333
|
+
|
|
334
|
+
# Restore from git
|
|
335
|
+
git checkout -- {{LARAVEL_ROOT}}database/migrations/omnify/
|
|
336
|
+
|
|
337
|
+
# Or reset completely
|
|
338
|
+
npx omnify reset --migrations
|
|
339
|
+
npx omnify generate --force
|
|
340
|
+
```
|
|
341
|
+
|
|
342
|
+
### "Checksum mismatch"
|
|
343
|
+
|
|
344
|
+
Someone manually edited an auto-generated file.
|
|
345
|
+
|
|
346
|
+
```bash
|
|
347
|
+
# Option 1: Regenerate
|
|
348
|
+
npx omnify generate --force
|
|
349
|
+
|
|
350
|
+
# Option 2: Reset lock file entry
|
|
351
|
+
# (manually edit .omnify.lock to remove the entry)
|
|
352
|
+
```
|
|
353
|
+
|
|
354
|
+
### "Stale migrations"
|
|
355
|
+
|
|
356
|
+
Old branch merged with old timestamps.
|
|
357
|
+
|
|
358
|
+
```bash
|
|
359
|
+
# Usually safe to ignore if migrations are independent
|
|
360
|
+
# But review the migration order:
|
|
361
|
+
|
|
362
|
+
php artisan migrate:status
|
|
363
|
+
# Check: Will the old migration run before something it depends on?
|
|
364
|
+
```
|
|
365
|
+
|
|
366
|
+
## Summary
|
|
367
|
+
|
|
368
|
+
| Workflow Step | Command |
|
|
369
|
+
|---------------|---------|
|
|
370
|
+
| Edit schema | Edit `schemas/*.yaml` |
|
|
371
|
+
| Generate | `npx omnify generate` |
|
|
372
|
+
| Commit | `git add schemas/ {{LARAVEL_ROOT}}database/migrations/ .omnify.lock` |
|
|
373
|
+
| CI Check | `npx omnify generate --check` |
|
|
374
|
+
| Deploy | `php artisan migrate` |
|
|
375
|
+
| Restore | `git checkout -- {{LARAVEL_ROOT}}database/migrations/omnify/` |
|
|
376
|
+
| Reset | `npx omnify reset --migrations` |
|