尚未偵測到更新。GitHub 發布版本後會顯示在這裡。
個人 GitHub 帳號下公開儲存庫的擁有者可以登入並驗證所有權,自行管理介紹,無需管理員核准。
登入並產生驗證檔案,在 30 分鐘內將其提交至此儲存庫的預設分支。其他分支或分叉儲存庫中的檔案無效。然後在下方檢查檔案,即可無需管理員核准直接管理專案。請保留檔案以維持管理權限。
如需登入,將前往登入頁面。登入後請回到此處,再次點擊所選的驗證按鈕。
在專案資料夾中執行 /nomorevibe verify,即可驗證所有權並自行管理介紹。
一分鐘完成驗證正在載入完整 README。 以下為已儲存的摘錄。
Panel de ventas multi-tienda / multi-usuario para bots de WhatsApp en Kapso que crean órdenes en Shopify. Kapso entrega analítica operativa; este panel agrega la analítica de ventas propia: ingresos, embudo de conversión (conversaciones → órdenes), desglose de negocio y salud operativa — todo por tienda y consolidado. Estado: Fase 1 — scaffold, modelo de datos + RLS, librerías core (crypto, Shopify, Kapso, métricas), ingesta (webhooks + cron), auth y dashboards de las 4 familias de métricas.檢視完整 README ↗
Panel de ventas multi-tienda / multi-usuario para bots de WhatsApp en Kapso que crean órdenes en Shopify. Kapso entrega analítica operativa; este panel agrega la analítica de ventas propia: ingresos, embudo de conversión (conversaciones → órdenes), desglose de negocio y salud operativa — todo por tienda y consolidado.
Estado: Fase 1 — scaffold, modelo de datos + RLS, librerías core (crypto, Shopify, Kapso, métricas), ingesta (webhooks + cron), auth y dashboards de las 4 familias de métricas.
No se consulta a Shopify/Kapso en vivo desde el dashboard. Se mantiene una base de datos propia alimentada por ingesta:
Shopify ──webhook orders/create|updated──▶ /api/webhooks/shopify/[storeId]
Shopify ──backfill/reconciliación (cron)──▶ /api/cron/sync (query: tag:kapso)
Kapso ──pull conversaciones/mensajes────▶ /api/cron/sync (Platform API)
│
▼
Postgres (orders, conversations, ops_snapshots)
│
recálculo ▼
daily_rollups
│
▼
Dashboards (lib/metrics.ts) — por tienda + consolidado
daily_rollups solo cuenta los pedidos del bot (tag:kapso). «Canal de
cierre» cuenta TODAS las ventas de la tienda desde la migración 0259, y desde
la 0268 también la cabecera del tablero, «Ventas por día», «Por tienda» y
«Conversión por fuente», con su canal de cierre, por funciones de lectura en Postgres
(ventas_por_origen, canal_de_cierre, conversion_por_fuente; MOM §17.3 y
§17.4). Los módulos que siguen leyendo los pedidos del bot lo dicen.
El enlace orden ↔ conversación se hace con los note_attributes que el bot
escribe en cada orden Shopify: kapso_conversation_id, kapso_phone_number_id,
source=whatsapp-bot.
organizations → memberships (rol owner/admin/viewer) → stores,
con acceso fino por tienda vía user_store_access. RLS filtra cada tabla
con store_id/org_id por las tiendas accesibles del usuario autenticado:
owner/admin de una organización ven todas sus tiendas.viewer ve solo las tiendas que le fueron concedidas explícitamente.La ingesta (webhooks/cron) escribe con la service role key (bypassa RLS); el dashboard solo lee bajo RLS.
lib/crypto.ts) usando ENCRYPTION_KEY y se guardan en la BD. Se descifran
solo en el servidor, bajo demanda. Nunca viajan al cliente ni se commitean..env, en el repo ni en el código. El hosting solo
recibe secretos de infraestructura (ENCRYPTION_KEY, claves Supabase,
CRON_SECRET).X-Shopify-Hmac-Sha256, comparación en
tiempo constante) con el secreto por tienda descifrado./api/webhooks/kapso/[storeId] se
autentica con un secreto por tienda (?secret=…, en Ajustes → Rotar
credenciales), comparado en tiempo constante. Cuando una tienda define el
suyo, solo ese secreto la autoriza — el CRON_SECRET compartido deja de servir
para esa tienda, así un dueño no puede inyectar leads en la tienda de otro.
Las tiendas sin secreto propio conservan el CRON_SECRET como respaldo
(compatibilidad); configúralo antes de dar acceso a dueños externos.webhook_events (store_id, topic, shopify_id).CRON_SECRET.lib/metrics.ts)source=whatsapp-bot) → tasa por tienda/día; enlace fino por
kapso_conversation_id.promo-whatsapp), # stock-por-validar,
contraentrega vs. agencia, top productos (de line_items), patrón por
fecha/hora.GET /whatsapp/phone_numbers/{id}/health), errores/latencia
(GET /api_logs), actividad 24h (derivada de conversaciones/mensajes),
capturado en ops_snapshots.https://{shop}.myshopify.com/admin/api/{version}/graphql.json, header
X-Shopify-Access-Token. Webhooks orders/create y orders/updated apuntan a
/api/webhooks/shopify/[storeId]. Reconciliación/backfill con
orders(query: "tag:kapso updated_at:>=<cursor>").
Base https://api.kapso.ai/platform/v1, header X-API-Key. Endpoints usados
(confirmados con la doc oficial):
| Uso | Endpoint |
|---|---|
| Conversaciones | GET /whatsapp/conversations (cursor; filtros phone_number_id, status, created_after, last_active_after) |
| Mensajes | GET /whatsapp/messages (cursor; filtros conversation_id, direction, …) |
| Salud del número | GET /whatsapp/phone_numbers/{phone_number_id}/health |
| Logs / errores / latencia | GET /api_logs (errors_only, status_code, period) |
La familia operativa es best-effort: si un endpoint no está disponible para un proyecto, se deriva de conversaciones/mensajes y se marca como tal.
pnpm install
cp .env.example .env.local # completa los secretos de infraestructura
# Aplica el esquema + RLS a tu base Supabase:
psql "$DATABASE_URL" -f db/migrations/0001_init.sql
psql "$DATABASE_URL" -f db/migrations/0002_rollups.sql
psql "$DATABASE_URL" -f supabase/policies.sql
pnpm seed # (opcional) datos demo
pnpm dev
Ver .env.example. Solo secretos de infraestructura + config no-secreta:
NEXT_PUBLIC_SUPABASE_URL, NEXT_PUBLIC_SUPABASE_ANON_KEY,
SUPABASE_SERVICE_ROLE_KEY, DATABASE_URL, ENCRYPTION_KEY, CRON_SECRET,
NEXT_PUBLIC_SITE_URL, SHOPIFY_API_VERSION, KAPSO_API_BASE.
# Genera ENCRYPTION_KEY (32 bytes base64) y CRON_SECRET:
openssl rand -base64 32
openssl rand -hex 32
pnpm test # vitest run (54 unit tests)
pnpm typecheck # tsc --noEmit
bash scripts/verify-db.sh # DB layer on a throwaway Postgres (see below)
Unit (Vitest) covers: round-trip of AES-GCM encryption (+ tamper detection),
Shopify HMAC verification, order mapping Shopify→orders (REST & GraphQL),
Shopify/Kapso query building, webhook orchestration (HMAC gate + idempotent
re-delivery), each metric family, and the demo generator.
scripts/verify-db.sh spins up a throwaway Postgres 16 cluster (never your
Supabase DB), applies the migrations + RLS policies, and asserts:
recompute_daily_rollups() matches the TS
computeDailyRollups() exactly.app/
(auth)/login # login (Google + magic link)
auth/callback # intercambio de código OAuth/OTP
dashboard/ # layout protegido + selector tienda/fechas
page.tsx # consolidado
[storeId]/page.tsx # detalle por tienda (4 familias)
stores/new # onboarding "Conectar tienda"
api/
webhooks/shopify/[storeId]/route.ts
cron/sync/route.ts
lib/ db, crypto, shopify, kapso, metrics, types, env
db/migrations/*.sql
supabase/policies.sql
scripts/seed.ts
test/*.test.ts