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