# 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.
