尚未偵測到更新。GitHub 發布版本後會顯示在這裡。
個人 GitHub 帳號下公開儲存庫的擁有者可以登入並驗證所有權,自行管理介紹,無需管理員核准。
登入並產生驗證檔案,在 30 分鐘內將其提交至此儲存庫的預設分支。其他分支或分叉儲存庫中的檔案無效。然後在下方檢查檔案,即可無需管理員核准直接管理專案。請保留檔案以維持管理權限。
如需登入,將前往登入頁面。登入後請回到此處,再次點擊所選的驗證按鈕。
在專案資料夾中執行 /nomorevibe verify,即可驗證所有權並自行管理介紹。
一分鐘完成驗證Real-time sprint retrospectives where the action items actually get done. Next.js 16, React 19, TypeScript, Socket.IO, PostgreSQL, Prisma.
翻譯準備中
正在載入完整 README。
檢視完整 README ↗Sprint retrospectives where the action items actually get done.
Live: https://retroloop-one.vercel.app — start a retro and open the invite link in a second browser to see it from two sides. (The API runs on a free instance that sleeps when idle, so the very first request can take up to a minute.)
A real-time retrospective board for teams: everyone writes cards anonymously, the cards are revealed, grouped and voted on, and the retro ends with a short list of action items — each with an owner and a due date, carried into the next retro until it is done. Participants join by link, no sign-up.
Why another retro tool: less than half of retrospective action items get completed in most teams, and existing tools stop at the board. See docs/RESEARCH.md.
| Write — teammates' cards stay hidden until the reveal | Group — drag similar cards together |
| Review — the next retro starts with last time's items | Landing — in English, Ukrainian, Russian and Portuguese |
Phase by phase, one or more commits each:
| Part | Tech |
|---|---|
| Web app | Next.js 16 (App Router), React 19, TypeScript, Tailwind CSS 4 |
| Realtime server | Node.js 24, Fastify 5, Socket.IO 4 |
| Data | PostgreSQL 18 + Prisma 7; Redis 8 to run several server instances (optional with one) |
| Shared contract | @retro/shared — socket events and payload schemas (zod), used by both sides |
| i18n | next-intl: English, Ukrainian, Russian, Portuguese on locale-prefixed routes; message keys type-checked |
| Production | Docker images for both apps, Caddy with automatic HTTPS, see docs/DEPLOY.md |
| Testing | Vitest (unit + integration on real Postgres/Redis), Playwright end-to-end, a load-test script |
| Tooling | npm workspaces, ESLint, tsup, Docker Compose, GitHub Actions |
apps/web Next.js app (UI, i18n messages, operator stats page)
apps/server Fastify + Socket.IO realtime server, Prisma schema and migrations,
load-test and stats scripts
packages/shared Wire protocol and types shared by web and server
e2e/ Playwright end-to-end tests
deploy/ Caddy config for the self-hosted setup
docs/ Research, deployment, performance, screenshots
The web app and the realtime server are separate processes: Next.js serves the UI,
the server keeps the WebSocket connections and owns the board state. Every event
that crosses the wire is declared once in packages/shared, so a change to the
protocol fails type-checking on both sides instead of at runtime.
Requires Node.js 22.12+ (24 recommended) and Docker.
cp .env.example .env
npm install
npm run db:up # PostgreSQL on :5433, Redis on :6380, Mailpit on :8025
npm run db:migrate
npm run dev # web on http://localhost:3001, server on http://localhost:4000
Start a retro on the home page, then open the invite link in another browser (or a private window) to join as a second person.
GET http://localhost:4000/health reports each dependency and answers 503
within a second if one of them is down.
| Stage | What happens | Enforced on the server |
|---|---|---|
| Write | Everyone adds cards | Other people's text is not sent to the browser at all — only a placeholder — so it can't be read in DevTools |
| Group | Cards are revealed; drag a card onto a similar one to group them | Groups are one level deep; deleting a group's top card promotes the next one |
| Vote | Everyone spends a limited number of votes on groups | The limit is checked in a transaction that locks the voter's row: 10 parallel votes with a limit of 3 store exactly 3. Totals stay hidden |
| Discuss | Groups ranked by votes; the facilitator highlights the current topic; the team agrees on action items | Vote totals are revealed only now. Every action item needs an owner and a due date, and there are at most three per retro — checked under a row lock, so parallel adds can't overshoot |
| Wrap up | What was agreed, the team's follow-through score, exports, the link to the next retro |
A team's retros form a series. When the facilitator starts the next retro, it opens with a review of every action item still open from earlier ones: done, not yet (with a new due date), or dropped. Items that are not done keep coming back until they are; the review stage is skipped when nothing is open.
The follow-through score — the share of action items from earlier retros that actually got done — is shown at the review and at the end of every retro. It is also the product's success metric: most teams finish under half of their retro action items (see docs/RESEARCH.md).
Owners can ask for one e-mail reminder the day before an item is due, in their language; the address is deleted as soon as it is sent and never reaches other browsers. Reminders work with any SMTP provider and are simply hidden when none is configured (in development they land in Mailpit at http://localhost:8025).
Agreed items leave the tool the way teams already work: Markdown for a wiki or chat, CSV that Jira's importer maps without setup, a prefilled GitHub issue link, and an .ics calendar event on the due date for the owner.
Whoever creates a retro gets a facilitator key (kept in their browser, stored as a hash); only the facilitator moves between stages, runs the timer and can hand the role over. Card authors are never sent to other participants in any stage — the client only learns "mine" or "not mine". The timer runs on the server clock; each browser corrects for its own clock offset, measured on join.
Every retro ends with a one-question survey — how useful was this retro? — with an optional comment and explicit consent to quote it without a name. Together with anonymous product events (a retro was created, a stage was reached, an export was used — never who, never what was written) this is how the product measures whether it helps.
There are no accounts, no tracking cookies and no ads. A test checks that no team name, participant name, card text or comment ever ends up in an analytics event. Teams with no retro for a year are deleted automatically, and a facilitator can delete a retro at any time. Public endpoints are rate-limited: 10 new teams a minute per address, and each socket gets a token bucket (bursts of 40 events, 10 a second sustained).
With ADMIN_TOKEN set, the operator gets a stats page at /en/admin: how far
teams get (created → discussed → finished → came back for another retro), survey
ratings and the comments people agreed to have quoted, the follow-through rate
on reviewed action items, and new teams per week. npm run stats -w @retro/server
prints the same numbers as a Markdown table for this README.
npm run typecheck
npm run lint
npm test
npm run build
npm run test:e2e # Playwright; reuses `npm run dev` if it is running
End-to-end tests drive several real browsers through whole retros: anonymous writing (the hidden text is checked against the page HTML, not just the screen), drag-and-drop grouping, the vote limit, action items with CSV and calendar downloads, the next retro's review, the Ukrainian locale, the survey and deleting a retro.
Server tests are integration tests: they start the real server and talk to it over
Socket.IO, against a separate retro_test PostgreSQL database (created and migrated
automatically, so npm run db:up must be running). CI runs the same steps on every
push against a fresh PostgreSQL.