feat(ADM-018): completed feature
This commit is contained in:
183
project/specs/brand-migration/BRAND_INVENTORY.md
Normal file
183
project/specs/brand-migration/BRAND_INVENTORY.md
Normal file
@@ -0,0 +1,183 @@
|
||||
# BRAND INVENTORY — MercadoDeVida
|
||||
|
||||
**Source**: https://mercadodevida.es
|
||||
**Inspected**: 2026-08-17
|
||||
**Status**: INCOMPLETE — CSS not yet extracted from legacy site
|
||||
|
||||
---
|
||||
|
||||
## To Extract Before Implementation
|
||||
|
||||
### 1. CSS Stylesheet
|
||||
|
||||
Fetch from the legacy site source. Common paths to try:
|
||||
- `/catalog/view/theme/journal3/stylesheet/stylesheet.css`
|
||||
- `/catalog/view/theme/default/stylesheet/stylesheet.css`
|
||||
- `/styles.css`
|
||||
- Inline `<style>` tags in page source
|
||||
|
||||
Extract all CSS custom properties (variables) or color values:
|
||||
- Primary color (likely green/teal)
|
||||
- Accent color (likely terracotta/coral)
|
||||
- Background colors
|
||||
- Text colors
|
||||
- Link colors
|
||||
- Border colors
|
||||
|
||||
### 2. Logo
|
||||
|
||||
Search for logo image sources in page HTML:
|
||||
```bash
|
||||
curl -s https://mercadodevida.es | grep -i "logo"
|
||||
```
|
||||
|
||||
The logo file name is unknown. Common paths to try:
|
||||
- `/image/logo.png`
|
||||
- `/image/Logo-Mdv.png`
|
||||
- `/image/data/logo.png`
|
||||
- `/image/catalog/logo.png`
|
||||
|
||||
Download the highest quality version available.
|
||||
|
||||
### 3. Favicon
|
||||
|
||||
Check for:
|
||||
- `/favicon.ico`
|
||||
- `/image/favicon.ico`
|
||||
- `<link rel="icon">` in HTML head
|
||||
|
||||
---
|
||||
|
||||
## Known Information
|
||||
|
||||
### Company
|
||||
- **Full name**: Natural - Mercado de Vida
|
||||
- **Short name**: MercadoDeVida
|
||||
- **Type**: Supermercado ecológico online
|
||||
- **Location**: Estepona, Costa del Sol, España
|
||||
- **Founders**: Ivana & Ricardo
|
||||
- **Since**: Not specified in public content
|
||||
|
||||
### Contact
|
||||
| Field | Value |
|
||||
|-------|-------|
|
||||
| Address | Av. Litoral - Edif. Vistamar II - Local 18, 29680 Estepona - Málaga |
|
||||
| Phone | +34 951 338 132 |
|
||||
| WhatsApp | +34 676 014 074 |
|
||||
| Email | info@mercadodevida.es |
|
||||
|
||||
### Hours
|
||||
```
|
||||
Lunes a Viernes: 10:00 – 18:00
|
||||
Sábado: 10:00 – 14:00
|
||||
```
|
||||
|
||||
### Social (URLs not confirmed)
|
||||
- Instagram link (in footer)
|
||||
- Facebook link (in footer)
|
||||
- Twitter link (in footer)
|
||||
|
||||
### Legacy Site Technology
|
||||
OpenCart-based (evidenced by `?route=` URL patterns in robots.txt disallows).
|
||||
|
||||
---
|
||||
|
||||
## Extracted Page Content
|
||||
|
||||
### /quienes-somos (About Us)
|
||||
|
||||
**Source**: https://mercadodevida.es/quienes-somos
|
||||
|
||||
**Content**:
|
||||
> Hola! Somos Ivana & Ricardo y te invitamos a conocer Natural - Mercado de Vida
|
||||
>
|
||||
> Nuestra empresa se creo con la idea de un mundo mas sostenible y concientizada en un consumo responsable. En Natural - Mercado de Vida, investigamos el mercado para ofrecer en nuestra establecimiento los mejores y mas novedosos productos ecológicos, y de medicina natural, con los mejores precios y la mayor calidad. Pero también intentamos acercar nuestra selección a todos los rincones de España... y en un futuro no muy lejano a Europa.
|
||||
>
|
||||
> Creemos en un mundo mas coherente con el medio ambiente y confiamos que esto será posible de la mano de un consumo mas responsable y acorde a las necesidades, primando el bienestar común al individual, eligiendo calidad y buen hacer.
|
||||
>
|
||||
> En Natural - Mercado de Vida, Estepona, te ofrecemos un mundo de productos ecológicos y naturales a la distancia de un click.
|
||||
>
|
||||
> Somos el primer Supermercado Ecológico online en la Costa del Sol, desde Estepona para Sotogrande, Marbella, Málaga y toda España, poniendo el corazón y las ganas de mejorar el mundo.
|
||||
>
|
||||
> Invitamos a nuestros clientes a compartir nuestras experiencias y recetas para mejorar nuestra relación con el medio ambiente.
|
||||
|
||||
**Note**: Legacy text contains spelling/grammar issues (e.g., "concientizada", "distancía", "mas"). Migration preserves text faithfully. Flag for human review.
|
||||
|
||||
### /contacto (Contact)
|
||||
|
||||
**Source**: https://mercadodevida.es/contacto
|
||||
|
||||
**Content**:
|
||||
> Contact us: +34 951 338 132
|
||||
> Envíanos un Whatsapp: +34 676 014 074
|
||||
> info@mercadodevida.es
|
||||
|
||||
**Form**: Legacy OpenCart contact form. New platform needs contact form or mailto link.
|
||||
|
||||
### /terminos-y-condiciones (Terms)
|
||||
|
||||
**Source**: https://mercadodevida.es/terminos-y-condiciones
|
||||
|
||||
**Content**: Full legal text covering:
|
||||
- Ley 7/1998 Condiciones Generales de Contratación
|
||||
- Ley 26/1984 Defensa Consumidores y Usuarios
|
||||
- Real Decreto 1906/1999 Contratación Electrónica
|
||||
- Ley Orgánica 15/1999 Protección de Datos (LOPD — LEGACY, needs updating to RGPD/LOPDGDD)
|
||||
- Ley 7/1996 Ordenación Comercio Minorista
|
||||
- Ley 34/2002 Servicios Sociedad Información y Comercio Electrónico (LSSI)
|
||||
|
||||
**⚠️ Legal flag**: LOPD (1999) referenced — Spain's current data protection law is RGPD/LOPDGDD 2018. Legal review required before publishing as-is.
|
||||
|
||||
### /politica-de-cookies (Cookie Policy)
|
||||
|
||||
**Source**: 404 on legacy. Create new policy based on RGPD requirements.
|
||||
|
||||
### /politica-de-privacidad (Privacy)
|
||||
|
||||
**Source**: 404 on legacy. Needs creation.
|
||||
|
||||
### /envios-y-formas-de-pago (Shipping & Payment)
|
||||
|
||||
**Source**: 404 on legacy. Content needs creation. Use existing new platform's /shipping page as baseline, add payment methods.
|
||||
|
||||
---
|
||||
|
||||
## Existing Design Tokens (from new platform)
|
||||
|
||||
These are the CURRENT tokens. They may or may not match legacy colors.
|
||||
|
||||
```css
|
||||
/* Frontend */
|
||||
--color-primary: #2D6A4F;
|
||||
--color-primary-dark: #1B4332;
|
||||
--color-primary-light: #40916C;
|
||||
--color-secondary: #F5F0E8;
|
||||
--color-accent: #E76F51;
|
||||
--color-text: #1a1a1a;
|
||||
--color-muted: #6b7280;
|
||||
--font-sans: "Inter", system-ui, sans-serif;
|
||||
--font-heading: "Playfair Display", Georgia, serif;
|
||||
```
|
||||
|
||||
```css
|
||||
/* Admin */
|
||||
--color-primary: #2D6A4F;
|
||||
--color-primary-dark: #1B4332;
|
||||
--color-primary-light: #40916C;
|
||||
--color-accent: #E76F51;
|
||||
--color-text: #111827;
|
||||
--color-muted: #6B7280;
|
||||
--color-bg: #F9FAFB;
|
||||
--color-surface: #FFFFFF;
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Implementation Notes
|
||||
|
||||
1. **Extract legacy CSS** before choosing final token values
|
||||
2. **Download logo** at highest resolution available
|
||||
3. **Check favicon** and generate appropriate formats (ICO, PNG, SVG if available)
|
||||
4. **Business config**: define `BUSINESS_INFO` constant once
|
||||
5. **Legal pages**: do NOT publish legal text without human/legal review
|
||||
6. **Spellchecking**: legacy text has errors — preserve them during migration, flag for review
|
||||
242
project/specs/brand-migration/DESIGN.md
Normal file
242
project/specs/brand-migration/DESIGN.md
Normal file
@@ -0,0 +1,242 @@
|
||||
# BRAND MIGRATION — DESIGN.md
|
||||
|
||||
## 1. Design Token Strategy
|
||||
|
||||
### 1.1 Current State
|
||||
|
||||
Both `frontend/src/app/globals.css` and `apps/admin/src/app/globals.css` use Tailwind `@theme` block:
|
||||
|
||||
```css
|
||||
@theme {
|
||||
--color-primary: #2D6A4F;
|
||||
--color-primary-dark: #1B4332;
|
||||
--color-primary-light: #40916C;
|
||||
--color-secondary: #F5F0E8;
|
||||
--color-accent: #E76F51;
|
||||
--color-text: #111827;
|
||||
--color-muted: #6B7280;
|
||||
--font-sans: "Inter", system-ui, sans-serif;
|
||||
--font-heading: "Playfair Display", Georgia, serif;
|
||||
}
|
||||
```
|
||||
|
||||
### 1.2 Decision Required
|
||||
|
||||
**Extract legacy CSS first** (see BRAND_INVENTORY.md). If legacy colors differ from current tokens, update the `@theme` block. If they match (green primary, terracotta accent), no change needed.
|
||||
|
||||
### 1.3 Token Architecture
|
||||
|
||||
```
|
||||
globals.css @theme
|
||||
│
|
||||
├── Tailwind utility classes auto-generate from @theme
|
||||
│ text-primary, bg-primary, border-primary, etc.
|
||||
│
|
||||
└── All components reference tokens, never raw hex values
|
||||
✅ text-[var(--color-primary)] / bg-[var(--color-accent)]
|
||||
❌ text-[#2D6A4F] scattered in JSX
|
||||
```
|
||||
|
||||
If any component uses a raw hex value matching a brand color, refactor to use the token.
|
||||
|
||||
## 2. Business Configuration
|
||||
|
||||
### 2.1 Single Source of Truth
|
||||
|
||||
Create `frontend/src/lib/businessConfig.ts`:
|
||||
|
||||
```typescript
|
||||
export const BUSINESS_CONFIG = {
|
||||
name: 'Natural - Mercado de Vida',
|
||||
shortName: 'MercadoDeVida',
|
||||
founders: 'Ivana & Ricardo',
|
||||
address: {
|
||||
street: 'Av. Litoral - Edif. Vistamar II - Local 18',
|
||||
postalCode: '29680',
|
||||
city: 'Estepona',
|
||||
province: 'Málaga',
|
||||
country: 'España',
|
||||
},
|
||||
phone: '+34 951 338 132',
|
||||
whatsapp: '+34 676 014 074',
|
||||
email: 'info@mercadodevida.es',
|
||||
hours: {
|
||||
weekdays: '10:00 – 18:00',
|
||||
saturday: '10:00 – 14:00',
|
||||
},
|
||||
social: {
|
||||
instagram: null, // TODO: extract from legacy site
|
||||
facebook: null, // TODO: extract from legacy site
|
||||
},
|
||||
website: 'https://mercadodevida.es',
|
||||
} as const;
|
||||
|
||||
export type BusinessConfig = typeof BUSINESS_CONFIG;
|
||||
```
|
||||
|
||||
### 2.2 Usage Points
|
||||
|
||||
```typescript
|
||||
import { BUSINESS_CONFIG } from '@/lib/businessConfig';
|
||||
|
||||
// Footer
|
||||
<span>{BUSINESS_CONFIG.name}</span>
|
||||
<span>{BUSINESS_CONFIG.address.city}</span>
|
||||
|
||||
// Contact page
|
||||
<a href={`tel:${BUSINESS_CONFIG.phone}`}>{BUSINESS_CONFIG.phone}</a>
|
||||
<a href={`mailto:${BUSINESS_CONFIG.email}`}>{BUSINESS_CONFIG.email}</a>
|
||||
|
||||
// About page
|
||||
<p>Somos {BUSINESS_CONFIG.founders}...</p>
|
||||
|
||||
// Checkout confirmation
|
||||
<p>{BUSINESS_CONFIG.address.street}, {BUSINESS_CONFIG.address.postalCode} {BUSINESS_CONFIG.address.city}</p>
|
||||
```
|
||||
|
||||
Do NOT duplicate any of these values anywhere else.
|
||||
|
||||
## 3. Logo
|
||||
|
||||
### 3.1 Source Asset
|
||||
|
||||
Download from legacy site. See BRAND_INVENTORY.md.
|
||||
|
||||
### 3.2 Placement
|
||||
|
||||
```
|
||||
Storefront Header
|
||||
└── Logo → /public/images/logo.svg (or .png)
|
||||
└── Also used in Admin sidebar
|
||||
|
||||
Storefront Footer
|
||||
└── Logo (same asset)
|
||||
|
||||
Favicon
|
||||
└── /public/favicon.ico
|
||||
└── Also /public/apple-touch-icon.png
|
||||
```
|
||||
|
||||
### 3.3 Next.js Metadata
|
||||
|
||||
In `frontend/src/app/layout.tsx`:
|
||||
```typescript
|
||||
import { BUSINESS_CONFIG } from '@/lib/businessConfig';
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: { default: BUSINESS_CONFIG.name, template: `%s | ${BUSINESS_CONFIG.name}` },
|
||||
metadataBase: new URL(BUSINESS_CONFIG.website),
|
||||
};
|
||||
```
|
||||
|
||||
## 4. Static Pages Content
|
||||
|
||||
### 4.1 Architecture Decision
|
||||
|
||||
For 5–7 informational pages, typed static React components are acceptable.
|
||||
|
||||
The existing `ContentPage` component (`frontend/src/components/content/ContentPage.tsx`) should be evaluated:
|
||||
- Does it support all needed HTML elements (tables, lists, headings, blockquotes)?
|
||||
- Does it support linking to business config data?
|
||||
|
||||
If rich layout is needed for complex pages (e.g., terms with sections), consider:
|
||||
- Markdown/MDX files processed at build time
|
||||
- Single `ContentPage` component that renders parsed markdown
|
||||
|
||||
### 4.2 Page Content Plan
|
||||
|
||||
| Page | Route | Source | Status |
|
||||
|------|-------|--------|--------|
|
||||
| About | /about | /quienes-somos (migrated) | See BRAND_INVENTORY.md |
|
||||
| Contact | /contact | /contacto (partial) | Needs form + hours |
|
||||
| Shipping | /shipping | New + legacy /envios-y-formas-de-pago (404) | Create from scratch |
|
||||
| Terms | /terms | /terminos-y-condiciones (migrated) | Needs legal review |
|
||||
| Privacy | /privacy | New (legacy 404) | Create from scratch |
|
||||
| Cookies | /cookies | New (legacy 404) | Create from scratch |
|
||||
| Legal | /legal | New (no legacy) | Create if needed |
|
||||
|
||||
### 4.3 Legal Content Flag
|
||||
|
||||
All legal pages (Terms, Privacy, Cookies) must be flagged:
|
||||
```
|
||||
⚠️ MIGRATED LEGAL CONTENT — REQUIRES HUMAN REVIEW BEFORE PUBLISHING
|
||||
```
|
||||
|
||||
Do not mark migrated legal text as newly legally approved.
|
||||
|
||||
## 5. SEO Redirects
|
||||
|
||||
### 5.1 Implementation
|
||||
|
||||
In `frontend/next.config.ts`:
|
||||
|
||||
```typescript
|
||||
import type { NextConfig } from 'next';
|
||||
|
||||
const nextConfig: NextConfig = {
|
||||
async redirects() {
|
||||
return [
|
||||
// Static pages
|
||||
{ source: '/quienes-somos', destination: '/about', permanent: true },
|
||||
{ source: '/contacto', destination: '/contact', permanent: true },
|
||||
{ source: '/terminos-y-condiciones', destination: '/terms', permanent: true },
|
||||
{ source: '/politica-de-cookies', destination: '/cookies', permanent: true },
|
||||
{ source: '/politica-de-privacidad', destination: '/privacy', permanent: true },
|
||||
{ source: '/donde-estamos', destination: '/contact', permanent: true },
|
||||
{ source: '/aviso-legal', destination: '/legal', permanent: true },
|
||||
|
||||
// OpenCart internals — block
|
||||
{ source: '/admin/:path*', destination: '/404', permanent: false },
|
||||
|
||||
// Catch-all for OpenCart query strings — these should not reach the app
|
||||
{ source: '/:path*', has: [{ type: 'query', key: 'route' }], destination: '/404', permanent: false },
|
||||
];
|
||||
},
|
||||
};
|
||||
```
|
||||
|
||||
### 5.2 Category Redirects
|
||||
|
||||
Complete the redirect map from LEGACY_REDIRECT_MAP.md before implementing.
|
||||
|
||||
### 5.3 Product Redirects
|
||||
|
||||
Evaluate Option A vs Option B from LEGACY_REDIRECT_MAP.md before implementing.
|
||||
|
||||
## 6. Admin Branding
|
||||
|
||||
### 6.1 Logo
|
||||
|
||||
Use the same logo file as storefront. Simplified/smaller version acceptable.
|
||||
|
||||
In `apps/admin/src/app/(dashboard)/layout.tsx`, the sidebar currently shows an inline SVG. Replace with the actual logo image.
|
||||
|
||||
### 6.2 Token Alignment
|
||||
|
||||
Admin should use the same `--color-primary` token as storefront. Verify the admin `globals.css` tokens match storefront. Currently they do (both use `#2D6A4F`).
|
||||
|
||||
### 6.3 NOT Changed
|
||||
|
||||
- Admin table styling (operational, not brand-focused)
|
||||
- Admin form components
|
||||
- Admin typography (keep Inter for data-dense UIs)
|
||||
|
||||
## 7. Header Component
|
||||
|
||||
Review `frontend/src/components/layout/Header.tsx`:
|
||||
|
||||
- Logo: use `BUSINESS_CONFIG.shortName` for text fallback
|
||||
- Nav links: About, Contact, Categories, etc.
|
||||
- Ensure no hardcoded company name/address
|
||||
|
||||
## 8. Footer Component
|
||||
|
||||
Review `frontend/src/components/layout/Footer.tsx`:
|
||||
|
||||
- Use `BUSINESS_CONFIG.name` for brand name
|
||||
- Use `BUSINESS_CONFIG.address` for address
|
||||
- Use `BUSINESS_CONFIG.phone`, `BUSINESS_CONFIG.email`
|
||||
- Use `BUSINESS_CONFIG.hours`
|
||||
- Social links from `BUSINESS_CONFIG.social`
|
||||
- Legal links: Terms, Privacy, Cookies
|
||||
- Copyright year dynamic: `{new Date().getFullYear()}`
|
||||
162
project/specs/brand-migration/LEGACY_REDIRECT_MAP.md
Normal file
162
project/specs/brand-migration/LEGACY_REDIRECT_MAP.md
Normal file
@@ -0,0 +1,162 @@
|
||||
# LEGACY REDIRECT MAP — mercadodevida.es → new-mercadodevida
|
||||
|
||||
**Legacy site**: OpenCart-based (evidenced by `?route=` URL patterns)
|
||||
**New site**: Next.js App Router
|
||||
**Status**: PARTIAL — requires completion after legacy site full audit
|
||||
|
||||
---
|
||||
|
||||
## How to Complete This Map
|
||||
|
||||
1. Fetch the full sitemap: `https://mercadodevida.es/sitemap.xml`
|
||||
2. Fetch the homepage and parse all footer/navigation links
|
||||
3. Check robots.txt disallows for route patterns
|
||||
4. Map each discovered URL to its new equivalent
|
||||
|
||||
---
|
||||
|
||||
## Confirmed Redirects
|
||||
|
||||
| Legacy URL | New URL | Type | Status |
|
||||
|-----------|---------|------|--------|
|
||||
| `/quienes-somos` | `/about` | 308 | Confirmed from page content |
|
||||
| `/quienes-somos` | `/about` | 308 | Confirmed from sitemap/links |
|
||||
| `/contacto` | `/contact` | 308 | Confirmed from links |
|
||||
| `/terminos-y-condiciones` | `/terms` | 308 | Confirmed from sitemap |
|
||||
| `/politica-de-cookies` | `/cookies` | 308 | New route; no legacy page found (404) |
|
||||
| `/politica-de-privacidad` | `/privacy` | 308 | New route; no legacy page found (404) |
|
||||
|
||||
---
|
||||
|
||||
## Product Redirects (from sitemap)
|
||||
|
||||
All product pages use slug format: `/[product-name-slug]`
|
||||
|
||||
From sitemap, product slugs look like:
|
||||
```
|
||||
/alga-dulse-hojas-100-gr-algamar
|
||||
/arroz-lentejas-algas-eco-500-gr-algamar
|
||||
/crema-de-cacahuetes-330gr-bio-monki
|
||||
/semillas-de-calabaza-bio-250gr-el-granero-integral
|
||||
/tahini-crema-de-sesamo-bio-340-gr-granovita
|
||||
```
|
||||
|
||||
**Strategy**: 308 redirect ALL legacy product slugs to `/products/[slug]`
|
||||
|
||||
The new platform's product slugs may differ. Two approaches:
|
||||
|
||||
### Option A: Keep legacy slugs as canonical
|
||||
- New platform generates slugs from product names
|
||||
- If a legacy slug matches, it becomes the new canonical slug
|
||||
- Redirect from legacy slug to new slug
|
||||
|
||||
### Option B: 308 everything to /products
|
||||
- All legacy product URLs → `/products`
|
||||
- User searches from there
|
||||
- Simpler but loses SEO equity
|
||||
|
||||
**Recommended**: Option A if new product slugs can be configured. Otherwise Option B.
|
||||
|
||||
---
|
||||
|
||||
## Category Redirects
|
||||
|
||||
Legacy OpenCart category URLs use `?route=product/category&path=N` pattern.
|
||||
|
||||
From homepage navigation (extracted from page HTML):
|
||||
```
|
||||
/alimentacion
|
||||
/aceites-y-vinagres
|
||||
/azucares-y-endulzantes
|
||||
/bebidas
|
||||
/cereales-y-harinas
|
||||
/chocolates-y-dulces
|
||||
/especias-y-condimentos
|
||||
/frutos-secos-y-semillas
|
||||
/infantil
|
||||
/infusiones-y-te
|
||||
/legumbres
|
||||
/macbiotica
|
||||
/panaderia-y-galletas
|
||||
/pastas-y-arrozes
|
||||
/snacks
|
||||
/cosmetica
|
||||
/aseo-personal
|
||||
/bebes-y-ninos
|
||||
/corporal
|
||||
/facial
|
||||
/herbolario
|
||||
/hogar
|
||||
/mascotas
|
||||
/libros
|
||||
/superfood
|
||||
```
|
||||
|
||||
**Strategy**: 308 redirect each legacy category slug to `/categories/[slug]`
|
||||
|
||||
---
|
||||
|
||||
## Static Pages Not Yet Confirmed
|
||||
|
||||
| Legacy URL | New URL | Type | Status |
|
||||
|-----------|---------|------|--------|
|
||||
| `/aviso-legal` | `/legal` | 308? | Not confirmed |
|
||||
| `/envios-y-formas-de-pago` | `/shipping` | 308? | Legacy page 404 |
|
||||
| `/donde-estamos` | `/contact` | 308? | Fragment of /contact |
|
||||
|
||||
---
|
||||
|
||||
## OpenCart Route Patterns (from robots.txt)
|
||||
|
||||
```
|
||||
Disallow: /*?sort
|
||||
Disallow: /*&sort
|
||||
Disallow: /*?limit
|
||||
Disallow: /*&limit
|
||||
Disallow: /*?route=checkout
|
||||
Disallow: /*?route=account
|
||||
Disallow: /*?route=product/search
|
||||
Disallow: /*&keyword
|
||||
```
|
||||
|
||||
These patterns should return 410 Gone (OpenCart internals, not migrated).
|
||||
|
||||
---
|
||||
|
||||
## Implementation
|
||||
|
||||
In Next.js, redirects are configured in `next.config.ts`:
|
||||
|
||||
```typescript
|
||||
// frontend/next.config.ts
|
||||
{
|
||||
async redirects() {
|
||||
return [
|
||||
// Products
|
||||
{ source: '/:slug', has: [{ type: 'query', key: 'route', value: 'product/product' }], destination: '/products/:slug', permanent: true },
|
||||
|
||||
// Categories
|
||||
{ source: '/:slug', has: [{ type: 'query', key: 'route', value: 'product/category' }], destination: '/categories/:slug', permanent: true },
|
||||
|
||||
// Static pages
|
||||
{ source: '/quienes-somos', destination: '/about', permanent: true },
|
||||
{ source: '/contacto', destination: '/contact', permanent: true },
|
||||
{ source: '/terminos-y-condiciones', destination: '/terms', permanent: true },
|
||||
{ source: '/politica-de-cookies', destination: '/cookies', permanent: true },
|
||||
{ source: '/politica-de-privacidad', destination: '/privacy', permanent: true },
|
||||
|
||||
// Block OpenCart internals
|
||||
{ source: '/admin/:path*', destination: '/404', permanent: false },
|
||||
];
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## SEO Equity Notes
|
||||
|
||||
- 308 (Permanent Redirect) preserves most SEO equity
|
||||
- All redirects must be in place before legacy site goes offline
|
||||
- Submit updated sitemap to Google Search Console after migration
|
||||
- Monitor 404 errors in Search Console for 30 days post-migration
|
||||
161
project/specs/brand-migration/SPEC.md
Normal file
161
project/specs/brand-migration/SPEC.md
Normal file
@@ -0,0 +1,161 @@
|
||||
# BRAND MIGRATION — SPEC.md
|
||||
|
||||
## 1. Concept & Vision
|
||||
|
||||
MercadoDeVida ("Natural - Mercado de Vida") is a Costa del Sol-based online organic supermarket founded by Ivana & Ricardo, serving all of Spain. The brand identity comes from the legacy site (mercadodevida.es). The new platform must faithfully adopt the established brand identity — colors, typography, company information, and approved content — without inventing or approximating.
|
||||
|
||||
**Rule: INSPECT, DO NOT INVENT. MIGRATE, DO NOT REWRITE.**
|
||||
|
||||
## 2. Source of Truth
|
||||
|
||||
**Legacy site**: https://mercadodevida.es
|
||||
**Legacy sitemap**: https://mercadodevida.es/sitemap.xml
|
||||
|
||||
All visual assets, colors, and content come from the legacy site. No AI approximation.
|
||||
|
||||
## 3. Company Identity
|
||||
|
||||
### 3.1 Official Business Name
|
||||
|
||||
```
|
||||
Primary: Natural - Mercado de Vida
|
||||
Abbreviated: MercadoDeVida
|
||||
```
|
||||
|
||||
### 3.2 Founders
|
||||
|
||||
```
|
||||
Ivana & Ricardo
|
||||
```
|
||||
|
||||
### 3.3 Contact Information
|
||||
|
||||
| Field | Value |
|
||||
|-------|-------|
|
||||
| Address | Av. Litoral - Edif. Vistamar II - Local 18, 29680 Estepona - Málaga |
|
||||
| Phone | +34 951 338 132 |
|
||||
| WhatsApp | +34 676 014 074 |
|
||||
| Email | info@mercadodevida.es |
|
||||
|
||||
### 3.4 Business Hours
|
||||
|
||||
```
|
||||
Monday–Friday: 10:00 – 18:00
|
||||
Saturday: 10:00 – 14:00
|
||||
```
|
||||
|
||||
### 3.5 Geographic Scope
|
||||
|
||||
Serving all of Spain (peninsular). First Costa del Sol: Estepona, Sotogrande, Marbella, Málaga.
|
||||
|
||||
### 3.6 Social Links
|
||||
|
||||
| Platform | Handle/Lookup |
|
||||
|---------|---------------|
|
||||
| Instagram | Siguenos en Instagram (URL to be confirmed) |
|
||||
| Facebook | Siguenos en Facebook (URL to be confirmed) |
|
||||
|
||||
URLs must be extracted from legacy site HTML. Do not guess.
|
||||
|
||||
## 4. Brand Inventory
|
||||
|
||||
See `BRAND_INVENTORY.md` for complete asset catalog.
|
||||
|
||||
## 5. Color Palette
|
||||
|
||||
Colors extracted from legacy site CSS. Do not eyeball from screenshots.
|
||||
|
||||
See `BRAND_INVENTORY.md` for source URLs and extracted values.
|
||||
|
||||
### Initial Observations
|
||||
|
||||
The legacy site appears to use:
|
||||
- A green/teal primary (matching the existing `#2D6A4F` in the new platform's design tokens)
|
||||
- A terracotta/coral accent
|
||||
- Warm cream/beige backgrounds
|
||||
- Earthy tones consistent with an organic/natural products brand
|
||||
|
||||
Exact CSS values must be extracted from the legacy site's stylesheet. See `BRAND_INVENTORY.md` for instructions.
|
||||
|
||||
## 6. Typography
|
||||
|
||||
**Current new platform**: Inter (sans) + Playfair Display (headings)
|
||||
|
||||
These should be evaluated against the legacy site's actual typography. If the legacy site uses different fonts, update the design tokens accordingly.
|
||||
|
||||
## 7. Information Pages
|
||||
|
||||
### 7.1 Source Content
|
||||
|
||||
| Legacy URL | New Route | Content Status |
|
||||
|-----------|-----------|---------------|
|
||||
| /quienes-somos | /about | Content extracted — see BRAND_INVENTORY.md |
|
||||
| /quienes-somos | /contact | Content extracted — partial |
|
||||
| /envios-y-formas-de-pago | /shipping | 404 on legacy — needs content creation |
|
||||
| /terminos-y-condiciones | /terms | Legal text migrated — needs legal review |
|
||||
| /politica-de-privacidad | /privacy | 404 on legacy — needs content creation |
|
||||
| /politica-de-cookies | /cookies | 404 on legacy — needs content creation |
|
||||
| /aviso-legal | /legal | Not on legacy — may need creation |
|
||||
|
||||
### 7.2 Content Architecture Decision
|
||||
|
||||
**Option A**: Typed static content in React components (current approach, works for simple pages)
|
||||
**Option B**: Markdown/MDX files
|
||||
**Option C**: CMS-backed (backend endpoint)
|
||||
|
||||
For this migration, Option A (typed static content) is acceptable if the new `ContentPage` component supports rich content. If rich content is needed, evaluate Option B.
|
||||
|
||||
Do NOT build a CMS just for five pages.
|
||||
|
||||
### 7.3 Single Source of Truth
|
||||
|
||||
Business information (address, phone, email, WhatsApp, hours) must be defined once and referenced from:
|
||||
- Footer
|
||||
- Contact page
|
||||
- About page
|
||||
- Checkout confirmation
|
||||
- Legal pages
|
||||
|
||||
Create a `businessConfig` constant in `frontend/src/lib/businessConfig.ts` (or existing equivalent). Do NOT duplicate strings.
|
||||
|
||||
## 8. SEO Redirects
|
||||
|
||||
See `LEGACY_REDIRECT_MAP.md` for full redirect map.
|
||||
|
||||
Key principles:
|
||||
- Every indexed legacy URL must either redirect (301/308) or return 410
|
||||
- Product pages: 301 redirect to new slug format
|
||||
- Informational pages: 301 redirect to new routes
|
||||
- Category pages: map legacy OpenCart routes to new category routes
|
||||
|
||||
## 9. Admin Branding
|
||||
|
||||
Admin reuses:
|
||||
- Logo (simplified or same)
|
||||
- Basic brand colors (primary green)
|
||||
|
||||
Admin does NOT need:
|
||||
- Full brand editorial content
|
||||
- Marketing imagery
|
||||
- Consumer-focused styling
|
||||
|
||||
Priority: operational usability. Admin must be clearly part of MercadoDeVida ecosystem without reducing table/form readability.
|
||||
|
||||
## 10. Out of Scope
|
||||
|
||||
- Rebuilding the legacy site functionality
|
||||
- Migrating user accounts
|
||||
- Migrating order history
|
||||
- Migrating product catalog (already done)
|
||||
- Changing domain registrar or DNS
|
||||
- Third-party integrations (Instagram, Facebook)
|
||||
- Payment gateway changes
|
||||
- New marketing pages
|
||||
|
||||
## 11. Feature Flag
|
||||
|
||||
Not required for brand migration. Brand is purely additive.
|
||||
|
||||
## 12. Acceptance Criteria
|
||||
|
||||
See `TESTS.md`.
|
||||
298
project/specs/brand-migration/TASKS.md
Normal file
298
project/specs/brand-migration/TASKS.md
Normal file
@@ -0,0 +1,298 @@
|
||||
# BRAND MIGRATION — TASKS.md
|
||||
|
||||
## Phase 1: Asset Extraction
|
||||
|
||||
### BRAND-FE-001
|
||||
**ID**: BRAND-FE-001
|
||||
**Title**: Extract legacy CSS and brand colors
|
||||
**Goal**: Get exact hex values from mercadodevida.es stylesheet
|
||||
**Why**: Do not approximate brand colors
|
||||
**Dependencies**: None
|
||||
**Applications**: Frontend, Admin
|
||||
**Modules**: Design tokens
|
||||
**Database impact**: None
|
||||
**API contracts**: None
|
||||
**Permissions**: N/A
|
||||
**Implementation**: Inspect legacy site CSS via DevTools or curl; compare with current tokens; update @theme if needed
|
||||
**Tests**: Visual comparison of legacy vs new site colors
|
||||
**Expected blast radius**: Low — purely visual
|
||||
**Definition of Done**: Extracted colors documented in BRAND_INVENTORY.md; any divergence from current tokens identified
|
||||
|
||||
### BRAND-FE-002
|
||||
**ID**: BRAND-FE-002
|
||||
**Title**: Download official logo
|
||||
**Goal**: Get highest quality logo from legacy site
|
||||
**Why**: No AI reconstruction or approximation allowed
|
||||
**Dependencies**: BRAND-FE-001
|
||||
**Applications**: Frontend, Admin
|
||||
**Modules**: Public assets
|
||||
**Database impact**: None
|
||||
**API contracts**: None
|
||||
**Permissions**: N/A
|
||||
**Implementation**: Find logo image URL from legacy HTML; download SVG/PNG; save to /public/images/; generate favicon variants
|
||||
**Tests**: Logo renders at correct size in Header and Footer; favicon loads
|
||||
**Expected blast radius**: Low
|
||||
**Definition of Done**: Logo file exists in /public/images/; renders in Header, Footer, and Admin sidebar
|
||||
|
||||
## Phase 2: Business Configuration
|
||||
|
||||
### BRAND-FE-003
|
||||
**ID**: BRAND-FE-003
|
||||
**Title**: Create businessConfig constant
|
||||
**Goal**: Single source of truth for company information
|
||||
**Why**: No duplicate address/phone/email strings
|
||||
**Dependencies**: BRAND-FE-001
|
||||
**Applications**: Frontend (all pages)
|
||||
**Modules**: frontend/src/lib/businessConfig.ts
|
||||
**Database impact**: None
|
||||
**API contracts**: None
|
||||
**Permissions**: N/A
|
||||
**Implementation**: Create businessConfig.ts with all known company info; use `as const` for type safety; mark social URLs as null pending extraction
|
||||
**Tests**: businessConfig type check; usage in Footer, Header, Contact, About, Checkout confirmation
|
||||
**Expected blast radius**: Frontend text content
|
||||
**Definition of Done**: All company info references businessConfig; no hardcoded strings in components
|
||||
|
||||
## Phase 3: Storefront Brand Application
|
||||
|
||||
### BRAND-FE-004
|
||||
**ID**: BRAND-FE-004
|
||||
**Title**: Update Header with logo + business config
|
||||
**Goal**: Header reflects official brand identity
|
||||
**Why**: Primary brand touchpoint
|
||||
**Dependencies**: BRAND-FE-002, BRAND-FE-003
|
||||
**Applications**: Frontend
|
||||
**Modules**: Header component
|
||||
**Database impact**: None
|
||||
**API contracts**: None
|
||||
**Permissions**: N/A
|
||||
**Implementation**: Replace inline SVG logo with actual logo file; use businessConfig for nav text; verify no hardcoded strings remain
|
||||
**Tests**: Logo renders; nav links correct; business name in correct places
|
||||
**Expected blast radius**: Low
|
||||
**Definition of Done**: Header matches brand; logo correct size and quality
|
||||
|
||||
### BRAND-FE-005
|
||||
**ID**: BRAND-FE-005
|
||||
**Title**: Update Footer with full business info + social
|
||||
**Goal**: Footer contains all business contact information
|
||||
**Why**: Trust and legal requirement (company info on all pages)
|
||||
**Dependencies**: BRAND-FE-002, BRAND-FE-003
|
||||
**Applications**: Frontend
|
||||
**Modules**: Footer component
|
||||
**Database impact**: None
|
||||
**API contracts**: None
|
||||
**Permissions**: N/A
|
||||
**Implementation**: Use businessConfig for all footer data; add social links; add company registration info; verify copyright year is dynamic
|
||||
**Tests**: All footer fields populated from businessConfig; no placeholder text
|
||||
**Expected blast radius**: Low
|
||||
**Definition of Done**: Footer contains address, phone, email, WhatsApp, hours, social, legal links, dynamic copyright
|
||||
|
||||
### BRAND-FE-006
|
||||
**ID**: BRAND-FE-006
|
||||
**Title**: Migrate About page content
|
||||
**Goal**: Faithful migration of /quienes-somos content
|
||||
**Why**: Preserve founder story and brand voice
|
||||
**Dependencies**: BRAND-FE-003
|
||||
**Applications**: Frontend
|
||||
**Modules**: /about page
|
||||
**Database impact**: None
|
||||
**API contracts**: None
|
||||
**Permissions**: N/A
|
||||
**Implementation**: Replace current /about content with migrated content from BRAND_INVENTORY.md; use ContentPage component; add legal flag comment
|
||||
**Tests**: Page renders migrated content correctly; text fidelity verified
|
||||
**Expected blast radius**: Low
|
||||
**Definition of Done**: About page matches legacy /quienes-somos; founders' story preserved; noted as needing legal review if claims made
|
||||
|
||||
### BRAND-FE-007
|
||||
**ID**: BRAND-FE-007
|
||||
**Title**: Update Contact page
|
||||
**Goal**: Contact information from businessConfig + contact form
|
||||
**Why**: Customer trust; functional contact channel
|
||||
**Dependencies**: BRAND-FE-003
|
||||
**Applications**: Frontend
|
||||
**Modules**: /contact page
|
||||
**Database impact**: None
|
||||
**API contracts**: None
|
||||
**Permissions**: N/A
|
||||
**Implementation**: Use businessConfig for all contact info; add functional contact form (mailto or API endpoint); include map/location if feasible; hours from businessConfig
|
||||
**Tests**: All contact methods displayed; form submits successfully
|
||||
**Expected blast radius**: Low
|
||||
**Definition of Done**: Phone, email, WhatsApp, address, hours all correct and functional
|
||||
|
||||
### BRAND-FE-008
|
||||
**ID**: BRAND-FE-008
|
||||
**Title**: Migrate/create legal pages (Terms, Privacy, Cookies)
|
||||
**Goal**: Legal pages exist with migrated or new content
|
||||
**Why**: Legal compliance; customer trust
|
||||
**Dependencies**: None (can run parallel)
|
||||
**Applications**: Frontend
|
||||
**Modules**: /terms, /privacy, /cookies pages
|
||||
**Database impact**: None
|
||||
**API contracts**: None
|
||||
**Permissions**: N/A
|
||||
**Implementation**: For Terms: migrate from legacy (see BRAND_INVENTORY.md); for Privacy/Cookies: create RGPD-compliant templates; add ⚠️LEGAL_REVIEW flag to all; use ContentPage component
|
||||
**Tests**: All three pages accessible at correct routes; content renders; links in footer correct
|
||||
**Expected blast radius**: Low
|
||||
**Definition of Done**: Pages exist and are accessible; flagged as needing legal review; legal links work
|
||||
|
||||
### BRAND-FE-009
|
||||
**ID**: BRAND-FE-009
|
||||
**Title**: Migrate/create Shipping page
|
||||
**Goal**: Shipping policy accessible
|
||||
**Why**: Customer information requirement
|
||||
**Dependencies**: BRAND-FE-003
|
||||
**Applications**: Frontend
|
||||
**Modules**: /shipping page
|
||||
**Database impact**: None
|
||||
**API contracts**: None
|
||||
**Permissions**: N/A
|
||||
**Implementation**: Review existing /shipping page; enhance with additional shipping methods, costs, estimated delivery times, geographical coverage (Spain peninsular); use businessConfig for company info
|
||||
**Tests**: Shipping page complete with all delivery options; pricing included if applicable
|
||||
**Expected blast radius**: Low
|
||||
**Definition of Done**: Shipping page reflects current shipping policy; clear geographic scope stated
|
||||
|
||||
## Phase 4: SEO Redirects
|
||||
|
||||
### BRAND-FE-010
|
||||
**ID**: BRAND-FE-010
|
||||
**Title**: Implement legacy URL redirects in next.config.ts
|
||||
**Goal**: Preserve SEO equity; no broken links for indexed URLs
|
||||
**Why**: Indexed legacy URLs must not 404
|
||||
**Dependencies**: Complete LEGACY_REDIRECT_MAP.md
|
||||
**Applications**: Frontend (Next.js config)
|
||||
**Modules**: next.config.ts
|
||||
**Database impact**: None
|
||||
**API contracts**: None
|
||||
**Permissions**: N/A
|
||||
**Implementation**: Add `redirects()` async function in next.config.ts; implement all confirmed 308 redirects from LEGACY_REDIRECT_MAP.md; handle OpenCart route patterns with 410
|
||||
**Tests**: curl each legacy URL → correct redirect or target page
|
||||
**Expected blast radius**: Low — purely routing
|
||||
**Definition of Done**: All legacy static page URLs redirect correctly; OpenCart query-string routes return 404
|
||||
|
||||
### BRAND-FE-011
|
||||
**ID**: BRAND-FE-011
|
||||
**Title**: Product slug redirects
|
||||
**Goal**: Redirect legacy product URLs to new product pages
|
||||
**Why**: Preserve SEO on indexed product pages
|
||||
**Dependencies**: BRAND-FE-010 (part of same config update)
|
||||
**Applications**: Frontend
|
||||
**Modules**: next.config.ts
|
||||
**Database impact**: None
|
||||
**API contracts**: None
|
||||
**Permissions**: N/A
|
||||
**Implementation**: Evaluate Option A vs B from LEGACY_REDIRECT_MAP.md; implement accordingly
|
||||
**Tests**: At least 5 legacy product URLs from sitemap → correct redirect
|
||||
**Expected blast radius**: Low
|
||||
**Definition of Done**: Legacy product slugs handled (either redirect to matching slug or to /products)
|
||||
|
||||
## Phase 5: Admin
|
||||
|
||||
### BRAND-ADM-001
|
||||
**ID**: BRAND-ADM-001
|
||||
**Title**: Admin sidebar logo
|
||||
**Goal**: Admin sidebar uses real logo instead of inline SVG
|
||||
**Why**: Brand consistency
|
||||
**Dependencies**: BRAND-FE-002
|
||||
**Applications**: Admin
|
||||
**Modules**: DashboardLayout sidebar
|
||||
**Database impact**: None
|
||||
**API contracts**: None
|
||||
**Permissions**: N/A
|
||||
**Implementation**: Copy logo to apps/admin/public/; update sidebar to use <img> instead of inline SVG
|
||||
**Tests**: Logo visible in admin sidebar
|
||||
**Expected blast radius**: Low
|
||||
**Definition of Done**: Admin sidebar shows actual logo; correct size
|
||||
|
||||
## SEO
|
||||
|
||||
### BRAND-SEO-001
|
||||
**ID**: BRAND-SEO-001
|
||||
**Title**: Sitemap update after migration
|
||||
**Goal**: New sitemap reflects migrated routes
|
||||
**Why**: Search engine indexing
|
||||
**Dependencies**: BRAND-FE-006, BRAND-FE-007, BRAND-FE-008, BRAND-FE-009, BRAND-FE-010
|
||||
**Applications**: Frontend
|
||||
**Modules**: sitemap.ts
|
||||
**Database impact**: None
|
||||
**API contracts**: None
|
||||
**Permissions**: N/A
|
||||
**Implementation**: Update frontend/src/app/sitemap.ts to include /about, /contact, /shipping, /terms, /privacy, /cookies; verify /products and /categories still included
|
||||
**Tests**: sitemap.xml accessible; contains all expected routes
|
||||
**Expected blast radius**: Low
|
||||
**Definition of Done**: Sitemap valid XML; includes all public routes
|
||||
|
||||
### BRAND-SEO-002
|
||||
**ID**: BRAND-SEO-002
|
||||
**Title**: robots.txt update
|
||||
**Goal**: Allow crawlers for new routes; block legacy OpenCart routes
|
||||
**Why**: SEO and security
|
||||
**Dependencies**: BRAND-FE-010
|
||||
**Applications**: Frontend
|
||||
**Modules**: robots.ts
|
||||
**Database impact**: None
|
||||
**API contracts**: None
|
||||
**Permissions**: N/A
|
||||
**Implementation**: Update robots.ts to reflect new site structure; add Sitemap directive pointing to new sitemap
|
||||
**Tests**: /robots.txt accessible; correct directives present
|
||||
**Expected blast radius**: Low
|
||||
**Definition of Done**: robots.txt allows crawling of all public pages; blocks admin and legacy internals
|
||||
|
||||
## QA
|
||||
|
||||
### BRAND-QA-001
|
||||
**ID**: BRAND-QA-001
|
||||
**Title**: Visual regression and route tests
|
||||
**Goal**: Brand elements render correctly; redirects work
|
||||
**Why**: Quality assurance
|
||||
**Dependencies**: All FE/ADM tasks
|
||||
**Applications**: QA
|
||||
**Modules**: E2E or visual tests
|
||||
**Tests**:
|
||||
- Logo renders on Header, Footer, Admin sidebar
|
||||
- Footer contains all business contact info from businessConfig
|
||||
- About page renders migrated content
|
||||
- Legacy redirects: /quienes-somos → /about (308), /contacto → /contact (308)
|
||||
- Sitemap contains all public routes
|
||||
- No hardcoded company info outside businessConfig
|
||||
**Expected blast radius**: N/A
|
||||
**Definition of Done**: All tests pass; visual QA sign-off
|
||||
|
||||
---
|
||||
|
||||
## Task Summary Table
|
||||
|
||||
| Task | Layer | Feature | Depends On | Risk | Parallel |
|
||||
|------|-------|---------|-----------|------|---------|
|
||||
| BRAND-FE-001 | FE | Extract legacy CSS | — | Low | * |
|
||||
| BRAND-FE-002 | FE | Download logo | BRAND-FE-001 | Low | * |
|
||||
| BRAND-FE-003 | FE | businessConfig | BRAND-FE-001 | Low | * |
|
||||
| BRAND-FE-004 | FE | Header update | BRAND-FE-002, BRAND-FE-003 | Low | * |
|
||||
| BRAND-FE-005 | FE | Footer update | BRAND-FE-002, BRAND-FE-003 | Low | * |
|
||||
| BRAND-FE-006 | FE | About page | BRAND-FE-003 | Low | * |
|
||||
| BRAND-FE-007 | FE | Contact page | BRAND-FE-003 | Low | * |
|
||||
| BRAND-FE-008 | FE | Legal pages | — | Medium | * |
|
||||
| BRAND-FE-009 | FE | Shipping page | BRAND-FE-003 | Low | * |
|
||||
| BRAND-FE-010 | FE | Static page redirects | BRAND-FE-001 | Low | BRAND-FE-006..009 |
|
||||
| BRAND-FE-011 | FE | Product slug redirects | BRAND-FE-010 | Medium | * |
|
||||
| BRAND-ADM-001 | Admin | Admin logo | BRAND-FE-002 | Low | * |
|
||||
| BRAND-SEO-001 | SEO | Sitemap update | BRAND-FE-006..009 | Low | * |
|
||||
| BRAND-SEO-002 | SEO | robots.txt update | BRAND-FE-010 | Low | * |
|
||||
| BRAND-QA-001 | QA | Visual + route tests | All above | Low | After FE tasks |
|
||||
|
||||
**Parallel group**: BRAND-FE-001 through BRAND-FE-003 can run in parallel. BRAND-FE-004 through BRAND-FE-009 can run in parallel after FE-003. BRAND-FE-010 depends on BRAND-FE-001 (extract URLs). BRAND-SEO-001 and BRAND-SEO-002 depend on content pages being done.
|
||||
|
||||
**Recommended order**:
|
||||
1. BRAND-FE-001, BRAND-FE-002, BRAND-FE-003 (parallel)
|
||||
2. BRAND-FE-004, BRAND-FE-005, BRAND-FE-006, BRAND-FE-007, BRAND-FE-008, BRAND-FE-009 (parallel)
|
||||
3. BRAND-FE-010 + BRAND-FE-011 (after FE-001)
|
||||
4. BRAND-ADM-001 (after FE-002)
|
||||
5. BRAND-SEO-001 + BRAND-SEO-002 (after content pages)
|
||||
6. BRAND-QA-001 (after everything)
|
||||
|
||||
**High-risk tasks**:
|
||||
- BRAND-FE-008 (legal pages — requires human review, cannot be auto-approved)
|
||||
- BRAND-FE-011 (product redirects — wrong option could lose SEO equity)
|
||||
|
||||
**Migration risks**:
|
||||
- Legal text is legacy and may not comply with current RGPD — must be reviewed by human before publishing
|
||||
- Legacy site may still be actively used — coordinate go-live date
|
||||
- Legacy product slugs may not match new platform slug format — requires slug mapping
|
||||
117
project/specs/brand-migration/TESTS.md
Normal file
117
project/specs/brand-migration/TESTS.md
Normal file
@@ -0,0 +1,117 @@
|
||||
# BRAND MIGRATION — TESTS.md
|
||||
|
||||
## Visual Regression Tests
|
||||
|
||||
```
|
||||
BRAND-VIS-001: Logo renders in Header at correct dimensions
|
||||
BRAND-VIS-002: Logo renders in Footer at correct dimensions
|
||||
BRAND-VIS-003: Logo renders in Admin sidebar
|
||||
BRAND-VIS-004: Favicon renders in browser tab
|
||||
BRAND-VIS-005: Primary color matches legacy (inspect CSS after BRAND-FE-001)
|
||||
BRAND-VIS-006: Accent color matches legacy (inspect CSS after BRAND-FE-001)
|
||||
BRAND-VIS-007: Footer contains company name from businessConfig
|
||||
BRAND-VIS-008: Footer contains full address from businessConfig
|
||||
BRAND-VIS-009: Footer contains phone from businessConfig
|
||||
BRAND-VIS-010: Footer contains email from businessConfig
|
||||
BRAND-VIS-011: Footer contains WhatsApp from businessConfig
|
||||
BRAND-VIS-012: Footer contains business hours from businessConfig
|
||||
BRAND-VIS-013: Header uses Inter font (system / Google Fonts)
|
||||
BRAND-VIS-014: Heading font (Playfair Display) renders for page titles
|
||||
BRAND-VIS-015: Responsive: logo and footer text readable on mobile
|
||||
```
|
||||
|
||||
## Route Tests
|
||||
|
||||
```
|
||||
BRAND-ROUTE-001: GET /about → 200, About page with migrated content
|
||||
BRAND-ROUTE-002: GET /contact → 200, Contact page with businessConfig info
|
||||
BRAND-ROUTE-003: GET /shipping → 200, Shipping policy
|
||||
BRAND-ROUTE-004: GET /terms → 200, Terms page (may be flagged for review)
|
||||
BRAND-ROUTE-005: GET /privacy → 200, Privacy policy
|
||||
BRAND-ROUTE-006: GET /cookies → 200, Cookie policy
|
||||
BRAND-ROUTE-007: GET /legal → 200 or /404 (if not created)
|
||||
```
|
||||
|
||||
## Redirect Tests
|
||||
|
||||
```
|
||||
BRAND-RED-001: GET /quienes-somos → 308 → /about
|
||||
BRAND-RED-002: GET /contacto → 308 → /contact
|
||||
BRAND-RED-003: GET /terminos-y-condiciones → 308 → /terms
|
||||
BRAND-RED-004: GET /politica-de-cookies → 308 → /cookies
|
||||
BRAND-RED-005: GET /politica-de-privacidad → 308 → /privacy
|
||||
BRAND-RED-006: GET /donde-estamos → 308 → /contact
|
||||
BRAND-RED-007: GET /admin → 404 (OpenCart internals blocked)
|
||||
BRAND-RED-008: GET /?route=product/product&id=42 → 404 (OpenCart query blocked)
|
||||
BRAND-RED-009: Legacy product slug from sitemap → appropriate redirect
|
||||
BRAND-RED-010: Legacy category slug → appropriate redirect
|
||||
```
|
||||
|
||||
## SEO Tests
|
||||
|
||||
```
|
||||
BRAND-SEO-001: GET /sitemap.xml → valid XML with all public routes
|
||||
BRAND-SEO-002: GET /robots.txt → contains sitemap directive
|
||||
BRAND-SEO-003: GET /robots.txt → does not block /about, /contact, /shipping, /terms, /privacy, /cookies
|
||||
BRAND-SEO-004: GET /robots.txt → blocks /admin
|
||||
BRAND-SEO-005: <title> on /about → includes "Mercado de Vida" or "MercadoDeVida"
|
||||
BRAND-SEO-006: <meta name="description"> on /about → present and meaningful
|
||||
```
|
||||
|
||||
## Content Tests
|
||||
|
||||
```
|
||||
BRAND-CONTENT-001: /about page mentions founders (Ivana & Ricardo)
|
||||
BRAND-CONTENT-002: /about page mentions Estepona/Costa del Sol
|
||||
BRAND-CONTENT-003: /contact page has clickable phone link (tel:)
|
||||
BRAND-CONTENT-004: /contact page has clickable email link (mailto:)
|
||||
BRAND-CONTENT-005: /contact page has WhatsApp link
|
||||
BRAND-CONTENT-006: Footer copyright year is current year (dynamic)
|
||||
BRAND-CONTENT-007: All business info fields populated (no empty phone/email/address)
|
||||
BRAND-CONTENT-008: Legal pages have ⚠️LEGAL_REVIEW flag or equivalent visible in source
|
||||
```
|
||||
|
||||
## businessConfig Tests
|
||||
|
||||
```
|
||||
BRAND-CFG-001: businessConfig.phone matches string used in Header, Footer, Contact
|
||||
BRAND-CFG-002: businessConfig.email matches string used in Header, Footer, Contact
|
||||
BRAND-CFG-003: businessConfig.address matches string used in Footer
|
||||
BRAND-CFG-004: No hardcoded address string in any component outside businessConfig
|
||||
BRAND-CFG-005: No hardcoded phone string in any component outside businessConfig
|
||||
BRAND-CFG-006: No hardcoded email string in any component outside businessConfig
|
||||
```
|
||||
|
||||
## Given/When/Then Acceptance Criteria
|
||||
|
||||
```
|
||||
GIVEN a user visits /quienes-somos
|
||||
WHEN the redirect is implemented
|
||||
THEN they receive a 308 redirect to /about
|
||||
AND they land on the About page with migrated content
|
||||
|
||||
GIVEN a user visits the footer
|
||||
WHEN the page renders
|
||||
THEN the address, phone, email, WhatsApp, and hours all come from businessConfig
|
||||
AND no string is hardcoded in the Footer component
|
||||
|
||||
GIVEN a developer needs to update the company phone number
|
||||
WHEN they update businessConfig.phone
|
||||
THEN every page that displays the phone reflects the new value
|
||||
AND no manual find-replace is required
|
||||
|
||||
GIVEN legal text has been migrated from the legacy site
|
||||
WHEN the Terms page is published
|
||||
THEN it is flagged as requiring human/legal review
|
||||
AND no AI-modified version is presented as newly legally approved
|
||||
|
||||
GIVEN a search engine bot crawls the site
|
||||
WHEN it requests /sitemap.xml
|
||||
THEN it contains all public routes (/about, /contact, /shipping, /products, /categories, etc.)
|
||||
AND no internal admin routes are exposed
|
||||
|
||||
GIVEN a legacy product URL is accessed
|
||||
WHEN the new platform handles it
|
||||
THEN it either redirects to the correct new product page
|
||||
OR returns 404 — it must NOT silently show a broken page
|
||||
```
|
||||
Reference in New Issue
Block a user