尚未偵測到更新。GitHub 發布版本後會顯示在這裡。
個人 GitHub 帳號下公開儲存庫的擁有者可以登入並驗證所有權,自行管理介紹,無需管理員核准。
登入並產生驗證檔案,在 30 分鐘內將其提交至此儲存庫的預設分支。其他分支或分叉儲存庫中的檔案無效。然後在下方檢查檔案,即可無需管理員核准直接管理專案。請保留檔案以維持管理權限。
如需登入,將前往登入頁面。登入後請回到此處,再次點擊所選的驗證按鈕。
在專案資料夾中執行 /nomorevibe verify,即可驗證所有權並自行管理介紹。
一分鐘完成驗證正在載入完整 README。 以下為已儲存的摘錄。
Aplicación de finanzas personales. Si no tenés pnpm instalado todavía, elegí una de estas opciones: • Rápido (recomendado si tenés Node ≥ 16.13): • Canónico: seguir las instrucciones de pnpm.io/installation.檢視完整 README ↗
Aplicación de finanzas personales.
Si no tenés pnpm instalado todavía, elegí una de estas opciones:
corepack enable pnpm
Verificá que quedó disponible:
pnpm --version
pnpm install
Si ves un warning tipo
[ERR_PNPM_IGNORED_BUILDS]mencionando paquetes como@parcel/watchero@swc/core, no es un error: pnpm pide tu autorización explícita para correr los build scripts de esas dependencias (es una protección contra paquetes maliciosos). En este repo ya dejamos preaprobados los paquetes seguros en la secciónpnpm.onlyBuiltDependenciesdepackage.json, así que normalmente no debería aparecer. Si igual aparece (por ejemplo después de agregar una dependencia nueva), corré:pnpm approve-buildsTe va a abrir un menú interactivo: con la barra espaciadora seleccionás los paquetes a aprobar y con Enter confirmás. Para los paquetes que ya están en el proyecto (
@parcel/watcher,@swc/core) es seguro aprobarlos.
Copia el archivo de ejemplo y completa tus credenciales de Supabase:
cp apps/web/.env.example apps/web/.env
Next.js carga el
.envdesde el cwd de la app, por eso vive enapps/web/, no en la raíz del repo.
| Variable | Dónde encontrarla |
|---|---|
NEXT_PUBLIC_SUPABASE_URL | Panel de Supabase → Project Settings → API → Project URL |
NEXT_PUBLIC_SUPABASE_ANON_KEY | Panel de Supabase → Project Settings → API → Publishable key |
Antes de levantar la app por primera vez, en el panel de Supabase:
Authentication → Providers → Email
Authentication → URL Configuration
http://localhost:3000 en desarrollo, tu dominio en producción.http://localhost:3000/auth/callbackhttps://<tu-dominio>/auth/callback (cuando despliegues)Authentication → Email Templates
Los templates viven versionados en el repo bajo supabase/templates/. El repo es la source of truth — el dashboard de Supabase es un mirror manual: mantenerlo al día es un paso que hace una persona, cada vez. Los asuntos de los mails, en cambio, hoy viven sólo en el dashboard: no están versionados acá.
Para cada uno de estos dos templates, abrí el archivo del repo, copiá el contenido completo del body y pegalo en el campo correspondiente del dashboard:
| Template del dashboard | Archivo en el repo |
|---|---|
| Confirm signup | supabase/templates/confirm-signup.html |
| Reset password | supabase/templates/reset-password.html |
Como doble check, los enlaces dentro de cada template deben respetar estas formas exactas (el callback de la app las parsea con esa estructura):
confirm-signup → {{ .SiteURL }}/auth/callback?token_hash={{ .TokenHash }}&type=signup
reset-password → {{ .SiteURL }}/auth/callback?code={{ .Token }}&next=/reset-password
Si el dashboard y el repo divergen alguna vez, sobrescribí el dashboard con el contenido del repo, nunca al revés. Los subjects (asuntos) por ahora siguen viviendo solo en el dashboard.
Ejecutar en SQL Editor:
# El archivo está en supabase/migrations/0001_profiles.sql
Copiar y pegar el contenido del archivo; correrlo una vez. Crea la tabla public.profiles, su RLS y el trigger on_auth_user_created que la mantiene sincronizada con auth.users.
pnpm dev
La app estará disponible en http://localhost:3000.
El repo está configurado para usar OpenSpec como flujo de spec-driven development. Los skills y slash commands ya vienen versionados en .claude/ (Claude Code) y .agents/ (Codex), pero el CLI se instala aparte:
pnpm add -g @fission-ai/openspec
Una vez instalado, dentro de Claude Code podés usar:
/grana-lightweight-explore — pensar / refinar una idea antes de proponerla: corto y sin escribir nada/grana-deep-explore — el /opsx:explore original de OpenSpec, palabra por palabra: largo, con diagramas, y puede escribir artefactos de OpenSpec si le decís que sí/opsx:propose "<idea>" — crear una nueva propuesta de cambio/opsx:apply — implementar las tasks de un cambio/opsx:update — revisar los artefactos de un cambio ya propuesto/opsx:sync — bajar las deltas del cambio a las specs maestras/opsx:archive — archivar un cambio ya completadoLas propuestas viven en openspec/changes/ y las specs en openspec/specs/.
Los comandos sin sufijo apuntan a apps/web. Para mobile usá los sufijos :mobile o pnpm --filter mobile <script>.
| Script | Descripción |
|---|---|
pnpm dev | Inicia el servidor de desarrollo de web |
pnpm build | Compila la app web para producción |
pnpm start | Ejecuta la build de producción de web |
pnpm lint | Ejecuta ESLint sobre apps/web |
pnpm typecheck | Type-check de apps/web |
pnpm test | Tests (Vitest) de apps/web |
pnpm storybook | Levanta Storybook en el puerto 6006 (web) |
pnpm dev:mobile | Inicia Expo dev server |
pnpm lint:mobile | Lint de apps/mobile |
pnpm typecheck:mobile | Type-check de apps/mobile |
pnpm eas:android | Build de Android con EAS (remoto) |
pnpm eas:ios | Build de iOS con EAS (remoto) |
pnpm openspec:check | Valida que ningún spec maestro tenga Purpose: TBD residual |
pnpm check:openspec-workflows | Valida que los workflows generados por OpenSpec sigan siendo cinco |
pnpm check:duplicate-deps | Falla si react o react-native quedaron duplicados en el workspace |
pnpm check:test-timezone | Falla si algún script test no corre en la zona horaria financiera |
pnpm verify | Todo lo que corre CI y se puede correr local, en un comando |
apps/web/components/ui/ con su Storybook story al lado. Antes de inventar un wrapper compuesto, ver si se puede componer con los primitivos existentes.bg-background, text-foreground, text-destructive, etc.). Los tokens viven en packages/ui-tokens/src/theme.css y apps/web/app/globals.css los importa. Nada de bg-zinc-*/text-gray-* directos — rompen el dark mode.next-intl con cookie NEXT_LOCALE (sin segmento [locale] en la URL). Los locales soportados están en apps/web/lib/i18n/config.ts; los catálogos en packages/i18n-messages/src/<locale>.json (consumidos vía @grana/i18n-messages). El switcher vive en el footer.packages/validation/src/ (paquete @grana/validation), compartidos entre los forms (react-hook-form + yupResolver) y los server actions (validateActionInput). El bridge React/next-intl (setup-yup-locale.tsx) se queda en apps/web/lib/validation/ porque depende del runtime de next-intl.packages/supabase/ (paquete @grana/supabase, expone createClient + slot Database). Los wrappers Next-aware (createBrowserClient / createServerClient con cookies de @supabase/ssr) viven en apps/web/lib/supabase/.ActionResult<T> = { ok: true } | { ok: false, fieldErrors?, formError? }. Los errores se muestran en la ruta con estado local, no por querystring.El repo es un monorepo pnpm con dos apps: web (apps/web, Next.js App Router) y mobile (apps/mobile, Expo). Comparten datos en Supabase y código vía los paquetes packages/*.
grana-v3/
├── apps/
│ ├── web/ # Next.js App Router
│ │ ├── app/ # rutas, layouts, server actions
│ │ ├── components/ # primitivos UI (HTML) + features web
│ │ ├── lib/ # código específico de web (supabase ssr, i18n runtime, etc.)
│ │ ├── .storybook/
│ │ ├── public/ # activos estáticos
│ │ ├── .env / .env.example # vars de entorno (Next las lee desde el cwd de la app)
│ │ ├── next.config.ts # `transpilePackages` incluye los @grana/*
│ │ └── tsconfig.json # extiende `../../tsconfig.base.json`
│ └── mobile/ # Expo (React Native) — espejo funcional del web
│ ├── app/ # rutas Expo Router
│ ├── components/ # primitivos UI (RN) + features mobile
│ ├── lib/ # código específico de mobile (supabase client RN, i18n RN)
│ └── app.json # config de Expo
├── packages/
│ ├── validation/ # @grana/validation — schemas Yup + helpers (cross-platform)
│ ├── i18n-messages/ # @grana/i18n-messages — catálogos JSON
│ ├── supabase/ # @grana/supabase — slot Database + createClient factory
│ ├── ui-tokens/ # @grana/ui-tokens — design tokens (CSS variables, web + mobile)
│ └── dashboard/ # @grana/dashboard — queries + agregaciones del dashboard
├── supabase/ # SQL migrations + email templates (backend, no es una app)
├── openspec/ # workflow spec-driven
├── AGENTS.md # instrucciones canónicas para LLMs (Claude Code, Codex, Cursor, …)
├── CLAUDE.md # stub que apunta a AGENTS.md (compat con tooling que carga CLAUDE.md)
├── SUPABASE_SETUP.md
├── README.md
├── package.json # orquestador con scripts para web y mobile
├── pnpm-workspace.yaml # declara `apps/*` y `packages/*`
├── tsconfig.base.json # base TS con paths `@grana/*` → source directa
└── .npmrc # hoist patterns necesarios para eslint-config-next
Reglas rápidas:
apps/<name>/.packages/<name>/.AGENTS.md → "Web ↔ Mobile policy"). No se comparte JSX entre web y React Native.Por ser monorepo, Vercel necesita saber qué subdirectorio buildear. En el dashboard del proyecto → Settings → Build & Development Settings → Root Directory, setear apps/web. Las env vars del proyecto (NEXT_PUBLIC_SUPABASE_URL, NEXT_PUBLIC_SUPABASE_ANON_KEY) no cambian. Vercel detecta el pnpm-workspace.yaml en la raíz y corre pnpm install desde ahí.
Acción única por entorno: hay que cambiarlo antes del primer push post-migración para evitar un build rojo. Sin Root Directory ajustado, Vercel buildea la raíz y no encuentra Next.
SUPABASE_SETUP.md)