Files
mercadodevida/work/artifacts/F-071/architect.md
2026-08-19 19:04:41 +02:00

88 lines
3.8 KiB
Markdown

# F-071 — Architecture: Editable emoji and color for categories
## Problem
The frontend uses **hardcoded** emoji/color maps keyed by category slug:
- `project/frontend/src/components/home/CategoriesGrid.tsx``icons` map + `colors` array
- `project/frontend/src/app/categories/page.tsx``icons` map + `colors` array
The admin category editor (`project/apps/admin/src/app/(dashboard)/categories/page.tsx`)
shows a generic 📁 folder icon for parent categories and has **no** emoji/color fields.
New parent categories therefore show the folder instead of an identifying emoji.
## Design
### 1. Database schema (migration 030)
```sql
ALTER TABLE categories_categories
ADD COLUMN emoji VARCHAR(10) NULL DEFAULT NULL,
ADD COLUMN color TEXT NULL DEFAULT NULL;
```
- `emoji VARCHAR(10)`: a single emoji unicode character (with potential variation selectors). Nullable so existing categories are unaffected.
- `color TEXT`: stores a Tailwind gradient class string, e.g. `from-[#70ad47] to-[#40916C]`. Nullable. Storing the class string keeps it simple and consistent with the existing `categories/page.tsx` `colors` array format.
Both columns are nullable with NULL default → zero-downtime, no data migration needed for existing rows.
### 2. Backend domain
`project/src/modules/categories/domain/category.ts`:
- Add `emoji?: string | null` and `color?: string | null` to `Category`, `NewCategory`, `CategoryPatch`.
### 3. Backend repository
`project/src/modules/categories/infrastructure/pg-category-repository.ts`:
- Add `emoji: string | null` and `color: string | null` to `CategoryRow`.
- Add `['emoji', 'emoji']` and `['color', 'color']` to `UPDATABLE`.
- Add emoji/color to the INSERT statement.
- Map emoji/color in `toCategory()`.
### 4. Backend API routes
`project/src/modules/categories/api/categories.routes.ts`:
- Add `emoji: z.string().max(10).optional().nullable()` and `color: z.string().max(200).optional().nullable()` to `newCategorySchema`.
- Add `emoji` and `color` to `serializeCategory()` output.
### 5. Frontend types
`project/frontend/src/types/api.ts`:
- Add `emoji?: string` and `color?: string` to the `Category` interface.
### 6. Frontend — CategoriesGrid + CategoriesPage
- Replace hardcoded `icons[cat.slug] ?? '📦'` with `cat.emoji ?? fallbackIcons[cat.slug] ?? '📦'`.
- Replace hardcoded `colors[i % colors.length]` gradient with `cat.color ?? colors[i % colors.length]` — keeps existing visual behavior for categories without stored color.
### 7. Admin — types + form
`project/apps/admin/src/types/index.ts`:
- Add `emoji?: string` and `color?: string` to `Category`.
`project/apps/admin/src/app/(dashboard)/categories/page.tsx`:
- Add `emoji` and `color` to `FormState`.
- Add emoji input (text) and color input (text input for Tailwind class, with placeholder examples) to the form UI.
- Include emoji/color in the save payload.
- In `CategoryRow`, replace the hardcoded 📁 with `cat.emoji ?? '📁'`.
### 8. Storefront
`project/storefront/src/lib/api.ts`:
- Add `emoji?: string | null` and `color?: string | null` to `CategoryDto`.
`project/storefront/src/app/categoria/[slug]/page.tsx`:
- Optionally render the emoji in the header if present.
## Data flow
```
Admin form → PATCH /api/categories/:id → backend serializes → DB stores
GET /categories/tree → backend returns emoji+color → frontend renders
```
## Risks
- **Low**: All new columns are nullable; existing categories keep working.
- The `color` field stores a CSS class string, not a sanitized color value. Admin input is validated by `z.string().max(200)`. A malicious class value is a cosmetic (not security) concern — it's rendered via `className` which React sanitizes against script injection.
- Backward compatibility: `emoji` and `color` default to `null` → UI falls back to hardcoded maps.