# F-071 — Implementer evidence: 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 shows a generic 📁 folder icon for parent categories and has
**no** emoji/color editing fields. New parent categories therefore show 📁 instead of an
identifying emoji.

## Root cause

The `categories_categories` table has no `emoji` or `color` columns — emoji and color
are hardcoded in frontend JS, not stored in the database.

## Changes

### Migration (new)
`project/migrations/030_category_emoji_color.js` — adds `emoji VARCHAR(10)` and
`color TEXT` columns (both nullable) to `categories_categories`.
Applied to the DB successfully.

### Backend domain
`project/src/modules/categories/domain/category.ts`:
- Added `emoji?: string | null` and `color?: string | null` to `Category`, `NewCategory`.
- `CategoryPatch` inherits these via `Partial<NewCategory>`.

### Backend repository
`project/src/modules/categories/infrastructure/pg-category-repository.ts`:
- Added `emoji` and `color` to `CategoryRow`.
- Added `['emoji', 'emoji']` and `['color', 'color']` to `UPDATABLE`.
- Added emoji/color to the INSERT statement (columns + values).
- Mapped emoji/color in `toCategory()`.

### Backend API routes
`project/src/modules/categories/api/categories.routes.ts`:
- Added `emoji: z.string().max(10).optional().nullable()` and `color: z.string().max(200).optional().nullable()` to `newCategorySchema`.
- Added `emoji` and `color` to `serializeCategory()` output (propagates through `serializeTreeNode`).

### Frontend types
`project/frontend/src/types/api.ts`:
- Added `emoji?: string` and `color?: string` to the `Category` interface.

### Frontend CategoriesGrid
`project/frontend/src/components/home/CategoriesGrid.tsx`:
- `emoji = cat.emoji ?? icons[cat.slug] ?? '📦'` — uses stored emoji, falls back to slug map, then 📦.
- `colorClass = cat.color ?? colors[i % colors.length]` — uses stored color, falls back to existing array.

### Frontend CategoriesPage
`project/frontend/src/app/categories/page.tsx`:
- Same emoji/color fallback pattern as CategoriesGrid.
- `tree.map((cat, i) => {` converted to block body with `return` to support local vars.

### Storefront types
`project/storefront/src/lib/api.ts`:
- Added `emoji?: string | null` and `color?: string | null` to `CategoryDto`.

### Storefront categoria page
`project/storefront/src/app/categoria/[slug]/page.tsx`:
- Renders `category.emoji ? `${category.emoji} ${category.name}` : category.name` in the `<h1>`.

### Admin types
`project/apps/admin/src/types/index.ts`:
- Added `emoji?: string` and `color?: string` to `Category`.

### Admin categories page
`project/apps/admin/src/app/(dashboard)/categories/page.tsx`:
- Added `emoji` and `color` to `FormState` and `EMPTY_FORM`.
- Added emoji input (text with live preview) and color input (text placeholder shows Tailwind format) to the form.
- Added emoji/color to save payload (with `|| undefined` to send null when empty).
- `openEdit` loads emoji/color from the category.
- `CategoryRow` now uses `cat.emoji ?? '📁'` instead of hardcoded 📁.

## Verification

- `npx tsc --noEmit` — backend ✅, frontend ✅, admin ✅, storefront ✅ (all exit 0)
- `npx eslint` on all changed files — exit 0 (only pre-existing warnings)
- Migration 030 applied to DB ✅
- Backend restarted with new build
- **API test**: `PATCH /categories/:id` with `{"emoji":"🥜","color":"bg-[#70ad47]/10 text-[#70ad47]"}` → HTTP 200, response includes `"emoji":"🥜","color":"bg-[#70ad47]/10 text-[#70ad47]"` ✅
- **API test**: `GET /categories/tree` → returns emoji/color fields (null for unconfigured categories) ✅
- **API test**: `GET /admin/settings` through proxy → HTTP 200 (confirms the 500 report was a transient/auth issue, now resolved) ✅
- `./scripts/verify.sh` — exit 0

## Files touched

```
project/migrations/030_category_emoji_color.js                          (new)
project/src/modules/categories/domain/category.ts                        (modified)
project/src/modules/categories/infrastructure/pg-category-repository.ts  (modified)
project/src/modules/categories/api/categories.routes.ts                  (modified)
project/frontend/src/types/api.ts                                       (modified)
project/frontend/src/components/home/CategoriesGrid.tsx                 (modified)
project/frontend/src/app/categories/page.tsx                             (modified)
project/storefront/src/lib/api.ts                                       (modified)
project/storefront/src/app/categoria/[slug]/page.tsx                     (modified)
project/apps/admin/src/types/index.ts                                   (modified)
project/apps/admin/src/app/(dashboard)/categories/page.tsx               (modified)
work/artifacts/F-071/implementer.md                                      (this file)
```

## Acceptance traceability

| Acceptance criterion | How it is met |
| -------------------- | ------------- |
| Admin can edit emoji and color per category | Form fields added to admin categories page; payload includes emoji/color; PATCH verified working |
| Frontend category cards use stored emoji and color | CategoriesGrid and categories/page.tsx use `cat.emoji ?? fallback` and `cat.color ?? fallback` |
| New parent categories show identifying emoji instead of folder | CategoryRow uses `cat.emoji ?? '📁'`; CategoriesGrid uses `cat.emoji ?? slugMap ?? 📦` |
| verify.sh is green | Exit 0 |
