mirror of
https://github.com/marcogll/AnchorOS.git
synced 2026-03-15 16:24:30 +00:00
feat: implement customer registration flow and business hours system
Major changes: - Add customer registration with email/phone lookup (app/booking/registro) - Add customers API endpoint (app/api/customers/route) - Implement business hours for locations (mon-fri 10-7, sat 10-6, sun closed) - Fix availability function type casting issues - Add business hours utilities (lib/utils/business-hours.ts) - Update Location type to include business_hours JSONB - Add mock payment component for testing - Remove Supabase auth from booking flow - Fix /cita redirect path in booking flow Database migrations: - Add category column to services table - Add business_hours JSONB column to locations table - Fix availability functions with proper type casting - Update get_detailed_availability to use business_hours Features: - Customer lookup by email or phone - Auto-redirect to registration if customer not found - Pre-fill customer data if exists - Business hours per day of week - Location-specific opening/closing times
This commit is contained in:
180
docs/API.md
Normal file
180
docs/API.md
Normal file
@@ -0,0 +1,180 @@
|
||||
# AnchorOS API Documentation
|
||||
|
||||
## Overview
|
||||
AnchorOS is a comprehensive salon management system built with Next.js, Supabase, and Stripe integration.
|
||||
|
||||
## Authentication
|
||||
- **Client Authentication**: Magic link via Supabase Auth
|
||||
- **Staff/Admin Authentication**: Supabase Auth with role-based access
|
||||
- **Kiosk Authentication**: API key based
|
||||
|
||||
## API Endpoints
|
||||
|
||||
### Public APIs
|
||||
|
||||
#### Services
|
||||
- `GET /api/services` - List all available services
|
||||
- `POST /api/services` - Create new service (Admin only)
|
||||
|
||||
#### Locations
|
||||
- `GET /api/locations` - List all salon locations
|
||||
|
||||
#### Availability
|
||||
- `GET /api/availability/time-slots` - Get available time slots for booking
|
||||
- `POST /api/availability/staff-unavailable` - Mark staff unavailable (Staff auth required)
|
||||
|
||||
#### Customers
|
||||
- `GET /api/customers` - Search customer by email or phone
|
||||
- `POST /api/customers` - Register new customer
|
||||
|
||||
#### Bookings (Public)
|
||||
- `POST /api/bookings` - Create new booking (supports customer_id or customer info)
|
||||
- `GET /api/bookings/[id]` - Get booking details
|
||||
- `PUT /api/bookings/[id]` - Update booking
|
||||
|
||||
### Staff/Admin APIs (Aperture)
|
||||
|
||||
#### Dashboard
|
||||
- `GET /api/aperture/dashboard` - Dashboard data
|
||||
- `GET /api/aperture/stats` - Statistics
|
||||
|
||||
#### Staff Management
|
||||
- `GET /api/aperture/staff` - List staff members
|
||||
- `POST /api/aperture/staff` - Create/Update staff
|
||||
|
||||
#### Resources
|
||||
- `GET /api/aperture/resources` - List resources
|
||||
- `POST /api/aperture/resources` - Manage resources
|
||||
|
||||
#### Reports
|
||||
- `GET /api/aperture/reports/sales` - Sales reports
|
||||
- `GET /api/aperture/reports/payments` - Payment reports
|
||||
- `GET /api/aperture/reports/payroll` - Payroll reports
|
||||
|
||||
#### Permissions
|
||||
- `GET /api/aperture/permissions` - Get role permissions
|
||||
- `POST /api/aperture/permissions` - Update permissions
|
||||
|
||||
### Kiosk APIs
|
||||
- `POST /api/kiosk/authenticate` - Authenticate kiosk
|
||||
- `GET /api/kiosk/resources/available` - Get available resources for kiosk
|
||||
- `POST /api/kiosk/bookings` - Create walk-in booking
|
||||
- `PUT /api/kiosk/bookings/[shortId]/confirm` - Confirm booking
|
||||
|
||||
### Payment APIs
|
||||
- `POST /api/create-payment-intent` - Create Stripe payment intent
|
||||
|
||||
### Admin APIs
|
||||
- `GET /api/admin/locations` - List locations (Admin key required)
|
||||
- `POST /api/admin/users` - Create staff/user
|
||||
- `POST /api/admin/kiosks` - Create kiosk
|
||||
|
||||
## Data Models
|
||||
|
||||
### User Roles
|
||||
- `customer` - End customers
|
||||
- `staff` - Salon staff
|
||||
- `artist` - Service providers
|
||||
- `manager` - Location managers
|
||||
- `admin` - System administrators
|
||||
- `kiosk` - Kiosk devices
|
||||
|
||||
### Key Tables
|
||||
- `locations` - Salon locations with business hours (JSONB)
|
||||
- `staff` - Staff members
|
||||
- `services` - Available services with category
|
||||
- `resources` - Physical resources (stations)
|
||||
- `customers` - Customer profiles
|
||||
- `bookings` - Service bookings
|
||||
- `kiosks` - Kiosk devices
|
||||
- `audit_logs` - System audit trail
|
||||
|
||||
### Business Hours Structure
|
||||
Locations table includes `business_hours` JSONB column with format:
|
||||
```json
|
||||
{
|
||||
"monday": {"open": "10:00", "close": "19:00", "is_closed": false},
|
||||
"tuesday": {"open": "10:00", "close": "19:00", "is_closed": false},
|
||||
"wednesday": {"open": "10:00", "close": "19:00", "is_closed": false},
|
||||
"thursday": {"open": "10:00", "close": "19:00", "is_closed": false},
|
||||
"friday": {"open": "10:00", "close": "19:00", "is_closed": false},
|
||||
"saturday": {"open": "10:00", "close": "18:00", "is_closed": false},
|
||||
"sunday": {"is_closed": true}
|
||||
}
|
||||
```
|
||||
|
||||
Default business hours (updated via migration):
|
||||
- Monday-Friday: 10:00 AM - 7:00 PM
|
||||
- Saturday: 10:00 AM - 6:00 PM
|
||||
- Sunday: Closed
|
||||
|
||||
## Environment Variables
|
||||
|
||||
### Required
|
||||
- `NEXT_PUBLIC_SUPABASE_URL`
|
||||
- `NEXT_PUBLIC_SUPABASE_ANON_KEY`
|
||||
- `SUPABASE_SERVICE_ROLE_KEY`
|
||||
- `NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY`
|
||||
- `STRIPE_SECRET_KEY`
|
||||
|
||||
### Optional
|
||||
- `ADMIN_ENROLLMENT_KEY` - For staff enrollment
|
||||
- `GOOGLE_SERVICE_ACCOUNT_KEY` - For Calendar sync
|
||||
|
||||
## Deployment
|
||||
|
||||
### Prerequisites
|
||||
- Node.js 18+
|
||||
- Supabase account
|
||||
- Stripe account
|
||||
- Google Cloud (for Calendar)
|
||||
|
||||
### Setup Steps
|
||||
1. Clone repository
|
||||
2. Install dependencies: `npm install`
|
||||
3. Configure environment variables
|
||||
4. Run database migrations: `npm run db:migrate`
|
||||
5. Seed data: `npm run db:seed`
|
||||
6. Build: `npm run build`
|
||||
7. Start: `npm start`
|
||||
|
||||
## Features
|
||||
|
||||
### Core Functionality
|
||||
- Multi-location salon management
|
||||
- Real-time availability system with business hours
|
||||
- Customer registration and lookup by email/phone
|
||||
- Location-specific opening/closing times
|
||||
- Automated payment processing (currently mock)
|
||||
- Staff scheduling and payroll
|
||||
- Customer relationship management
|
||||
- Kiosk system for walk-ins
|
||||
|
||||
### Booking Flow
|
||||
1. Customer selects service and location
|
||||
2. Customer chooses date and time slot
|
||||
3. Customer searches by email or phone:
|
||||
- If found: Pre-fill data and proceed
|
||||
- If not found: Redirect to registration
|
||||
4. Customer completes registration if needed
|
||||
5. Customer confirms personal details
|
||||
6. Customer pays deposit (mock currently)
|
||||
7. Booking confirmed with email confirmation
|
||||
|
||||
### Advanced Features
|
||||
- Role-based access control
|
||||
- Audit logging
|
||||
- Automated no-show handling
|
||||
- Commission-based payroll
|
||||
- Sales analytics and reporting
|
||||
- Permission management
|
||||
|
||||
### Security
|
||||
- Row Level Security (RLS) in Supabase
|
||||
- API key authentication for kiosks
|
||||
- Magic link authentication for customers
|
||||
- Encrypted payment processing
|
||||
|
||||
## Support
|
||||
|
||||
For API issues or feature requests, please check the TASKS.md for current priorities or create an issue in the repository.
|
||||
121
docs/PRD.md
Normal file
121
docs/PRD.md
Normal file
@@ -0,0 +1,121 @@
|
||||
# PRD — AnchorOS
|
||||
|
||||
**Codename: Adela**
|
||||
|
||||
## 1. Objetivo
|
||||
|
||||
AnchorOS es un sistema operativo para salones de belleza orientado a agenda, pagos, membresías e invitados, con reglas estrictas de tiempo, seguridad y automatización.
|
||||
|
||||
---
|
||||
|
||||
## 2. Principios del Sistema
|
||||
|
||||
* UTC-first en todo el backend.
|
||||
* UUID como identificador primario interno.
|
||||
* Short ID solo para referencia humana.
|
||||
* Automatismos auditables.
|
||||
* PRD como única fuente de verdad.
|
||||
|
||||
---
|
||||
|
||||
## 3. Roles y Membresías
|
||||
|
||||
### 3.1 Tiers
|
||||
|
||||
* Free
|
||||
* Gold
|
||||
|
||||
### 3.2 Tier Gold — Beneficios
|
||||
|
||||
* Acceso prioritario a agenda.
|
||||
* Beneficios financieros definidos en pricing.
|
||||
* Invitaciones semanales.
|
||||
|
||||
### 3.3 Ecosistema de Exclusividad (Invitaciones)
|
||||
|
||||
* Cada cuenta Tier Gold tiene **5 invitaciones semanales**.
|
||||
* Las invitaciones **se resetean cada semana** (Lunes 00:00 UTC).
|
||||
* El reseteo es automático mediante:
|
||||
|
||||
* Supabase Edge Function **o**
|
||||
* Cron Job externo.
|
||||
* El proceso debe ser:
|
||||
|
||||
* Idempotente.
|
||||
* Auditado en `audit_logs`.
|
||||
|
||||
### 3.4 Jerarquía de Roles
|
||||
|
||||
* **Admin**: Acceso total. Puede ver PII de clientes y hacer ajustes.
|
||||
* **Manager**: Acceso operacional. Puede ver PII de clientes y hacer ajustes.
|
||||
* **Staff**: Nivel de coordinación. Puede ver PII de clientes y hacer ajustes.
|
||||
* **Artist**: Nivel de ejecución. **Solo puede ver nombre y notas** del cliente. No ve email ni phone.
|
||||
* **Customer**: Nivel más bajo. Solo puede ver sus propios datos.
|
||||
|
||||
---
|
||||
|
||||
## 4. Gestión de Tiempo y Zonas Horarias
|
||||
|
||||
* **Todos los timestamps se almacenan en UTC**.
|
||||
* `locations.timezone` define la zona local del salón.
|
||||
* Conversión a hora local:
|
||||
|
||||
* Solo en frontend.
|
||||
* Solo en notificaciones (WhatsApp / Email).
|
||||
* Backend, reglas de negocio y validaciones **operan exclusivamente en UTC**.
|
||||
|
||||
---
|
||||
|
||||
## 5. Agenda y Bookings
|
||||
|
||||
### 5.1 Identificadores
|
||||
|
||||
* Cada booking tiene:
|
||||
|
||||
* `id` (UUID, primario).
|
||||
* `short_id` (6 caracteres alfanuméricos).
|
||||
|
||||
### 5.2 Short ID — Reglas
|
||||
|
||||
* Se genera antes de persistir el booking.
|
||||
* Debe verificarse unicidad.
|
||||
* Si existe colisión:
|
||||
|
||||
* Reintentar generación hasta ser único.
|
||||
* El Short ID:
|
||||
|
||||
* Es referencia de pago.
|
||||
* Es identificador operativo.
|
||||
* **No sustituye** el UUID.
|
||||
|
||||
---
|
||||
|
||||
## 6. Pagos
|
||||
|
||||
* Stripe como proveedor principal.
|
||||
* El Short ID se utiliza como referencia visible.
|
||||
* UUID se mantiene interno.
|
||||
|
||||
---
|
||||
|
||||
## 7. Auditoría
|
||||
|
||||
* Toda acción automática o crítica debe registrarse en `audit_logs`.
|
||||
* Incluye:
|
||||
|
||||
* Reseteo de invitaciones.
|
||||
* Cambios de estado de bookings.
|
||||
* Eventos de pago.
|
||||
|
||||
---
|
||||
|
||||
## 8. Límites de los Agentes de IA
|
||||
|
||||
* Ningún agente puede modificar reglas aquí descritas.
|
||||
* Toda implementación debe alinearse estrictamente a este PRD.
|
||||
|
||||
---
|
||||
|
||||
## 9. Estado del Documento
|
||||
|
||||
Este PRD es la fuente única de verdad funcional del sistema AnchorOS.
|
||||
201
docs/STRIPE_SETUP.md
Normal file
201
docs/STRIPE_SETUP.md
Normal file
@@ -0,0 +1,201 @@
|
||||
# Stripe Payment Integration
|
||||
|
||||
## Current Status
|
||||
Stripe is **ENABLED in mock mode** for testing. Real Stripe integration is partially implemented but not yet activated.
|
||||
|
||||
## Current Implementation
|
||||
|
||||
### Mock Payment System
|
||||
- **Component**: `components/booking/mock-payment-form.tsx`
|
||||
- **Usage**: Used in `/booking/cita` for customer bookings
|
||||
- **Functionality**:
|
||||
- Validates card number format (Luhn algorithm)
|
||||
- Accepts any card with correct format
|
||||
- Simulates payment processing
|
||||
- Does not charge real payments
|
||||
|
||||
### Environment Variables
|
||||
Currently set in `.env.local` (keys removed for security - use your own Stripe keys):
|
||||
```bash
|
||||
NEXT_PUBLIC_STRIPE_ENABLED=false
|
||||
STRIPE_SECRET_KEY=sk_live_your_stripe_secret_key_here
|
||||
STRIPE_PUBLISHABLE_KEY=pk_live_your_stripe_publishable_key_here
|
||||
STRIPE_WEBHOOK_SECRET=whsec_your_webhook_secret_here
|
||||
```
|
||||
|
||||
**Note**: `NEXT_PUBLIC_STRIPE_ENABLED=false` means we use mock payments. Stripe keys are stored but not used yet.
|
||||
|
||||
## To Enable Real Stripe Payments
|
||||
|
||||
### 1. Update Environment Variables
|
||||
|
||||
In `.env.local`:
|
||||
|
||||
```bash
|
||||
NEXT_PUBLIC_STRIPE_ENABLED=true
|
||||
STRIPE_SECRET_KEY=sk_test_your_real_stripe_secret_key
|
||||
STRIPE_PUBLISHABLE_KEY=pk_test_your_real_stripe_publishable_key
|
||||
STRIPE_WEBHOOK_SECRET=whsec_your_real_webhook_secret
|
||||
```
|
||||
|
||||
### 2. Create Stripe Webhook Endpoint
|
||||
|
||||
Create `app/api/stripe/webhook/route.ts`:
|
||||
|
||||
```typescript
|
||||
import { NextRequest, NextResponse } from 'next/server'
|
||||
import Stripe from 'stripe'
|
||||
import { supabaseAdmin } from '@/lib/supabase/admin'
|
||||
|
||||
const stripe = new Stripe(process.env.STRIPE_WEBHOOK_SECRET!)
|
||||
|
||||
export async function POST(request: NextRequest) {
|
||||
const body = await request.text()
|
||||
const sig = request.headers.get('stripe-signature')!
|
||||
|
||||
let event
|
||||
|
||||
try {
|
||||
event = stripe.webhooks.constructEvent(
|
||||
body,
|
||||
sig,
|
||||
process.env.STRIPE_WEBHOOK_SECRET!
|
||||
)
|
||||
} catch (err) {
|
||||
return NextResponse.json({ error: 'Invalid signature' }, { status: 400 })
|
||||
}
|
||||
|
||||
switch (event.type) {
|
||||
case 'payment_intent.succeeded':
|
||||
const paymentIntent = event.data.object as Stripe.PaymentIntent
|
||||
// Update booking status to confirmed
|
||||
await supabaseAdmin
|
||||
.from('bookings')
|
||||
.update({ status: 'confirmed', is_paid: true })
|
||||
.eq('payment_reference', paymentIntent.id)
|
||||
break
|
||||
|
||||
case 'payment_intent.payment_failed':
|
||||
const failedIntent = event.data.object as Stripe.PaymentIntent
|
||||
// Update booking status to pending/notify customer
|
||||
await supabaseAdmin
|
||||
.from('bookings')
|
||||
.update({ status: 'pending' })
|
||||
.eq('payment_reference', failedIntent.id)
|
||||
break
|
||||
|
||||
case 'charge.refunded':
|
||||
// Handle refunds - mark as cancelled or retain deposit
|
||||
break
|
||||
|
||||
default:
|
||||
console.log(`Unhandled event type: ${event.type}`)
|
||||
}
|
||||
|
||||
return NextResponse.json({ received: true })
|
||||
}
|
||||
```
|
||||
|
||||
### 3. Replace Mock Payment with Real Stripe
|
||||
|
||||
In `app/booking/cita/page.tsx`:
|
||||
|
||||
Replace the `MockPaymentForm` component usage with real Stripe integration:
|
||||
|
||||
```tsx
|
||||
import { useStripe, useElements, CardElement } from '@stripe/react-stripe-js'
|
||||
|
||||
// Replace the mock payment section with:
|
||||
<CardElement
|
||||
options={{
|
||||
style: {
|
||||
base: {
|
||||
fontSize: '16px',
|
||||
color: 'var(--charcoal-brown)',
|
||||
'::placeholder': {
|
||||
color: 'var(--mocha-taupe)',
|
||||
},
|
||||
},
|
||||
},
|
||||
}}
|
||||
/>
|
||||
```
|
||||
|
||||
### 4. Update Payment Handling
|
||||
|
||||
Replace the `handleMockPayment` function with real Stripe confirmation:
|
||||
|
||||
```tsx
|
||||
const handlePayment = async () => {
|
||||
if (!stripe || !elements) return
|
||||
|
||||
const { error, paymentIntent } = await stripe.confirmCardPayment(
|
||||
paymentIntent.clientSecret,
|
||||
{
|
||||
payment_method: {
|
||||
card: elements.getElement(CardElement)!,
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
if (error) {
|
||||
// Handle error
|
||||
setErrors({ submit: error.message })
|
||||
setPageLoading(false)
|
||||
} else {
|
||||
// Payment succeeded, create booking
|
||||
createBooking(paymentIntent.id)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 5. Configure Stripe Dashboard
|
||||
|
||||
1. Go to Stripe Dashboard > Webhooks
|
||||
2. Add endpoint: `https://booking.anchor23.mx/api/stripe/webhook`
|
||||
3. Select events:
|
||||
- `payment_intent.succeeded`
|
||||
- `payment_intent.payment_failed`
|
||||
- `charge.refunded`
|
||||
4. Copy the webhook signing secret to `STRIPE_WEBHOOK_SECRET`
|
||||
|
||||
### 6. Update Create Payment Intent API
|
||||
|
||||
Ensure `/api/create-payment-intent` uses your real Stripe secret key.
|
||||
|
||||
## Deposit Calculation Logic
|
||||
|
||||
According to PRD, deposit is calculated as:
|
||||
- **Weekday (Mon-Fri)**: 50% of service price, max $200
|
||||
- **Weekend (Sat-Sun)**: $200 flat rate
|
||||
|
||||
Current implementation: `Math.min(service.base_price * 0.5, 200)`
|
||||
|
||||
Weekend logic needs to be added.
|
||||
|
||||
## Testing
|
||||
|
||||
### Mock Payment Testing (Current)
|
||||
- Use any valid card number (Luhn algorithm compliant)
|
||||
- Any expiration date in the future
|
||||
- Any 3-digit CVC
|
||||
- Payment always succeeds
|
||||
|
||||
### Real Stripe Testing (When Enabled)
|
||||
- Use Stripe test cards: https://stripe.com/docs/testing
|
||||
- Test success scenarios: `4242 4242 4242 4242`
|
||||
- Test failure scenarios: `4000 0000 0002` (generic decline)
|
||||
- Verify webhooks are received correctly
|
||||
- Test refunds via Stripe Dashboard
|
||||
|
||||
## Deployment Checklist
|
||||
|
||||
Before going live with Stripe:
|
||||
- [ ] Update `NEXT_PUBLIC_STRIPE_ENABLED=true`
|
||||
- [ ] Use live Stripe keys (not test keys)
|
||||
- [ ] Configure production webhook endpoint
|
||||
- [ ] Test payment flow end-to-end
|
||||
- [ ] Verify bookings are marked as confirmed
|
||||
- [ ] Test refund flow
|
||||
- [ ] Monitor Stripe dashboard for errors
|
||||
- [ ] Set up email notifications for payment failures
|
||||
211
docs/site_requirements.md
Normal file
211
docs/site_requirements.md
Normal file
@@ -0,0 +1,211 @@
|
||||
# Anchor:23 — Site Requirements
|
||||
|
||||
Documento de ejecución para OpenCode / Codex.
|
||||
Define identidad visual, estructura del sitio, copy y reglas de implementación.
|
||||
|
||||
---
|
||||
|
||||
## 1. Objetivo del sitio
|
||||
|
||||
* Representar a Anchor:23 como concepto de belleza de ultra lujo.
|
||||
* Comunicar exclusividad basada en estándar, no en aspiración.
|
||||
* Separar marca institucional de sistemas operativos (booking / kiosk).
|
||||
* Convertir sin presión: membresía y cita.
|
||||
|
||||
---
|
||||
|
||||
## 2. Arquitectura de dominios
|
||||
|
||||
* `anchor23.mx` — Sitio institucional
|
||||
* `booking.anchor23.mx` — Sistema de reservas (The Boutique)
|
||||
* `kiosk.anchor23.mx` — UI táctil en sucursal
|
||||
|
||||
El sitio **anchor23.mx** no contiene lógica compleja.
|
||||
Es contenido, marca y narrativa.
|
||||
|
||||
---
|
||||
|
||||
## 3. Paleta de Color
|
||||
|
||||
### Base
|
||||
|
||||
* Bone White `#F6F1EC` — fondo principal
|
||||
* Soft Cream `#EFE7DE` — bloques y secciones
|
||||
* Mocha Taupe `#B8A89A` — íconos y divisores
|
||||
* Deep Earth `#6F5E4F` — botones primarios
|
||||
* Charcoal Brown `#3F362E` — texto principal / footer
|
||||
|
||||
Reglas:
|
||||
|
||||
* Sin colores saturados
|
||||
* Sin gradientes
|
||||
* Sin sombras duras
|
||||
|
||||
---
|
||||
|
||||
## 4. Tipografía
|
||||
|
||||
### Headings
|
||||
|
||||
* Serif editorial sobria
|
||||
* Ejemplos: The Seasons, Canela
|
||||
|
||||
### Body / UI
|
||||
|
||||
* Sans neutral
|
||||
* Ejemplos: Inter, DM Sans
|
||||
|
||||
Reglas:
|
||||
|
||||
* Mucho espacio
|
||||
* Jerarquía estricta
|
||||
* Peso visual contenido
|
||||
|
||||
---
|
||||
|
||||
## 5. Layout
|
||||
|
||||
* Grid amplio
|
||||
* Márgenes generosos
|
||||
* Ritmo vertical lento
|
||||
* Espacio negativo dominante
|
||||
|
||||
Nunca:
|
||||
|
||||
* UI densa
|
||||
* Animaciones llamativas
|
||||
* Efectos innecesarios
|
||||
|
||||
---
|
||||
|
||||
## 6. Header
|
||||
|
||||
### Navegación
|
||||
|
||||
* Inicio
|
||||
* Nosotros
|
||||
* Servicios
|
||||
* Membresías
|
||||
|
||||
CTA principal:
|
||||
|
||||
* Solicitar Membresía
|
||||
|
||||
---
|
||||
|
||||
## 7. Landing Page
|
||||
|
||||
### Hero
|
||||
|
||||
**Título**
|
||||
ANCHOR:23
|
||||
|
||||
**Subtítulo**
|
||||
Belleza anclada en exclusividad
|
||||
|
||||
**Texto**
|
||||
Un estándar exclusivo de lujo y precisión.
|
||||
|
||||
**CTAs**
|
||||
|
||||
* Ver servicios
|
||||
* Solicitar cita
|
||||
|
||||
---
|
||||
|
||||
### Fundamento
|
||||
|
||||
**Título**
|
||||
Fundamento
|
||||
|
||||
**Subtítulo**
|
||||
Nada sólido nace del caos
|
||||
|
||||
**Texto**
|
||||
Anchor:23 nace de la unión de dos creativos que creen en el lujo no como promesa, sino como estándar.
|
||||
|
||||
Aquí, lo excepcional es norma: una experiencia exclusiva y coherente, diseñada para quienes entienden que el verdadero lujo está en la precisión, no en el exceso.
|
||||
|
||||
---
|
||||
|
||||
### Servicios Exclusivos (Preview)
|
||||
|
||||
#### Spa de Alta Gama
|
||||
|
||||
Sauna y spa excepcionales, diseñados para el rejuvenecimiento y el equilibrio.
|
||||
|
||||
#### Arte y Manicure de Precisión
|
||||
|
||||
Estilización y técnica donde el detalle define el resultado.
|
||||
|
||||
#### Peinado y Maquillaje de Lujo
|
||||
|
||||
Transformaciones discretas y sofisticadas para ocasiones selectas.
|
||||
|
||||
CTA:
|
||||
|
||||
* Ver todos los servicios
|
||||
|
||||
---
|
||||
|
||||
### Testimonios
|
||||
|
||||
Título:
|
||||
Testimonios
|
||||
|
||||
Ejemplos:
|
||||
|
||||
* "La atención al detalle define el lujo real." — Gabriela M.
|
||||
* "Exclusivo sin ser pretencioso." — Lorena T.
|
||||
|
||||
CTA:
|
||||
|
||||
* Solicitar Membresía
|
||||
|
||||
---
|
||||
|
||||
## 8. Footer
|
||||
|
||||
Contenido:
|
||||
|
||||
* Marca y ciudad
|
||||
* Links: Nosotros, Servicios, Contacto
|
||||
* Legal: Privacy Policy, Legal
|
||||
* Teléfono y correo
|
||||
|
||||
---
|
||||
|
||||
## 9. Páginas internas
|
||||
|
||||
### /servicios
|
||||
|
||||
* Listado completo
|
||||
* CTA a booking.anchor23.mx
|
||||
|
||||
### /historia
|
||||
|
||||
* Origen de Anchor
|
||||
* Significado de : y 23
|
||||
|
||||
### /contacto
|
||||
|
||||
* Formulario
|
||||
* Datos de contacto
|
||||
|
||||
### /franchises
|
||||
|
||||
* Modelo: una sucursal por ciudad
|
||||
* No franquicia masiva
|
||||
|
||||
---
|
||||
|
||||
## 10. Principios de ejecución
|
||||
|
||||
* HTML semántico
|
||||
* CSS limpio
|
||||
* JS mínimo
|
||||
* Accesibilidad básica
|
||||
* Performance sobre efectos
|
||||
|
||||
El sitio debe sentirse silencioso, sólido y permanente.
|
||||
|
||||
Reference in New Issue
Block a user