Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 7 additions & 9 deletions .env.example
Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
# Airtable Configuration
# Get these from your Airtable account settings
VITE_AIRTABLE_API_KEY=your_airtable_api_key_here
VITE_AIRTABLE_BASE_ID=your_base_id_here
VITE_AIRTABLE_TABLE_NAME=Productos
# API Configuration
VITE_API_URL=https://api.example.com/v1

# MercadoPago Configuration (Frontend)
# MercadoPago Configuration
VITE_MERCADOPAGO_PUBLIC_KEY=your_mercadopago_public_key_here
MERCADOPAGO_ACCESS_TOKEN=your_mercadopago_access_token_here

# Server-side MercadoPago Configuration (Netlify Functions)
# Add this in Netlify Dashboard > Functions > Environment
MERCADOPAGO_ACCESS_TOKEN=your_mercadopago_access_token_here
# Netlify Functions Environment
ALLOWED_ORIGINS=https://your-domain.netlify.app,http://localhost:3000
SITE_URL=http://localhost:3000
10 changes: 4 additions & 6 deletions .env.secure
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,8 @@
# This file contains template values. DO NOT use these in production!
# Replace with your actual values and set them in Netlify environment variables

# Airtable Configuration
VITE_AIRTABLE_API_KEY=your_actual_airtable_personal_access_token_here
VITE_AIRTABLE_BASE_ID=your_actual_base_id_here
VITE_AIRTABLE_TABLE_NAME=Productos
# API Configuration
VITE_API_URL=https://api.example.com/v1

# MercadoPago Configuration (Frontend)
VITE_MERCADOPAGO_PUBLIC_KEY=your_actual_mercadopago_public_key_here
Expand All @@ -17,7 +15,7 @@ MERCADOPAGO_ACCESS_TOKEN=your_actual_mercadopago_access_token_here

# Security Configuration (Netlify Functions Environment)
# Comma-separated list of allowed origins
ALLOWED_ORIGINS=https://amigurumi-de-ines.netlify.app,https://localhost:3000
ALLOWED_ORIGINS=https://tienda-devschile.netlify.app,http://localhost:5173

# Node Environment (Production)
NODE_ENV=production
Expand All @@ -26,4 +24,4 @@ NODE_ENV=production
# 1. NEVER commit real API keys to version control
# 2. Set sensitive values in Netlify environment variables
# 3. Rotate all exposed credentials immediately
# 4. See SECURITY.md for detailed security analysis
# 4. See SECURITY.md for detailed security analysis
6 changes: 5 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -174,4 +174,8 @@ bundle-report.html
SECURITY.md
*.pem
*.key
*.crt
*.crt

# Local environment variables source
.env
.env.local
2 changes: 1 addition & 1 deletion .nvmrc
Original file line number Diff line number Diff line change
@@ -1 +1 @@
18
25
10 changes: 10 additions & 0 deletions .prettierignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# Prettier ignore file
node_modules
dist
build
.idea
.DS_Store
package-lock.json
package.json
public
*.html
11 changes: 11 additions & 0 deletions .prettierrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"semi": true,
"trailingComma": "all",
"singleQuote": true,
"printWidth": 100,
"tabWidth": 2,
"useTabs": false,
"jsxSingleQuote": false,
"bracketSpacing": true,
"arrowParens": "always"
}
123 changes: 38 additions & 85 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,29 +1,15 @@
# Amigurumis de Inés - Ecommerce con MercadoPago
# Tienda devsChile - Ecommerce con MercadoPago

Sitio web para la venta de amigurumis tejidos a mano por Inés. Construido con React, TypeScript, Tailwind CSS y Vite. **Ahora con integración completa de MercadoPago para pagos reales**.

## 🚨 AVISO DE SEGURIDAD IMPORTANTE

