Overview
Scrumlr.io is an open-source real-time retrospective tool for agile teams. Teams can collaboratively create and manage retro boards with cards, reactions, and voting, all synchronized live via WebSockets.
During my time at inovex I contributed across the full stack: React frontend, Go backend, Redux state management, CI/CD, and documentation.
Contributions
Full Emoji Reaction System
The largest feature work was the card reaction system. The original implementation supported only 7 hardcoded emojis, I replaced it with a full emoji picker.
This required changes on both sides of the stack. On the backend, ReactionType was converted from a fixed enum to a free string field, with validation capped at 50 characters and legacy mappings for backward compatibility. On the frontend, I built a new EmojiPickerReactionBar component with portal rendering, viewport-aware positioning (so the picker never overflows the screen), dark/light/auto theme integration, and recent emoji tracking via localStorage.
Drag-and-Drop Improvements
Two concrete issues in the drag-and-drop logic for cards. The collision detection thresholds were miscalibrated: cards were too easy to accidentally group and too hard to move. Adjusting COMBINE_THRESHOLD and MOVE_THRESHOLD made the behavior significantly more intuitive.
A mutation bug came on top of that: items.reverse() mutated the array in place, causing inconsistent state across clients. The fix was [...items].reverse(), a small change with real weight in a collaborative environment.
Anonymous User Board Creation Controls
A full-stack feature giving admins control over whether unauthenticated users can create new boards, via a new environment variable (SCRUMLR_ALLOW_ANONYMOUS_BOARD_CREATION).
On the backend, a new context middleware and an extended server info API were added. On the frontend, I extended the Redux state and added conditional UI restrictions with tooltip explanations for anonymous users. I also built a second middleware for custom template creation under the same configuration logic, and updated Docker Compose and Kubernetes deployment configs accordingly.
Column UX
Several smaller improvements to column interactions that added up to a noticeably better editing experience.
Inline description editing: double-clicking a column description opens it for inline editing directly on the board. This involved adding a readOnly prop to the TextArea component and testing the new interaction pattern.
Consistent column height: when one column has a description and others don't, the layout heights would diverge. A new Redux selector (anyColumnHasDescription) ensures all columns maintain uniform height whenever at least one has a description.
Enter key submission: column title and description fields now submit on Enter; Shift+Enter inserts a line break in the description field.
Backend: Board Deletion Event
When a board was deleted, connected clients weren't receiving a BOARD_DELETED WebSocket event, just a generic error. I fixed the event publishing step in the backend and added tests to verify that all board members are properly redirected to the home screen.
CI/DevEx: Go Formatting
Inconsistent Go formatting was a recurring friction point in code review. I integrated gofmt into the CI pipeline (make format-check before the lint step) and provided a Git pre-commit hook via a setup script so formatting issues surface locally before pushing, not in review. Developer docs were updated with IDE configuration examples for VS Code and GoLand.
