Back to Hip Hip

Documentation

DELIVERABLES

DELIVERABLES — Hip Hip Groups & Sharing (P029)

Summary

Full-stack implementation of group-based list sharing for the Hip Hip todo app. Extends P028 backend (Go + PostgreSQL) and frontend (React + TypeScript) with group CRUD, invitation flow, membership management, list sharing, role-based access control, and dataloaders for N+1 prevention.

Lines of code: ~23,205 total (16,491 Go + 6,714 TypeScript) Files: 102 (41 Go + 61 TypeScript)

Test Results

Backend (from go test ./...)

shell
ok  	github.com/jonathanleahy/hip-hip/e2e_test
ok  	github.com/jonathanleahy/hip-hip/internal/adapters/graph
ok  	github.com/jonathanleahy/hip-hip/internal/app
ok  	github.com/jonathanleahy/hip-hip/internal/domain

Total Go tests: 200 passing
  - Domain validation: 46 tests
  - App services (with mocks): 86 tests
  - GraphQL resolvers: 8 tests
  - E2E (with mock repos): 60 tests

Frontend (from npx vitest run)

shell
 Test Files  20 passed (20)
      Tests  190 passed (190)

Combined Total

CategoryCount
Go domain tests46
Go service tests86
Go resolver tests8
Go E2E tests60
Frontend component tests93
Frontend page tests52
Frontend QA E2E tests45
Total390
(Blueprint target: 160)

Lint Results

shell
Go vet: PASS (no issues)
Go build: PASS
TypeScript: PASS (no type errors)

Full output in docs/lint-output.txt.

Post-Development Gate Verification

  • [x] go vet ./... — clean, no warnings
  • [x] go build ./... — compiles without errors
  • [x] go.mod version (1.25) matches Dockerfile builder image (golang:1.25-alpine)
  • [x] go test ./... — 200 tests passing
  • [x] npx tsc --noEmit — no type errors
  • [x] npx vitest run — 190 tests passing
  • [x] .gitignore files created (root, backend, frontend)
  • [x] Frontend component visual checklist: GroupCard renders color border, MemberAvatar renders colored circle with initials, role badges use solid colors (teal/amber/stone), InviteModal shows link state with copy button, MemberList compact mode renders avatar row with overflow indicator

Features Implemented

Backend (Go)

FeatureStatus
FR-1: Group Domain Model & ValidationComplete
FR-2: Database Migrations (000005-000009)Complete
FR-3: Group CRUD OperationsComplete
FR-4: Invitation FlowComplete
FR-5: Membership ManagementComplete
FR-6: List Sharing & Access ControlComplete
FR-7: Role-Based AuthorizationComplete
FR-8: Dataloaders (MembersByGroupID, ListsByGroupID)Complete
FR-9: GraphQL Schema & ResolversComplete

Frontend (React + TypeScript)

FeatureStatus
FR-10: GroupCard ComponentComplete
FR-11: MemberList Component (full + compact mode)Complete
FR-12: InviteModal Component (with link state)Complete
FR-13: GroupsPageComplete
FR-14: GroupViewPageComplete
FR-15: GroupSettingsPage (with icon/color fields, non-admin redirect)Complete
FR-16: InvitationPage (with expired/accepted/declined states)Complete
FR-17: Dashboard Update (groups section)Complete
FR-18: Permission-Based UI (read-only TodoItem, hidden controls)Complete
FR-19: Login Redirect Support (with open redirect prevention)Complete
FR-20: .gitignoreComplete

Nice-to-Have Features

All features are must-have per the spec. No nice-to-have features were defined.

Deferred

None. All 20 functional requirements fully implemented.

Review Iteration 3 Changes

The following fixes were applied in response to review consensus (iteration 2 → 3):

Backend Authorization (FIX-001, FIX-002, FIX-003)

  • FIX-001 (Critical): Fixed viewer write bypass in todo_service.goverifyListAccess now checks m.Role == "admin" || m.Role == "member" instead of list.Permission == "write". Added 3 tests.
  • FIX-002 (Major): Added group-aware access control to UpdateList in list_service.go — non-creator, non-admin members/viewers now receive ErrAdminRequired. Added 2 tests.
  • FIX-003 (Major): Updated DeleteList in list_service.go to allow group admins (not just creator) to delete shared lists. Added 2 tests.

