Serein
Rust로 만든 가볍고 성능 좋은 Discord 전용 네이티브 클라이언트
TuTribu: 개인·직업적 성장을 위한 학습·공유·네트워킹 플랫폼
TuTribu: la plataforma donde los usuarios pueden aprender, compartir conocimientos y conectar con una tribu enfocada en el crecimiento personal y profesional.
소셜TypeScript · HTMLGitHub @guidomodarelli온라인운영자 미확인
써 보셨어요? 한 번만 눌러 주세요. 로그인은 필요 없어요.
아직 감지된 업데이트가 없습니다. GitHub 릴리스가 나오면 여기에 보입니다.
개인 계정의 공개 저장소 소유자는 GitHub로 로그인해 운영자를 확인하고 소개를 직접 관리할 수 있습니다. 관리자 승인은 필요하지 않습니다.
로그인한 뒤 확인 파일을 만들어 이 저장소의 기본 브랜치에 30분 안에 커밋해 주세요. 다른 브랜치나 포크의 파일은 인정하지 않습니다. 파일을 올린 뒤 아래에서 확인하면 관리자 승인 없이 관리할 수 있습니다. 자격을 유지하려면 파일을 남겨 두세요.
로그인이 필요하면 로그인 화면으로 이동합니다. 로그인 후 이곳으로 돌아와 원하는 확인 버튼을 다시 눌러 주세요.
프로젝트 폴더에서 /nomorevibe verify를 실행하면 소유권을 확인하고 소개를 직접 관리할 수 있습니다.
1분 만에 확인하기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. |