**⚠️ ANTES DE USAR EN PRODUCCIÓN: Se realizó una auditoría de seguridad completa. Las credenciales expuestas deben rotarse inmediatamente. Ver la sección [Seguridad](#-seguridad) para más detalles.**

## ✨ Características

- 🎨 Diseño responsivo y atractivo con gradientes cálidos
- 📱 Interfaz moderna optimizada para móviles
- 🛍️ Catálogo de productos dinámico desde Airtable
- 💳 **Pagos reales con MercadoPago** (¡NUEVO!)
- 🔒 Pago seguro con redirección a MercadoPago
- ✅ Páginas de confirmación: éxito, falla y pendiente
- 📊 Gestión de estados de pago completa
- 🎯 Sin carrito de compras - compra directa por producto
- 🛡️ **Auditoría de seguridad completa implementada**
Sitio web para la venta de productos de la comunidad devsChile.
Construido con React, TypeScript, Tailwind CSS y Vite.
**Ahora con integración completa de MercadoPago para transacciones reales**.

## 🛠️ Tecnologías

- **Frontend**: React 18 + TypeScript + Vite
- **Estilos**: Tailwind CSS + Gradientes personalizados
- **UI Components**: Radix UI + shadcn/ui
- **Datos**: Airtable API
- **Datos**: API Genérica / Mock Data
- **Pagos**: MercadoPago SDK + Netlify Functions
- **Despliegue**: Netlify (Frontend + Functions)
- **Seguridad**: CORS whitelist, validación de entrada, headers de seguridad
Expand All @@ -48,14 +34,14 @@ cp .env.secure .env

**Variables requeridas:**

#### Airtable (para productos)
#### API Configuration (para productos)

```env
VITE_AIRTABLE_API_KEY=tu_airtable_api_key_aqui
VITE_AIRTABLE_BASE_ID=tu_base_id_aqui
VITE_AIRTABLE_TABLE_NAME=Productos
VITE_API_URL=https://tu-api.com/v1
```

#### MercadoPago (para pagos)

```env
# Clave pública (frontend) - esta se puede exponer
VITE_MERCADOPAGO_PUBLIC_KEY=tu_public_key_aqui
Expand All @@ -65,9 +51,10 @@ MERCADOPAGO_ACCESS_TOKEN=tu_access_token_aqui
```

#### Seguridad (Netlify Functions)

```env
# Orígenes permitidos (comas separadas)
ALLOWED_ORIGINS=https://amigurumi-de-ines.netlify.app,https://localhost:3000
ALLOWED_ORIGINS=https://tienda-devschile.cl,http://localhost:3000

NODE_ENV=production
```
Expand All @@ -80,18 +67,18 @@ NODE_ENV=production
- `Public Key`: Para el frontend (VITE_MERCADOPAGO_PUBLIC_KEY)
- `Access Token`: Para el backend (MERCADOPAGO_ACCESS_TOKEN)

### 4. Configurar Airtable
### 4. Configuración de API de Productos

La aplicación espera una tabla llamada "Productos" con estos campos:
La aplicación espera un endpoint `GET /products` que retorne una estructura compatible con `ProductResponse` conteniendo estos campos:

| Campo | Tipo | Requerido | Descripción |
|-------|------|-----------|-------------|
| `nombre` | Texto | ✅ | Nombre del producto |
| `descripcion` | Texto largo | ✅ | Descripción detallada |
| `precio` | Número | ✅ | Precio en CLP |
| `imagen_miniatura` | Attachment | ✅ | Imagen 300x300px |
| `imagenes_grandes` | Attachment | ✅ | Imágenes alta resolución |
| `activo` | Checkbox | ✅ | Disponible para venta |
| Campo | Tipo | Requerido | Descripción |
| ------------------ | ----------- | --------- | ------------------------ |
| `name` | Texto | ✅ | Nombre del producto |
| `description` | Texto largo | ✅ | Descripción detallada |
| `price` | Número | ✅ | Precio en CLP |
| `thumbnailImages` | Attachment | ✅ | Imagen 300x300px |
| `largeImages` | Attachment | ✅ | Imágenes alta resolución |
| `active` | Checkbox | ✅ | Disponible para venta |

## 🏃‍♂️ Desarrollo

Expand Down Expand Up @@ -133,6 +120,8 @@ npm run lint
│ └── functions/
│ ├── create-payment.js # Netlify Function para MercadoPago (segura)
│ └── package.json # Dependencias de Functions
├── public/
│ └── images/ # Imágenes estáticas (accesibles vía /images/*)
├── app/
│ └── app.tsx # Componente principal con pago
├── components/
Expand All @@ -147,35 +136,10 @@ npm run lint
└── package.json # Dependencias del proyecto
```

## 🌐 Despliegue en Netlify

### Configuración Automática:

1. **Conecta tu repositorio a Netlify**
2. **Variables de entorno en Netlify Dashboard:**
- Todas las variables `VITE_*` en "Build & deploy" → "Environment"
- `MERCADOPAGO_ACCESS_TOKEN` en "Functions" → "Environment"
- `ALLOWED_ORIGINS` en "Functions" → "Environment"
- `NODE_ENV=production` en "Functions" → "Environment"
3. **Netlify detectará automáticamente:**
- Build: `npm ci && npm run build`
- Publish directory: `dist`
- Functions directory: `netlify/functions`

### URLs de Función:

- Crear pago: `https://tu-sitio.netlify.app/.netlify/functions/create-payment`

### 🛠️ Solución de Problemas de Despliegue:

#### Error "vite: not found"

Si encuentras el error `sh: 1: vite: not found` durante el build:

1. **✅ Ya solucionado**: El archivo `netlify.toml` incluye `npm ci &&` para instalar dependencias
2. **Node.js Version**: El proyecto usa Node.js 18 (ver `.nvmrc`)
3. **Dependencias**: Asegúrate de que `package-lock.json` esté en el repositorio

#### Comandos de Build Configurados:

```toml
Expand All @@ -189,38 +153,32 @@ Esto asegura que las dependencias se instalen antes del build.

### Modificar Productos:

Edita directamente en tu tabla de Airtable. Los cambios se reflejan automáticamente.
Edita tus datos en el archivo `app/productsMock.ts` o configura tu API Genérica. Los cambios se reflejan automáticamente.

#### Imágenes Locales:

Puedes guardar imágenes estáticas en la carpeta `public/images/`. Para usarlas en tus productos, utiliza la ruta relativa comenzando con `/images/`.
Ejemplo: Si guardas `mi-producto.jpg` en `public/images/`, la URL en tu JSON/Mock será `/images/mi-producto.jpg`.

### Cambiar Precios:

Los precios se muestran en CLP (Pesos Chilenos) y se formatean automáticamente.

### Personalizar Estilos:

- Colores principales: `rose-500` y `orange-500`
- Gradientes: `from-rose-500 to-orange-500`
- Colores principales: `brand-primary` (#85422b) y `brand-secondary` (#b45b38)
- Texto principal: `brand-text` (#1d1d1d)
- Gradientes: `from-brand-primary to-brand-secondary`
- Tipografía: Sistema fonts optimizados

## 📋 Checklist de Configuración

- [ ] ✅ Instalar dependencias
- [ ] ✅ Configurar variables de Airtable
- [ ] ✅ Crear cuenta en MercadoPago
- [ ] ✅ Obtener credenciales de MercadoPago
- [ ] ✅ **ROTAR credenciales expuestas** (Ver sección Seguridad)
- [ ] ✅ Configurar variables de entorno
- [ ] ✅ Conectar repositorio a Netlify
- [ ] ✅ Probar flujo de pagos
- [ ] ✅ Verificar páginas de confirmación
- [ ] ✅ Configurar variables de seguridad en Netlify

## 🛡️ Seguridad

### ⚠️ AUDITORÍA DE SEGURIDAD COMPLETADA

Se realizó una auditoría completa de seguridad que identificó y corrigió vulnerabilidades críticas:

#### Vulnerabilidades Corregidas:

- ✅ **CORS mejorado**: Reemplazado wildcard `*` con whitelist de orígenes
- ✅ **Validación de entrada**: Sanitización y validación de todos los inputs
- ✅ **Headers de seguridad**: X-Frame-Options, X-XSS-Protection, X-Content-Type-Options
Expand All @@ -231,25 +189,22 @@ Se realizó una auditoría completa de seguridad que identificó y corrigió vul

**Las siguientes credenciales están expuestas y deben rotarse INMEDIATAMENTE:**

1. **Airtable API Key**: `patDvA7InUnb2X449.*` (PAT completa expuesta)
2. **Airtable Base ID**: `apprLGWcETltWUXpn`
3. **MercadoPago Public Key**: `APP_USR-0ce0eeab-*` (Key completa expuesta)
4. **MercadoPago Access Token**: `APP_USR-2637451468197049-*` (Token completo expuesto)
1. **MercadoPago Public Key**: `APP_USR-0ce0eeab-*` (Key completa expuesta)
2. **MercadoPago Access Token**: `APP_USR-2637451468197049-*` (Token completo expuesto)

#### Pasos de Rotación CRÍTICOS:

1. **🔄 Rotar credenciales inmediatamente:**
- Airtable: [Personal Access Tokens](https://airtable.com/developers/web/api/personal-access-tokens)
- MercadoPago: [Developer Panel](https://www.mercadopago.com.ar/developers/panel/credentials)

2. **🗑️ Eliminar archivo .env actual** después de la rotación

3. **🧹 Limpiar historial de git** si las credenciales fueron commitadas
3. **🧹 Limpiar historial de git** si las credenciales fueron commiteadas

4. **⚙️ Configurar en Netlify Dashboard:**
```
MERCADOPAGO_ACCESS_TOKEN=nueva_token_rotado
ALLOWED_ORIGINS=https://amigurumi-de-ines.netlify.app,https://localhost:3000
ALLOWED_ORIGINS=https://tienda-devschile.netlify.app,http://localhost:5173
NODE_ENV=production
```

Expand Down Expand Up @@ -281,10 +236,8 @@ Si tienes problemas con la integración de MercadoPago:

## 📄 Licencia

Proyecto privado - © 2025 Amigurumis de Inés. Todos los derechos reservados.
Proyecto privado - © 2026 Tienda devsChile. Todos los derechos reservados.

---

**🎉 ¡Listo para recibir pagos reales con MercadoPago!** 💳

**⚠️ RECORDATORIO**: Rotar credenciales expuestas antes del despliegue en producción.
49 changes: 36 additions & 13 deletions actions/createPayment.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,42 @@
// Acción para crear pago en la pasarela
import { action } from '@uibakery/data';

function createPayment() {
return action('createPayment', 'HTTP', {
datasourceName: 'httpApi',
options: {
method: 'POST',
url: '{{params?.paymentGatewayUrl}}',
headers: {
'Content-Type': 'application/json',
},
bodyType: 'object',
body: '{ amount: {{params?.amount}}, productName: {{params?.productName}}, currency: "CLP" }',
export const createPayment = async (
amount: number,
productName: string,
productId: string,
quantity: number = 1,
) => {
// En desarrollo, usamos un mock según los requerimientos
if (import.meta.env.DEV) {
console.log('Utilizando mock de pago para desarrollo');
// Simulamos un pequeño retraso de red
await new Promise((resolve) => setTimeout(resolve, 800));

return {
success: true,
checkout_url: '/success.html',
};
}

// En producción, llamamos a la Netlify Function
const response = await fetch('/.netlify/functions/create-payment', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
amount,
productName,
productId,
quantity,
}),
});
}

if (!response.ok) {
throw new Error('Error al crear el pago en el servidor');
}

return response.json();
};

export default createPayment;
8 changes: 4 additions & 4 deletions actions/loadProducts.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
// Acción para cargar todos los productos activos desde Airtable
// Action to load all active products from the API
import { action } from '@uibakery/data';

function loadProducts() {
return action('loadProducts', 'HTTP', {
datasourceName: 'httpApi',
options: {
method: 'GET',
url: 'https://api.airtable.com/v0/{{params?.baseId}}/{{params?.tableName}}',
url: '{{params?.apiUrl}}/products',
queryParams: {
filterByFormula: '{activo} = TRUE()',
active: 'true',
},
headers: {
Authorization: 'Bearer {{params?.apiKey}}',
'Content-Type': 'application/json',
},
},
});
Expand Down
Loading