This file provides guidance to Claude Code (claude.ai/code) when working with this repository.
Always create PRs targeting the develop branch by default.
Every commit message must be prefixed with an issue number following this pattern:
GO-{issueNumber} Short description
Optional longer description.
Example:
GO-6443 Add chat name to push notifications
Include chatName field in push notification payload so users can see
which chat a message was sent from.
-
Use fixture pattern for consistent test setup:
type fixture struct { *service objectStore *objectstore.StoreFixture // other dependencies } func newFixture(t *testing.T) *fixture { objectStore := objectstore.NewStoreFixture(t) // setup mocks and dependencies return &fixture{ service: New().(*service), objectStore: objectStore, } }
-
Use
wantstructure in tests for clarity - it makes expected values explicit:t.Run("test case name", func(t *testing.T) { // given fx := newFixture(t) req := SomeRequest{...} want := &ExpectedType{ Field1: "expected value", Field2: 123, } // when got, err := fx.methodUnderTest(req) // then require.NoError(t, err) assert.Equal(t, want, got) })
-
Use
AddObjectsmethod ofStoreFixturefor setting up test data:fx.objectStore.AddObjects(t, spaceId, []objectstore.TestObject{ { bundle.RelationKeyId: domain.String("objectId"), bundle.RelationKeyName: domain.String("Object Name"), bundle.RelationKeyResolvedLayout: domain.Int64(int64(model.ObjectType_basic)), }, })
-
Tech space ID - use
objectstore.TestTechSpaceIdconstant for space view setup:fx.objectStore.AddObjects(t, objectstore.TestTechSpaceId, []objectstore.TestObject{ { bundle.RelationKeyId: domain.String("spaceView1"), bundle.RelationKeyResolvedLayout: domain.Int64(int64(model.ObjectType_spaceView)), bundle.RelationKeyTargetSpaceId: domain.String(spaceId), bundle.RelationKeyName: domain.String(spaceName), }, })
-
Test naming: Use descriptive names that explain what's being tested:
"basic message with space and sender names""message with attachments""message with emoji marks""empty chat name"
Use testify assertions:
assert.Equal(t, expected, actual)
require.NoError(t, err)
require.Len(t, slice, expectedLen)-
Mock generation: Use mockery with
.mockery.yamlconfiguration# Regenerate mocks make test-deps -
Mock expectations: Use
EXPECT()pattern with testify/mock:fx.crossSpaceSubService.EXPECT().Subscribe(mock.Anything, mock.Anything).Return(&subscription.SubscribeResponse{ Records: []*domain.Details{}, }, nil).Maybe()
-
Flexible matching: Use
mock.Anythingfor parameters you don't need to match exactly
Always wrap errors with context using fmt.Errorf("operation description: %w", err). Never return bare err from functions — every error should carry information about which operation failed.
// Bad
if err != nil {
return err
}
// Good
if err != nil {
return fmt.Errorf("query objects by relation: %w", err)
}- Use short, lowercase descriptions that identify the failed operation
- Avoid redundant prefixes like
"failed to"or"error in"— just name the operation - Use
%wverb to preserve the error chain forerrors.Is/errors.As - Do not change bare
returntoreturn errwithout wrapping — change it toreturn fmt.Errorf("context: %w", err)