3.8 KiB
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—iconsmap +colorsarrayproject/frontend/src/app/categories/page.tsx—iconsmap +colorsarray
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)
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 existingcategories/page.tsxcolorsarray 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 | nullandcolor?: string | nulltoCategory,NewCategory,CategoryPatch.
3. Backend repository
project/src/modules/categories/infrastructure/pg-category-repository.ts:
- Add
emoji: string | nullandcolor: string | nulltoCategoryRow. - Add
['emoji', 'emoji']and['color', 'color']toUPDATABLE. - 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()andcolor: z.string().max(200).optional().nullable()tonewCategorySchema. - Add
emojiandcolortoserializeCategory()output.
5. Frontend types
project/frontend/src/types/api.ts:
- Add
emoji?: stringandcolor?: stringto theCategoryinterface.
6. Frontend — CategoriesGrid + CategoriesPage
- Replace hardcoded
icons[cat.slug] ?? '📦'withcat.emoji ?? fallbackIcons[cat.slug] ?? '📦'. - Replace hardcoded
colors[i % colors.length]gradient withcat.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?: stringandcolor?: stringtoCategory.
project/apps/admin/src/app/(dashboard)/categories/page.tsx:
- Add
emojiandcolortoFormState. - 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 📁 withcat.emoji ?? '📁'.
8. Storefront
project/storefront/src/lib/api.ts:
- Add
emoji?: string | nullandcolor?: string | nulltoCategoryDto.
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
colorfield stores a CSS class string, not a sanitized color value. Admin input is validated byz.string().max(200). A malicious class value is a cosmetic (not security) concern — it's rendered viaclassNamewhich React sanitizes against script injection. - Backward compatibility:
emojiandcolordefault tonull→ UI falls back to hardcoded maps.