{"id":45219139,"url":"https://github.com/agustinusnathaniel/spoker","last_synced_at":"2026-04-01T23:31:01.727Z","repository":{"id":37015338,"uuid":"339353816","full_name":"agustinusnathaniel/spoker","owner":"agustinusnathaniel","description":"My take on making scrum poker room","archived":false,"fork":false,"pushed_at":"2026-01-28T14:02:01.000Z","size":4230,"stargazers_count":66,"open_issues_count":1,"forks_count":12,"subscribers_count":1,"default_branch":"main","last_synced_at":"2026-01-29T06:10:12.635Z","etag":null,"topics":["built-with-react","chakra-ui","firebase","nextjs","planning-poker","scrum","scrum-agile","scrum-poker","scrumpoker","typescript","webapp"],"latest_commit_sha":null,"homepage":"https://spoker.dev","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/agustinusnathaniel.png","metadata":{"funding":{"github":"sozonome","patreon":null,"open_collective":null,"ko_fi":"sozonome","tidelift":null,"community_bridge":null,"liberapay":"sozonome","issuehunt":null,"otechie":null,"lfx_crowdfunding":null,"custom":["https://buymeacoff.ee/sozonome","https://www.nihbuatjajan.com/sozonome","https://trakteer.id/sozonome/tip?utm_source=github_sozonome"]},"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":"AGENTS.md","dco":null,"cla":null}},"created_at":"2021-02-16T09:58:28.000Z","updated_at":"2026-01-20T12:54:35.000Z","dependencies_parsed_at":"2023-10-10T19:37:03.832Z","dependency_job_id":"ab6ac27b-22a9-4749-8750-dd18a2c2f8d3","html_url":"https://github.com/agustinusnathaniel/spoker","commit_stats":null,"previous_names":["agustinusnathaniel/spoker"],"tags_count":97,"template":false,"template_full_name":"agustinusnathaniel/nextarter-chakra","purl":"pkg:github/agustinusnathaniel/spoker","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/agustinusnathaniel%2Fspoker","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/agustinusnathaniel%2Fspoker/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/agustinusnathaniel%2Fspoker/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/agustinusnathaniel%2Fspoker/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/agustinusnathaniel","download_url":"https://codeload.github.com/agustinusnathaniel/spoker/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/agustinusnathaniel%2Fspoker/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29659761,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-20T16:33:43.953Z","status":"ssl_error","status_checked_at":"2026-02-20T16:33:43.598Z","response_time":59,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["built-with-react","chakra-ui","firebase","nextjs","planning-poker","scrum","scrum-agile","scrum-poker","scrumpoker","typescript","webapp"],"created_at":"2026-02-20T18:09:08.479Z","updated_at":"2026-04-01T23:31:01.716Z","avatar_url":"https://github.com/agustinusnathaniel.png","language":"TypeScript","funding_links":["https://github.com/sponsors/sozonome","https://ko-fi.com/sozonome","https://liberapay.com/sozonome","https://buymeacoff.ee/sozonome","https://www.nihbuatjajan.com/sozonome","https://trakteer.id/sozonome/tip?utm_source=github_sozonome"],"categories":[],"sub_categories":[],"readme":"# spoker\n\nA real-time planning poker (scrum poker) application for agile teams to estimate story points collaboratively.\n\n\u003cimg src=\"public/chip.svg\" width=\"120\" /\u003e\n\n[![Quality Gate Status](https://sonarcloud.io/api/project_badges/measure?project=sozonome_spoker\u0026metric=alert_status)](https://sonarcloud.io/dashboard?id=sozonome_spoker) [![Bugs](https://sonarcloud.io/api/project_badges/measure?project=sozonome_spoker\u0026metric=bugs)](https://sonarcloud.io/dashboard?id=sozonome_spoker) [![Code Smells](https://sonarcloud.io/api/project_badges/measure?project=sozonome_spoker\u0026metric=code_smells)](https://sonarcloud.io/dashboard?id=sozonome_spoker) [![Duplicated Lines (%)](https://sonarcloud.io/api/project_badges/measure?project=sozonome_spoker\u0026metric=duplicated_lines_density)](https://sonarcloud.io/dashboard?id=sozonome_spoker) [![Technical Debt](https://sonarcloud.io/api/project_badges/measure?project=sozonome_spoker\u0026metric=sqale_index)](https://sonarcloud.io/dashboard?id=sozonome_spoker) [![Maintainability Rating](https://sonarcloud.io/api/project_badges/measure?project=sozonome_spoker\u0026metric=sqale_rating)](https://sonarcloud.io/dashboard?id=sozonome_spoker) [![Reliability Rating](https://sonarcloud.io/api/project_badges/measure?project=sozonome_spoker\u0026metric=reliability_rating)](https://sonarcloud.io/dashboard?id=sozonome_spoker) [![Security Rating](https://sonarcloud.io/api/project_badges/measure?project=sozonome_spoker\u0026metric=security_rating)](https://sonarcloud.io/dashboard?id=sozonome_spoker) [![Vulnerabilities](https://sonarcloud.io/api/project_badges/measure?project=sozonome_spoker\u0026metric=vulnerabilities)](https://sonarcloud.io/dashboard?id=sozonome_spoker)\n\n[![Commitizen friendly](https://img.shields.io/badge/commitizen-friendly-brightgreen.svg)](http://commitizen.github.io/cz-cli/)\n\n[![Ask DeepWiki](https://deepwiki.com/badge.svg)](https://deepwiki.com/agustinusnathaniel/spoker)\n\n## Overview\n\nSpoker enables distributed teams to conduct planning poker sessions in real-time. Team members join rooms, vote on story points, and see results synchronized across all participants. The application uses Firebase Realtime Database for instant updates and supports multiple user roles with different permissions.\n\n### What It Does\n\n- **Real-time collaboration**: Multiple users can join rooms and vote simultaneously with live updates\n- **Role-based access**: Three roles (owner, participant, observant) with different capabilities\n- **Task management**: Queue-based workflow with completed task history\n- **Vote hiding**: Configurable emoji-based labels to hide votes until all participants vote\n- **Room privacy**: Support for public and password-protected private rooms\n- **Email verification**: Required authentication with email verification\n\n### What It Does Not Do\n\n- Persistent user profiles or voting history across sessions\n- Integration with project management tools (Jira, Trello, etc.)\n- Analytics or reporting beyond basic vote averages\n- Mobile native applications (web-only)\n- Offline mode or local-first synchronization\n\n## Architecture\n\n### High-Level System Architecture\n\n```mermaid\ngraph TB\n    subgraph \"Client (Next.js)\"\n        UI[React Components]\n        Store[Zustand Stores]\n        Services[Firebase Services]\n    end\n    \n    subgraph \"Firebase Services\"\n        Auth[Firebase Auth]\n        DB[(Realtime Database)]\n        AppCheck[App Check]\n    end\n    \n    subgraph \"External\"\n        Sentry[Error Tracking]\n        Analytics[Umami Analytics]\n    end\n    \n    UI --\u003e Store\n    UI --\u003e Services\n    Services --\u003e Auth\n    Services --\u003e DB\n    Services --\u003e AppCheck\n    UI --\u003e Sentry\n    UI --\u003e Analytics\n    \n    style DB fill:#4CAF50\n    style Auth fill:#FFA726\n    style Store fill:#7B68EE\n```\n\n### Core Data Flow\n\n```mermaid\nsequenceDiagram\n    participant User\n    participant UI\n    participant Store\n    participant Service\n    participant Firebase\n    \n    User-\u003e\u003eUI: Join Room / Vote\n    UI-\u003e\u003eService: Call Firebase Service\n    Service-\u003e\u003eFirebase: Write to Realtime DB\n    Firebase--\u003e\u003eService: Update Confirmed\n    Firebase--\u003e\u003eStore: Real-time Listener Update\n    Store--\u003e\u003eUI: State Change\n    UI--\u003e\u003eUser: UI Update\n```\n\n### Repository Structure\n\n```\nspoker/\n├── src/\n│   ├── lib/                    # Core application logic\n│   │   ├── components/         # Reusable UI components\n│   │   ├── constants/          # Configuration constants\n│   │   │   ├── routes/         # Route definitions (public/private/restricted)\n│   │   │   └── hide-label.ts   # Vote hiding emoji options\n│   │   ├── hooks/              # Custom React hooks\n│   │   ├── layout/             # Layout components (header, footer, auth)\n│   │   ├── models/             # Form validation schemas (Zod)\n│   │   ├── pages/              # Page-level components\n│   │   │   ├── hall/           # Room creation/joining interface\n│   │   │   ├── room/           # Main voting interface\n│   │   │   └── home/           # Landing page\n│   │   ├── services/           # Firebase service layer\n│   │   │   └── firebase/\n│   │   │       ├── auth/       # Authentication operations\n│   │   │       ├── room/       # Room CRUD and updates\n│   │   │       └── rules.ts    # Security rules generator\n│   │   ├── stores/             # Zustand state management\n│   │   ├── styles/             # Theme configuration (Chakra UI)\n│   │   ├── types/              # TypeScript type definitions\n│   │   └── utils/              # Utility functions\n│   └── pages/                  # Next.js pages (routing)\n├── public/                     # Static assets\n├── tools/                      # Build-time scripts\n└── config files               # Next.js, TypeScript, Biome, etc.\n```\n\n## Tech Stack\n\n### Core Dependencies\n\n| Package | Purpose | Version |\n|---------|---------|---------|\n| `next` | React framework with SSR/SSG | ^16.1.1 |\n| `react` | UI library | ^19.2.3 |\n| `firebase` | Backend (Auth + Realtime Database) | ^12.7.0 |\n| `@chakra-ui/react` | Component library | ^2.10.9 |\n| `zustand` | State management | ^5.0.9 |\n| `zod` | Runtime type validation | ^4.2.1 |\n| `react-hook-form` | Form handling | ^7.69.0 |\n\n### Development Tools\n\n- **Biome**: Linting and formatting (replaces ESLint/Prettier)\n- **TypeScript**: Type safety\n- **Commitlint**: Conventional commits\n- **Husky**: Git hooks\n- **Knip**: Unused code detection\n- **Sentry**: Error tracking and monitoring\n\n## Getting Started\n\n### Prerequisites\n\n- Node.js v24.11.x (specified in `engines`)\n- pnpm v10.24.0 (specified in `packageManager`)\n- Firebase project with Realtime Database enabled\n- ReCAPTCHA v3 site key (optional, for App Check)\n\n### Environment Variables\n\nCreate a `.env.local` file with the following variables:\n\n```bash\n# Firebase Configuration\nNEXT_PUBLIC_FIREBASE_API_KEY=\nNEXT_PUBLIC_FIREBASE_AUTH_DOMAIN=\nNEXT_PUBLIC_FIREBASE_DATABASE_URL=\nNEXT_PUBLIC_FIREBASE_PROJECT_ID=\nNEXT_PUBLIC_FIREBASE_STORAGE_BUCKET=\nNEXT_PUBLIC_FIREBASE_MESSAGING_SENDER_ID=\nNEXT_PUBLIC_FIREBASE_APP_ID=\nNEXT_PUBLIC_FIREBASE_MEASUREMENT_ID=\n\n# Optional: ReCAPTCHA for App Check\nNEXT_PUBLIC_RECAPTCHA_SITE_KEY=\n\n# Optional: Sentry\nSENTRY_DSN=\nNEXT_PUBLIC_SENTRY_DSN=\nAPP_ENV=\n```\n\n### Installation\n\n```bash\n# Install dependencies\npnpm install\n\n# Run development server\npnpm dev\n```\n\nOpen [http://localhost:3000](http://localhost:3000) to view the application.\n\n### Building\n\n```bash\n# Type check\npnpm type:check\n\n# Lint and format\npnpm biome:check\npnpm biome:fix\n\n# Build for production\npnpm build\n\n# Start production server\npnpm start\n```\n\n### Firebase Setup\n\n1. Create a Firebase project in the [Firebase Console](https://console.firebase.google.com/)\n2. Enable Realtime Database (not Firestore)\n3. Configure Authentication (Email/Password and Google providers)\n4. Deploy security rules using `pnpm generate-rules` (generates rules from `src/lib/services/firebase/rules.ts`)\n5. Optionally enable App Check with ReCAPTCHA v3\n\n## Development Workflows\n\n### Code Quality\n\n```bash\n# Run all checks (linting, type checking)\npnpm check:turbo\n\n# Check for unused code\npnpm check:unused\n```\n\n### Commits\n\nThis project uses [Conventional Commits](https://www.conventionalcommits.org/). Use `pnpm commit` (via Commitizen) or follow the format:\n\n```\ntype(scope): subject\n\nbody (optional)\n\nfooter (optional)\n```\n\n### Release Process\n\n```bash\n# Create release (updates version, CHANGELOG.md)\npnpm release\n\n# Push release tags\npnpm push-release\n```\n\n## Key Concepts\n\n### User Roles\n\n- **Owner**: Can create rooms, finish votes, configure room settings, manage tasks\n- **Participant**: Can vote on tasks, view results when revealed\n- **Observant**: Can view votes and results but cannot vote\n\n### Room Lifecycle\n\n1. **Creation**: Owner creates room with name, privacy, and optional password\n2. **Joining**: Users join with a role (owner/participant/observant)\n3. **Voting**: Participants vote on current task; votes hidden until all vote\n4. **Reveal**: When all participants vote, results are shown to all\n5. **Completion**: Owner selects final estimate and moves to next task in queue\n\n### Vote Hiding\n\nVotes can be hidden using emoji labels (monkey, chicken, cow, fish, money, cloud, shrimp, think) until all participants have voted. This prevents bias in estimation.\n\n### Task Queue\n\n- **Current Task**: Active task being estimated (`room.task`)\n- **Queue**: Upcoming tasks (`room.queue[]`)\n- **Completed**: Finished tasks with estimates (`room.completed[]`)\n\n## Common Development Tasks\n\n### Adding a New Page\n\n1. Create component in `src/lib/pages/[page-name]/index.tsx`\n2. Create route in `src/pages/[page-name].ts` (or `[page-name]/[id].ts` for dynamic routes)\n3. Add route to appropriate constant in `src/lib/constants/routes/`\n\n### Adding a New Firebase Service\n\n1. Create service function in `src/lib/services/firebase/[domain]/[operation]/index.ts`\n2. Export from service module\n3. Update Firebase rules in `src/lib/services/firebase/rules.ts` if needed\n4. Run `pnpm generate-rules` to regenerate rules JSON\n\n### Modifying State Management\n\n- Room state: `src/lib/stores/room.ts`\n- Auth state: `src/lib/stores/auth.ts`\n- Use `useShallow` from Zustand to prevent unnecessary re-renders\n\n## Testing\n\nCurrently, the project does not include automated tests. Manual testing should cover:\n\n- Room creation and joining\n- Real-time vote synchronization\n- Role-based permissions\n- Task queue management\n- Email verification flow\n- Private room password protection\n\n## Deployment\n\nThe project is configured for Vercel deployment (`vercel.json`). Ensure environment variables are set in the deployment platform.\n\n## Contributors ✨\n\nThanks goes to these wonderful people ([emoji key](https://allcontributors.org/docs/en/emoji-key)):\n\n\u003c!-- ALL-CONTRIBUTORS-LIST:START - Do not remove or modify this section --\u003e\n\u003c!-- prettier-ignore-start --\u003e\n\u003c!-- markdownlint-disable --\u003e\n\u003ctable\u003e\n  \u003ctbody\u003e\n    \u003ctr\u003e\n      \u003ctd align=\"center\" valign=\"top\" width=\"14.28%\"\u003e\u003ca href=\"https://agustinusnathaniel.com/\"\u003e\u003cimg src=\"https://avatars.githubusercontent.com/u/17046154?v=4?s=72\" width=\"72px;\" alt=\"Agustinus Nathaniel\"/\u003e\u003cbr /\u003e\u003csub\u003e\u003cb\u003eAgustinus Nathaniel\u003c/b\u003e\u003c/sub\u003e\u003c/a\u003e\u003cbr /\u003e\u003ca href=\"https://github.com/agustinusnathaniel/spoker/commits?author=agustinusnathaniel\" title=\"Code\"\u003e💻\u003c/a\u003e \u003ca href=\"https://github.com/agustinusnathaniel/spoker/issues?q=author%3Aagustinusnathaniel\" title=\"Bug reports\"\u003e🐛\u003c/a\u003e \u003ca href=\"#design-agustinusnathaniel\" title=\"Design\"\u003e🎨\u003c/a\u003e \u003ca href=\"#ideas-agustinusnathaniel\" title=\"Ideas, Planning, \u0026 Feedback\"\u003e🤔\u003c/a\u003e \u003ca href=\"#infra-agustinusnathaniel\" title=\"Infrastructure (Hosting, Build-Tools, etc)\"\u003e🚇\u003c/a\u003e \u003ca href=\"#maintenance-agustinusnathaniel\" title=\"Maintenance\"\u003e🚧\u003c/a\u003e\u003c/td\u003e\n    \u003c/tr\u003e\n  \u003c/tbody\u003e\n\u003c/table\u003e\n\n\u003c!-- markdownlint-restore --\u003e\n\u003c!-- prettier-ignore-end --\u003e\n\n\u003c!-- ALL-CONTRIBUTORS-LIST:END --\u003e\n\nThis project follows the [all-contributors](https://github.com/all-contributors/all-contributors) specification. Contributions of any kind welcome!\n\n## Related Documentation\n\n- [CONTRIBUTING.md](./CONTRIBUTING.md) - Contribution guidelines\n- [SPEC.md](./SPEC.md) - System specification and invariants\n- [AGENTS.md](./AGENTS.md) - AI agent guidance and mental model\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fagustinusnathaniel%2Fspoker","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fagustinusnathaniel%2Fspoker","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fagustinusnathaniel%2Fspoker/lists"}