尚未偵測到更新。GitHub 發布版本後會顯示在這裡。
個人 GitHub 帳號下公開儲存庫的擁有者可以登入並驗證所有權,自行管理介紹,無需管理員核准。
登入並產生驗證檔案,在 30 分鐘內將其提交至此儲存庫的預設分支。其他分支或分叉儲存庫中的檔案無效。然後在下方檢查檔案,即可無需管理員核准直接管理專案。請保留檔案以維持管理權限。
如需登入,將前往登入頁面。登入後請回到此處,再次點擊所選的驗證按鈕。
在專案資料夾中執行 /nomorevibe verify,即可驗證所有權並自行管理介紹。
一分鐘完成驗證La plataforma donde los usuarios pueden aprender, compartir conocimientos y conectar con una comunidad enfocada en el crecimiento personal y profesional
翻譯準備中
取自儲存庫 README
正在載入完整 README。 以下為已儲存的摘錄。
TuTribu is a Next.js App Router application built around hexagonal architecture and module-scoped features.
• Read AGENTS.md before editing code.
• Read DESIGN.md before creating or changing UI.
• Review docs/architecture/*.htm before changes that affect architecture, authentication, authorization, provider integrations, data flow, or modular structure.
• Keep all technical names in English.
• Keep user-facing product text in Spanish.
• Prefer src/modules/ /{domain,application,infrastructure} for business code.檢視完整 README ↗TuTribu is a Next.js App Router application built around hexagonal architecture and module-scoped features.
AGENTS.md before editing code.DESIGN.md before creating or changing UI.docs/architecture/*.htm before changes that affect architecture, authentication, authorization, provider integrations, data flow, or modular structure.src/modules/<feature>/{domain,application,infrastructure} for business code.pg.nvmrc; use fnm use or nvm use)packageManager; run corepack enable and the pinned version is used automatically)Install dependencies:
pnpm install --frozen-lockfile
Create .env.local from .env.example and fill in the values (see Environment).
Apply database migrations:
pnpm run db:migrate
Start the dev server through portless (checks that dev.tutribu.app resolves to 127.0.0.1 through its public DNS record, restarts the proxy on the tutribu.app TLD, trusts the local CA for the current user and runs next dev). Requires portless 0.15.5 or newer (npm install -g portless@latest), the first release that accepts the dotted tutribu.app TLD. The hosts file is never written; on Windows no step asks for administrator privileges, while on macOS and Linux portless asks for sudo once to bind the HTTPS proxy to port 443:
pnpm run dev
The app is then served at https://dev.tutribu.app. Use pnpm run dev -- --dry-run to see the steps without changing anything.
| Script | Description |
|---|---|
pnpm run dev | Start the Next.js dev server through portless at https://dev.tutribu.app (portless 0.15.5+ check, DNS check, proxy restart, CA trust, next dev with hot reload). Needs sudo once on macOS and Linux to bind port 443; no administrator privileges on Windows. Accepts --dry-run. |
pnpm run dev:next | Bare next dev on a plain port. Reserved for the Playwright web server of the e2e suite; use pnpm run dev for manual work. |
pnpm run build | Build the production bundle. |
pnpm run build:cloudflare | Build the Cloudflare Workers bundle with OpenNext. |
pnpm run preview:cloudflare | Build and preview the app locally in the Cloudflare Workers runtime. |
pnpm run deploy:cloudflare | Build and deploy the app to Cloudflare Workers. |
pnpm run upload:cloudflare | Build and upload a new Cloudflare Workers version without deploying it. |
pnpm run cf-typegen | Generate Cloudflare binding types from wrangler.jsonc. |
pnpm start | Run the production build locally. |
pnpm run ci | Run the full quality gate (also run by GitHub Actions on pushes to main and on pull requests): lint, application/test type checks, Vitest, and Next.js build. |
pnpm run lint | Run golfo-lint lint: bun lint with the @golfo/lint/eslint preset (configured in eslint.config.mjs; needs Bun canary until 1.4.5). |
pnpm run typecheck | Type-check production code with bun check (Bun's type checker, same errors as tsc from TypeScript 7). |
pnpm run typecheck:tests | Type-check the tests with bun check against tsconfig.test.json. |
pnpm test | Run Vitest unit and integration tests. |
pnpm run test:watch |
Create .env.local from .env.example and provide:
DATABASE_URL: runtime Postgres connection string. Use the direct Neon URL for warm runtime environments. Do not use the -pooler host here unless the deployment explicitly needs PgBouncer-style transaction pooling.DATABASE_MIGRATION_URL: optional direct Postgres connection string for migrations and tooling.BETTER_AUTH_URLBETTER_AUTH_SECRETGOOGLE_CLIENT_IDGOOGLE_CLIENT_SECRETCONTACT_EMAIL: optional contact email shown when tribe creation is not available. Leave it empty to hide the contact action.Generate a strong random value for BETTER_AUTH_SECRET.
PowerShell (Windows):
[Convert]::ToBase64String((1..32 | ForEach-Object { Get-Random -Maximum 256 }))
Cross-platform via Node.js:
node -e "console.log(require('crypto').randomBytes(32).toString('base64'))"
POSIX shells with OpenSSL available:
openssl rand -base64 32
Local example (illustrative only — use least-privilege credentials for DATABASE_URL once available, and reserve owner/migration credentials for DATABASE_MIGRATION_URL):
DATABASE_URL=postgresql://user:[email protected]/database?sslmode=verify-full&channel_binding=require
DATABASE_MIGRATION_URL=postgresql://user:[email protected]/database?sslmode=verify-full&channel_binding=require
BETTER_AUTH_URL=https://dev.tutribu.app
BETTER_AUTH_SECRET=replace-with-a-strong-random-secret
GOOGLE_CLIENT_ID=replace-with-google-client-id
GOOGLE_CLIENT_SECRET=replace-with-google-client-secret
TUTRIBU_BACKEND_BASE_URL=
[email protected]
Neon role and schema guidance:
public schema is acceptable for local development and early project setup.public unless the application needs stronger separation between apps, modules, tenants, or permission scopes within the same database.DATABASE_URL should use a runtime role with limited permissions over a direct Neon connection, while DATABASE_MIGRATION_URL can use the owner or migration role needed for schema changes./api/maintenance/image-cleanup and the event-reminder and notification-purge cron at /api/maintenance/event-reminders) drives owner-only SECURITY DEFINER functions whose EXECUTE the migrations hold to the schema owner or a dedicated maintenance role, never the shared request role. So that the sweep does not fail with permission denied when DATABASE_URL is the least-privilege runtime role, set DATABASE_MAINTENANCE_URL to a connection whose role retains EXECUTE on those functions (the owner or a dedicated maintenance role). When it is unset, maintenance falls back to DATABASE_MIGRATION_URL and then to DATABASE_URL, which only works where the runtime role already owns the schema (local and early setup).This project uses Better Auth with Google OAuth and Neon Postgres through Drizzle and pg.
Before testing sign-in locally:
GOOGLE_CLIENT_ID and GOOGLE_CLIENT_SECRET.https://dev.tutribu.app.https://dev.tutribu.app/api/auth/callback/google.Other integrations derive their URLs from BETTER_AUTH_URL. After moving it to https://dev.tutribu.app (for example, from the former https://dev-tutribu.app), also update them by hand:
https://dev.tutribu.app/api/mercado-pago/oauth/callback as a Redirect URL. The seller connection sends BETTER_AUTH_URL + /api/mercado-pago/oauth/callback as redirect_uri, and Mercado Pago rejects it unless it matches a registered Redirect URL exactly.node scripts/configure-r2-cors.mjs with BETTER_AUTH_URL=https://dev.tutribu.app (from .env.local or the shell) so the development bucket allows the new origin for presigned lesson and message attachment uploads; Cloudflare matches origins exactly. The script replaces the bucket CORS rules and needs an R2 token with bucket configuration permission; pnpm run dev does not run it. Alternatively, add https://dev.tutribu.app to the bucket's CORS AllowedOrigins by hand.Security notes:
FAILED_TO_GET_SESSION response before surfacing the failure, which protects requests from stale or restarted database connections without hiding persistent schema or credential errors.TDD is mandatory for every feature, bug fix, and architectural change. The sequence is always testing → code → refactor → green. See AGENTS.md for the full TDD policy and per-layer testing responsibilities.
Day-to-day commands:
pnpm test # Unit + integration (Vitest)
pnpm run test:watch # Vitest in watch mode
pnpm run test:e2e # Playwright E2E
Before closing any task, both of the following must pass:
pnpm run typecheck
pnpm run lint
Commits and pushes run no local quality hooks. GitHub Actions runs the full pnpm run ci gate after a frozen-lockfile install on pushes to main, pull requests and manual dispatches; pushes to other branches are validated through their pull request. Tags do not trigger the gate. The workflow installs Node.js from .nvmrc and pnpm from packageManager. Configure Quality gate as a required status check in branch protection to block merges on failures. Vercel remains the default Next.js deployment target and continues to use pnpm run build with deployment environment variables available.
Cloudflare Workers is supported through @opennextjs/cloudflare and wrangler.jsonc. Use the Cloudflare-specific scripts instead of invoking wrangler directly for the Next.js app:
pnpm run build:cloudflare
pnpm run preview:cloudflare
pnpm run deploy:cloudflare
OpenNext warns that Windows local builds can hit runtime-specific failures. Prefer Linux, WSL with Node.js installed, or the Cloudflare build environment for final Cloudflare validation.
The orphan-image cleanup sweep runs as a scheduled job on both targets against /api/maintenance/image-cleanup: Vercel installs it from vercel.json, and Cloudflare installs the matching schedule from wrangler.jsonc (triggers.crons) through the cloudflare/worker.ts entrypoint. Configure CRON_SECRET as a Cloudflare Worker secret so the scheduled sweep is authorized; without it the sweep is skipped and the cron fails visibly. Keep both schedules in sync. See docs/architecture/deployment-targets.htm.
Notes:
app/ — App Router can treat colocated special files as route artifacts.app/* — App Router entrypoints and route composition (Server Components by default).src/modules/<feature>/{domain,application,infrastructure} — business code organized by vertical slice following hexagonal architecture. Dependencies always point inward.
domain/ — entities, value objects, ports. No framework or infrastructure details.application/ — use cases, commands, queries, results.infrastructure/ — adapters for auth, persistence, HTTP clients, and provider SDKs. Owns external DTOs and their mappers.src/modules/shared/* — cross-module shared code (e.g. infrastructure/database/).@golfo/ui — shared UI implementation, maintained in the sibling repository. Import named components from the package root.@golfo/ui@^2.0.0 — shared UI package installed from the public npm registry, with its exact version and integrity pinned in pnpm-lock.yaml; see the shared UI contract.components/<scope>/<component>/{index.tsx,styles.module.scss} — custom presentational components.lib/* — framework-safe helpers, UI utilities, and client-only adapters. Off-limits to application and domain.database/migrations/* — versioned SQL migrations (source of truth for schema and RLS policies).docs/architecture/*.htm — authoritative architectural decisions. Conflicts with AGENTS.md resolve in favor of docs/architecture.| Run Vitest in watch mode. |
pnpm run test:e2e | Run Playwright E2E tests. |
pnpm run test:e2e:ui | Run Playwright with the interactive UI runner. |
pnpm run test:e2e:beezping | Run the Beezping widget E2E spec (Chromium and WebKit, desktop and mobile) against https://dev.tutribu.app. Requires pnpm run dev with SITEPING_ENABLED on; excluded from test:e2e. |
pnpm run db:migrate | Apply pending SQL migrations to the configured Neon database. |
pnpm run db:migrate:force | Force a Drizzle push. Use only when an intentional override is required. |
pnpm create-version (alias pnpm cv) | Diagnose the repository and ship a release from main: update main, apply pending migrations (after confirmation), stop if the CHANGELOG.md [Unreleased] block is missing or has no entries, bump the version (--bump patch|minor|major or -b p|m|M, the shortcuts --patch/-p, --minor/-m, --major/-M, or --set-version X.Y.Z/-sv X.Y.Z, only the next patch/minor/major; -l is --local) renaming [Unreleased] to [X.Y.Z] - date (Argentina date through releaseTimeZone) in the version commit with a new empty [Unreleased] on top, and push main plus the vX.Y.Z tag. --dry-run only shows the plan. Runs the shared golfo-rp create-version command, configured for TuTribu in golfo-rp.config.mjs. See docs/conventions/release-process.htm. |