You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: admin/AGENTS.md
+6Lines changed: 6 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -194,12 +194,16 @@ When adding a new entity, build the files in this order, matching the existing f
194
194
- Tables use `public static function table(Table $table): Table` with `->columns([])`, `->filters([])`, `->recordActions([...])`, `->toolbarActions([...])`.
195
195
- Actions come from the `Filament\Actions\` namespace (`EditAction`, `CreateAction`, `DeleteAction`, `BulkActionGroup`, `DeleteBulkAction`).
196
196
- Import individual components (`Filament\Forms\Components\TextInput`, `Filament\Tables\Columns\TextColumn`), not the parent `Forms`/`Tables` namespaces.
197
+
- For reactive `->options()` or `->live()` closures that receive `Get $get`, import `Filament\Schemas\Components\Utilities\Get` (NOT `Filament\Forms\Get` - that will throw a type error at runtime).
197
198
- Page classes set `protected static string $resource = {Name}Resource::class;`. List pages expose `CreateAction::make()` in `getHeaderActions()`. Create and Edit pages redirect with `getRedirectUrl(): string` returning `$this->getResource()::getUrl('index')`.
198
199
- Rich text uses `AmidEsfahani\FilamentTinyEditor\TinyEditor`.
199
200
- Select fields backed by an enum use `->options(SomeEnum::options())` and `->default(SomeEnum::CASE->value)`.
200
201
- Table text columns that can be long (headings, relation labels) use `->limit(30)->wrap()`.
201
202
- Enum-backed table columns render via `->getStateUsing(fn ($record) => $record->field->label())` and `->color(fn ($record) => $record->field->color())`.
202
203
- Manage many-to-many pivots with a relationship multi-select: `Select::make('products')->relationship('products', 'heading')->multiple()->searchable()->preload()` (see `CouponResource`). No separate resource for pure scoping pivots.
204
+
- Control navigation order within a group with `protected static ?int $navigationSort = 1;` (lower = higher in the list).
205
+
- Add an explanatory subheading to a list page with `protected ?string $subheading = 'Description here.';` on the `ListRecords` page class.
206
+
- Add a tooltip to a form field with `->hintIcon('heroicon-o-information-circle')->hintIconTooltip('Explanation...')`. Use this instead of always-visible `->hint()` when the text is long.
203
207
204
208
## Models
205
209
@@ -218,6 +222,7 @@ When adding a new entity, build the files in this order, matching the existing f
218
222
219
223
## Migrations
220
224
225
+
-**Development rule**: NEVER create a new migration to add a column to a table that already has a migration in this branch. Update the existing `create_*` migration directly to keep history clean. After editing, run `php artisan migrate:fresh` inside the container to re-apply everything from scratch. Only create additive migrations when the table already exists in production.
221
226
- Anonymous class style: `return new class extends Migration`.
222
227
- Use `$table->foreignIdFor(Model::class)` for foreign keys (add `->nullable()` when optional). Chain `->constrained()->cascadeOnDelete()` / `->nullOnDelete()` / `->restrictOnDelete()` to add the real FK constraint with its delete rule.
223
228
- For a second FK to the same table, use a named column: `$table->foreignId('user_creator_id')->nullable()->constrained('users')->nullOnDelete()` (see `coupons`).
@@ -255,5 +260,6 @@ When adding a new entity, build the files in this order, matching the existing f
255
260
256
261
- The implementation status and priority order live in `IMPLEMENTATION.md`. When an entity is finished or the plan changes, update it.
257
262
- The full schema reference is `ShoFlow db doc.md`. Treat it as the source of truth for table columns and relationships.
263
+
- Cache keys that have been identified but not yet implemented are tracked in `CACHE.md`. When adding a model whose data is likely to be cached (products, categories, banners, menus, etc.), check `CACHE.md` and add or update the relevant rows.
258
264
- Keep this "ShopFlow Admin Conventions" section updated whenever a new reusable pattern is introduced.
Tracks cache keys that have been identified but are not yet implemented.
4
+
When a cache is implemented, move it to the **Implemented** section and record the key, driver, TTL, and where it is invalidated.
5
+
6
+
Legend: `[ ]` not started, `[x]` implemented.
7
+
8
+
> **Note:**`variety_counts` on `products` is NOT a cache. It is a denormalized DB column kept in sync by `Variety::booted()` (saved/deleted events calling `syncProductVarietyCount()`). No cache entry needed for it.
9
+
10
+
---
11
+
12
+
## Pending (identified, not implemented)
13
+
14
+
| # | Cache key / pattern | What it caches | Suggested TTL | Invalidated when |
-`CACHE.md` added to track identified-but-not-implemented cache keys.
35
+
31
36
## Phase 0 - Finish current branch (`implement_variety`)
32
37
33
38
Done. Variety has model, migration, factory, resource (+ pages), tests, and `variety_counts` auto-sync.
34
39
35
40
-[x] Fix `VarietyResource` table: `product.heading` column (was `product.title` with `->numeric()` on a string)
36
-
-[ ] Variety extensions (`warehouse_id`, `guarantee_name_id`, `attribute_id`, `variety_attribute`, `variety_serials`, `variety_details`) - deferred to Phase 3, they need Warehouses / Guarantees first
37
-
-[ ] Attribute `as_filter` / `required` flags into the product/category flow (open `// todo` in the attribute-group-category migration) - moved to its own branch; it is an attribute/category feature, not variety
41
+
-[x]`attribute_id` FK on varieties - links each variety to one attribute; auto-populates `attribute_value` and `color` from the attribute on save
42
+
-[ ] Variety extensions (`warehouse_id`, `guarantee_name_id`, `variety_serials`, `variety_details`) - deferred to Phase 3, they need Warehouses / Guarantees first
43
+
-[x] Attribute `required` flag enforced in `ProductResource`: if a category has required attribute groups, saving a product without them shows a danger notification and skips the sync
Copy file name to clipboardExpand all lines: admin/ShoFlow db doc.md
+8-8Lines changed: 8 additions & 8 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -94,11 +94,10 @@ Used to store banners.
94
94
*`position` specifies the advertisement location, which is an arbitrary name to retrieve the corresponding record from the database.
95
95
*`heading` specifies the banner item title or the alt text of the image.
96
96
*`url` specifies the item link, which redirects when the image or title is clicked.
97
-
*`image_id1` specifies the item's image.
98
-
*`image_id2` specifies the item's image.
99
-
*`image_id3` specifies the item's image.
100
97
*`sort` specifies the item order.
101
-
*`status` specifies the publication and draft status of the banner.
98
+
*`status` stores the publication status of the banner, with values 10 for deleted, 20 for published, and 30 for draft.
99
+
100
+
Images are attached through the polymorphic `images` table (`imageable_type` / `imageable_id`), so a banner can have one or more images instead of fixed `image_id` columns. The featured image is the one with `is_featured` set to true.
102
101
103
102
# Brand\_Category
104
103
@@ -374,7 +373,7 @@ In short: discounts are automatic, per-variety, condition-based price rules. The
374
373
375
374
* Stores images.
376
375
*`path`: Stores the relative path of the images, the absolute path can be specified using the `static_asset` function relative to the CDN.
377
-
*`imageable_type:` used for polymorphic relation Attributes Brand Categories
376
+
*`imageable_type:` used for polymorphic relation Attributes, Brand, Categories, Products, Banners
378
377
*`imageable_id:` used for polymorphic relation
379
378
*`created_at`: Specifies the record creation date.
380
379
@@ -818,9 +817,10 @@ For storing user permissions and removing role-based permissions.
818
817
819
818
Contains product variations entered by the seller on the site. This table creates a record depending on the selected variation and price.
820
819
821
-
*`product_id`: Indicates which product this variety belongs to. Foreign key to `products`; cascades on product delete.
822
-
*`attribute_value`: Free-text value of the selected variation (e.g., "Red", "8GB"). Currently not linked to the `attributes` table.
823
-
*`color`: Optional color value for the variation.
820
+
*`product_id`: Indicates which product this variety belongs to. Foreign key to `products`; cascades on product delete.
821
+
*`attribute_id`: Links to the `attributes` table - the specific attribute that defines this variety (e.g. "Red", "XL"). Nullable FK; set to null when the attribute is deleted. When set, `attribute_value` and `color` are auto-populated from the linked attribute via model saving event.
822
+
*`attribute_value`: Display label for the variation, auto-populated from `attribute.value` when `attribute_id` is set. Can also be set manually when no attribute is linked.
823
+
*`color`: Hex or name color for the variation, auto-populated from `attribute.color` when `attribute_id` is set.
824
824
*`price`
825
825
*`sale_price`
826
826
*`inventory`: Number of ShopFlow inventory, the default value is 0\.
protected ?string$subheading = 'Links an attribute group to a category. This tells the system which attributes are relevant for products in that category. Use "As Filter" to show the group as a filter panel on the category page, and "Required" to force admins to pick an attribute from this group when creating a product in that category.';
protected ?string$subheading = 'An attribute group is a set of attributes that share a common property (e.g. "Color" contains Red, Blue, Green). Each group belongs to an ancestor and is linked to categories via Attribute Group Categories. Products then use a group to define their variety differentiator.';
0 commit comments