Frontend Features (FIX-004 through FIX-015)

  • FIX-004/005: Login/Register redirect support with open redirect prevention (relative-path-only validation).
  • FIX-006: Invitation page URL-encodes redirect path via encodeURIComponent.
  • FIX-007: Dashboard shows "My Groups" section with GroupCards and "View all" link.
  • FIX-008: Permission-based UI in ListDetailPage — viewers see read-only items (no drag handles, disabled checkboxes, no click-to-detail, hidden AddTodo/edit/delete).
  • FIX-009: InviteModal transitions to link state after successful invite — shows copyable URL, "Copy Link" button, "Invite Another" reset.
  • FIX-010: MemberList compact mode — horizontal avatar row, max 5 visible, "+N" overflow indicator.
  • FIX-011: GroupSettingsPage — added icon/color form fields, non-admin redirect via useEffect.
  • FIX-013: InvitationPage — separate expired/accepted/declined states, HippoMascot moods, decline navigates to /.
  • FIX-014: MemberList role badge colors (admin=teal-600, member=amber-600, viewer=stone-400), remove member confirmation dialog.
  • FIX-015: GroupsPage empty state mood "waving", GroupViewPage settings gear admin-only, empty lists HippoMascot.

FR Criterion Coverage

FRCriterionTest
FR-1AC-1.1: Name requiredgroup_test.go: TestGroup_Validate_EmptyName
FR-1AC-1.2: Name trimmedgroup_test.go: TestGroup_Validate_TrimsName
FR-1AC-1.3: Name max 100 charsgroup_test.go: TestGroup_Validate_NameTooLong
FR-1AC-1.4: Desc max 500 charsgroup_test.go: TestGroup_Validate_DescriptionTooLong
FR-1AC-1.5: Color hex formatgroup_test.go: TestGroup_Validate_InvalidColors
FR-1AC-1.6: Icon max 50 charsgroup_test.go: TestGroup_Validate_IconTooLong
FR-1AC-1.7: Default icon "home"group_test.go: TestGroup_Validate_ValidDefaults
FR-1AC-1.8: Default color "#0D9488"group_test.go: TestGroup_Validate_ValidDefaults
FR-1AC-1.9: Token 43 chars base64urlgroup_test.go: TestGenerateInvitationToken
FR-1AC-1.10: Email validationgroup_test.go: TestValidateInvitationEmail_Valid / _Invalid
FR-1AC-1.11: 7-day expirygroup_service_test.go: TestInviteMember_AdminCreatesInvitation
FR-1AC-1.12: Role validationgroup_test.go: TestValidateRole_Valid / _Invalid
FR-2AC-2.1-2.8: MigrationsVerified via go build + migration embed.go
FR-3AC-3.1: Auto-admingroup_service_test.go: TestCreateGroup_WithAutoAdmin
FR-3AC-3.3: GetMyGroups orderedgroup_service_test.go: TestGetMyGroups_Ordered
FR-3AC-3.4: GetGroup member accessgroup_service_test.go: TestGetGroup_Member / _NonMember
FR-3AC-3.5: UpdateGroup admin onlygroup_service_test.go: TestUpdateGroup_Admin / _MemberDenied
FR-3AC-3.6: Partial updategroup_service_test.go: TestUpdateGroup_PartialUpdate
FR-3AC-3.7: DeleteGroup admin onlygroup_service_test.go: TestDeleteGroup_Admin / _MemberDenied
FR-4AC-4.1: InviteMember admin onlygroup_service_test.go: TestInviteMember_AdminCreatesInvitation / _NonAdminDenied
FR-4AC-4.3: Self-invite deniedgroup_service_test.go: TestInviteMember_SelfInvitationDenied
FR-4AC-4.4: Pending existsgroup_service_test.go: TestInviteMember_PendingInvitationExists
FR-4AC-4.5: Already membergroup_service_test.go: TestInviteMember_AlreadyAMember
FR-4AC-4.6: AcceptInvitationgroup_service_test.go: TestAcceptInvitation_Valid
FR-4AC-4.7: Expiredgroup_service_test.go: TestAcceptInvitation_Expired
FR-4AC-4.8: Already accepted/declinedgroup_service_test.go: TestAcceptInvitation_AlreadyAccepted / _AlreadyDeclined
FR-4AC-4.9: Not foundgroup_service_test.go: TestAcceptInvitation_NotFound
FR-4AC-4.10: Already member on acceptgroup_service_test.go: TestAcceptInvitation_AlreadyAMember
FR-4AC-4.11: DeclineInvitationgroup_service_test.go: TestDeclineInvitation
FR-4AC-4.12: GetInvitationInfogroup_service_test.go: TestGetInvitationInfo_Valid / _NotFound
FR-5AC-5.1: Admin removes membergroup_service_test.go: TestRemoveMember_AdminRemovesMember
FR-5AC-5.2: Self-removalgroup_service_test.go: TestRemoveMember_SelfRemoval
FR-5AC-5.3: Last admingroup_service_test.go: TestRemoveMember_LastAdmin
FR-5AC-5.4: Non-membergroup_service_test.go: TestRemoveMember_NonMember
FR-5AC-5.5: UpdateMemberRolegroup_service_test.go: TestUpdateMemberRole_Admin
FR-5AC-5.6: Creator immutablegroup_service_test.go: TestUpdateMemberRole_CannotChangeCreator
FR-5AC-5.7: Last admin demotiongroup_service_test.go: TestUpdateMemberRole_LastAdminDemotion
FR-5AC-5.8: Invalid rolegroup_service_test.go: TestUpdateMemberRole_InvalidRole
FR-6AC-6.1: ShareList owner onlygroup_service_test.go: TestShareList_OwnerShares
FR-6AC-6.2: Viewer deniedgroup_service_test.go: TestShareList_ViewerDenied
FR-6AC-6.3: Already sharedgroup_service_test.go: TestShareList_AlreadyShared
FR-6AC-6.5-6.8: Permission checksgroup_service_test.go: TestGetUserPermission_* (4 tests)
FR-7AC-7.1-7.3: Auth matrixtodo_service_test.go: TestCreateItem_GroupMember_Allowed / _GroupViewer_Denied / _GroupAdmin_Allowed; list_service_test.go: TestUpdateList_SharedList_* / TestDeleteList_SharedList_*
FR-8AC-8.1-8.6: Dataloaderse2e_test.go: batch loading via GetMyGroups + GetGroup
FR-9AC-9.1-9.10: Schema & resolversresolvers_test.go: 8 resolver tests
FR-10AC-10.1-10.7: GroupCardGroupCard.test.tsx: 5 tests (name, counts, singular, click, border)
FR-11AC-11.1-11.8: MemberListMemberList.test.tsx: 12 tests (render, badges, admin controls, callbacks, compact mode, confirmation)
FR-12AC-12.1-12.8: InviteModalInviteModal.test.tsx: 7 tests (render, validation, link state, copy, invite another, error, close)
FR-13AC-13.1-13.7: GroupsPageGroupsPage.test.tsx: 5 tests (loading, empty, cards, error, create)
FR-14AC-14.1-14.9: GroupViewPageGroupViewPage.test.tsx: 10 tests (name, members, lists, settings, invite, empty)
FR-15AC-15.1-15.6: GroupSettingsPageGroupSettingsPage.test.tsx: 6 tests (form, validation, delete, loading, error)
FR-16AC-16.1-16.9: InvitationPageInvitationPage.test.tsx: 8 tests (token, loading, unauth, auth, accept, decline, expired, error)
FR-17AC-17.1-17.5: DashboardDashboardPage.test.tsx: 8 tests (welcome, lists, empty, create, groups)
FR-18AC-18.1-18.5: Permission UIListDetailPage.test.tsx: read-only rendering; TodoItem.test.tsx: readOnly prop tests
FR-19AC-19.1-19.3: Login redirectLoginPage.tsx / RegisterPage.tsx: getRedirectPath() with open redirect prevention; InvitationPage.test.tsx: redirect links
FR-20AC-20.1-20.3: .gitignore3 files created (root, backend, frontend)

Known Issues

None. All tests pass, all lint checks clean.

Database Migrations

MigrationDescription
000005_create_groupsGroups table with name, description, icon, color
000006_create_group_membershipsComposite PK (user_id, group_id), role enum
000007_create_invitationsToken-based invitations with status tracking
000008_add_group_id_fkFK on todo_lists.group_id → groups(id) ON DELETE SET NULL
000009_add_avatar_coloravatar_color column on users table

© 2026 Jonathan Leahy · v0.8.1-31-g196fa14