Skip to content

Commit 9e096da

Browse files
feat(audit): add Kafka reader for UserOp events (#103)
* feat(audit): add Kafka reader for UserOp events - Add UserOpEventWrapper struct with key, event, timestamp - Add UserOpEventReader trait with read_event() and commit() - Add KafkaUserOpAuditLogReader implementation - Add integration test verifying real Kafka publish/read flow
1 parent 0e40c2c commit 9e096da

26 files changed

+1844
-5
lines changed
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
---
2+
description: Describes how to handle a request to fix a bugsnag issue
3+
globs:
4+
alwaysApply: false
5+
---
6+
# Bugsnag Ticket Workflow
7+
8+
When a user provides a Bugsnag error URL or asks to fix a Bugsnag issue, follow this systematic approach:
9+
10+
## 1. **Root Cause Analysis**
11+
12+
### Error Investigation
13+
- Use `mcp_bugsnag-mcp_list-error-events` to get recent events for the error
14+
- Use `mcp_bugsnag-mcp_get-stacktrace` with `include_code: true` and `show_all_frames: true` to get the complete stacktrace
15+
- Analyze the stacktrace to identify:
16+
- The exact line and file where the error occurs
17+
- The call stack that leads to the error
18+
- The error message and context
19+
20+
### Codebase Investigation
21+
- Read the relevant files identified in the stacktrace
22+
- Search for related code patterns or similar implementations
23+
- Identify the data flow that leads to the problematic state
24+
- Look for edge cases or missing null/undefined checks
25+
26+
## 2. **Suggest Fixes (No Code Changes)**
27+
28+
### Analysis Summary
29+
- Provide a clear explanation of what's causing the error
30+
- Identify the specific conditions that trigger the issue
31+
- Explain the impact and severity of the error
32+
- If you can't figure out what is going on, just say so and ask the user for more context
33+
34+
### Proposed Solutions
35+
- Present 1-3 potential fix approaches with pros/cons
36+
- Suggest relevant tests to prevent regression
37+
- Try to be tactical with your suggestions, avoid large refactors when possible
38+
39+
### Implementation Recommendations
40+
- Specify which files need to be modified
41+
- Outline the exact changes needed (but don't make them yet)
42+
- Mention any dependencies or related changes required
43+
- Highlight potential breaking changes or compatibility concerns
44+
45+
## 3. **User Confirmation & Implementation**
46+
47+
### Get Approval
48+
- Wait for user confirmation on the proposed approach
49+
- Allow for discussion and refinement of the solution
50+
- Clarify any ambiguous requirements or edge cases
51+
52+
### Implementation & PR Creation
53+
Once the user confirms the approach:
54+
- Follow the below process:
55+
- Making code changes
56+
- Adding tests if needed
57+
58+
---
59+
60+
**Example Workflow:**
61+
62+
- User: "Fix this Bugsnag issue: https://app.bugsnag.com/<ticket>"
63+
- Assistant:
64+
1. Fetches error events and stacktrace from Bugsnag
65+
2. Analyzes the code to identify root cause
66+
3. Proposes specific fix approach with explanation
67+
4. Waits for user confirmation
68+
5. Making code changes and tests if needed
69+
70+
---
71+
72+
**Note:** This workflow ensures thorough analysis before making changes, reducing the risk of incomplete fixes or introducing new issues while maintaining the systematic approach for PR creation.

.cursor/rules/coding-workflow.mdc

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
---
2+
description: Coding workflow cursor must follow
3+
globs:
4+
alwaysApply: false
5+
---
6+
# Coding workflow preferences
7+
- Focus on the areas of code relevant to the task
8+
- Do not touch code that is unrelated to the task
9+
- Avoid making major changes to the patterns and architecture of how a feature works, after it has shown to work well, unless explicitly instructed
10+
- Always think about what other methods and areas of code might be affected by code changes
11+
- Keep code simple and readable
12+
- Write thorough tests for all functionalities you wrote
13+
14+
Follow this sequential workflow:
15+
1. Write or update existing code
16+
2. Write the incremental unit-test to cover code logic you wrote
17+
3. Test unit-test pass
18+
4. Verify it passes all the tests by running `make test` command
19+
5. Ensue your unit-test has good code coverage for the code you have written
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
---
2+
description:
3+
globs:
4+
alwaysApply: false
5+
---
6+
---
7+
description: Follow PR template format from .github/pull_request_template.md when creating pull request descriptions
8+
globs: "**/*"
9+
alwaysApply: false
10+
---
11+
12+
# GitHub Pull Request Template Format
13+
14+
When creating pull request descriptions, you **must** follow the format specified in `.github/pull_request_template.md` if it exists in the repository.
15+
16+
## Rule Requirements
17+
18+
1. **Check for Template**: Always check if `.github/pull_request_template.md` exists in the repository root before creating PR descriptions.
19+
20+
2. **Use Template Structure**: If the template exists:
21+
- Follow the exact section structure defined in the template
22+
- Include all required sections from the template
23+
- Maintain the same heading levels and formatting style
24+
- Preserve any placeholder text guidelines or instructions
25+
- Fill in the template sections with relevant information for the specific PR
26+
27+
3. **Template Sections**: Common sections that should be preserved if present in the template include:
28+
- **Summary/Description**: Brief overview of the changes
29+
- **Changes Made**: Detailed list of modifications
30+
- **Testing**: How the changes were tested
31+
- **Type of Change**: Bug fix, feature, documentation, etc.
32+
- **Checklist**: Action items or verification steps
33+
- **Breaking Changes**: Any backward compatibility concerns
34+
- **Related Issues**: Links to related issues or tickets
35+
36+
4. **Fallback Behavior**: If no template exists, create a well-structured PR description with:
37+
- Clear summary of changes
38+
- Bullet points for key modifications
39+
- Testing information if applicable
40+
- Any relevant context or notes
41+
42+
## Implementation Guidelines
43+
44+
- **Read Template First**: Use tools to read the `.github/pull_request_template.md` file content before generating PR descriptions
45+
- **Preserve Formatting**: Maintain markdown formatting, comments, and structure from the template
46+
- **Fill Appropriately**: Replace template placeholders with actual, relevant information
47+
- **Be Comprehensive**: Ensure all template sections are addressed, even if briefly
48+
- **Stay Consistent**: Use the same tone and style as indicated by the template
49+
50+
## Example Usage
51+
52+
When creating a PR:
53+
1. Check for `.github/pull_request_template.md`
54+
2. If found, read the template content
55+
3. Generate PR description following the template structure
56+
4. Fill in each section with relevant information
57+
5. Ensure all required sections are included
58+
59+
This rule ensures consistency across all pull requests in repositories that have established PR templates, while providing a sensible fallback for repositories without templates.
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
---
2+
description: Rules to follow when writing code
3+
globs: *.go
4+
---
5+
You are Staff Software Engineer expert in Golang, Protobuff, GRPC. You write clean and properly docummented code. You ensure code written works, and you always write corresponding Unit-tests.
6+
You are an expert in writing Unit-test, and specialised in updating existing unit-test to fit missing use-cases.
7+
8+
# Coding pattern preferences
9+
- Always prefer simple solutions.
10+
- Keep the codebase very clean and organized.
11+
- Avoid duplication of code whenever possible, which means checking for other areas of the codebase that might already have similar code and functionality.
12+
- Write code that takes into account the different environments: development, staging, and production.
13+
- You are careful to only make changes that are requested or you are confident are well understood and related to the change being requested.
14+
- When fixing an issue or bug, do not introduce a new pattern or technology without first exhausting all options for the existing implementation. And if you finally do this, make sure to remove the old ipmlementation afterwards so we don't have duplicate logic.
15+
- Avoid having files over 200-300 lines of code. Refactor at that point.
16+
- Mocking data is only needed for tests, never mock data for dev or prod.
17+
- Avoid writing scripts in files if possible, especially if the script is likely only to be run once.
18+
- Never add stubbing or fake data patterns to code that affects the dev or prod environments.
19+
- Never overwrite config *.yml (Yaml) files without first asking and confirming.
20+
- It is acceptable to say you do not know.
21+
- Do not write your own mocks in testing. Follow this sequence:
22+
1. Update Makefile to generate the mock needed.
23+
Following the example for internal packages
24+
`mockgen -source=internal/client/users_service.go -destination=internal/dao/mocks/mock_users_service.go -package=mockdao`
25+
and for external packages follow this:
26+
` mockgen -destination=mocks/eth_client_mock.go -mock_names EthClient=MockEthClient -package=mocks github.cbhq.net/intl/rip7755-fulfiller/internal/client EthClientmockgen`
27+
2. Update testing code to use the generated mock
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
---
2+
description: Make sure to always add clear comments within the codebase
3+
globs: *.go
4+
alwaysApply: true
5+
---
6+
# Standard: Language, Comments, and Documentation
7+
8+
This rule defines the standards for language use and commenting within the codebase, prioritizing clarity and developer experience for engineers familiar with the project.
9+
10+
**1. Language:**
11+
12+
* **All** code artifacts, including variable names, function names, comments, documentation, commit messages, and generated rules, **must** be written in **simple, clear, friendly and idiomatic English**.
13+
14+
**2. Comments:**
15+
16+
* **Target Audience:** Assume the reader is an experienced developer familiar with Go and the general project context.
17+
* **Prioritize Readability:** Code should be self-documenting whenever possible through clear naming and structure.
18+
* **Avoid Redundant Comments:** Do **not** add comments that merely restate what the code clearly does. For example:
19+
```go
20+
// Bad: Comment explains the obvious
21+
// Increment count
22+
count++
23+
24+
// Good: Comment starts with the function name
25+
// GetUserByID finds a user by their ID
26+
func GetUserByID(id string) (*User, error) { ... }
27+
```
28+
* **Focus on the "Why", Not Just the "What":** Prioritize comments that explain *why* a particular approach was taken, especially if it's non-obvious, involves trade-offs, or relates to external factors or historical context.
29+
* Explain complex logic or algorithms briefly.
30+
* Clarify the purpose of seemingly arbitrary values or constants.
31+
* Document known limitations, potential issues, or future work (`TODO`, `FIXME`).
32+
* Add comments when fixing subtle bugs to explain the reasoning.
33+
```go
34+
// Good: Explains the rationale for a non-obvious choice
35+
// Use FNV-1a hash for Redis hash tags to optimize for speed and key length,
36+
// as cryptographic security is not required for slot assignment.
37+
func hashUserIDForTag(userID string) string { ... }
38+
39+
// Good: Explains a workaround or limitation
40+
// TODO(GH-123): Refactor this when the upstream API supports batch requests.
41+
for _, item := range items { ... }
42+
```
43+
* **Placement:** Place comments on the line *before* the code they refer to, or sometimes at the end of a line for very short clarifications.
44+
45+
**3. Documentation (e.g., READMEs, Design Docs):**
46+
47+
* Maintain clarity and conciseness.
48+
* Keep documentation up-to-date with significant code changes.
49+
* Use diagrams or examples where appropriate to illustrate complex concepts.
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
---
2+
description: Avoid package prefix redundancy when naming
3+
globs: *.go
4+
alwaysApply: false
5+
---
6+
# Go Standard: Naming Conventions - Avoid Package Prefix Redundancy
7+
8+
This rule outlines the standard Go practice for naming exported identifiers to avoid redundancy with the package name.
9+
10+
**The Standard:**
11+
12+
When naming exported identifiers (types, functions, variables, constants), **avoid repeating the package name** if the context provided by the package itself makes the identifier clear.
13+
14+
**Rationale:**
15+
16+
* **Readability:** Code that imports the package becomes cleaner and less verbose. For example, `store.New()` is more idiomatic and readable than `store.NewStore()`.
17+
* **Conciseness:** Reduces unnecessary stuttering in code (e.g., `store.StoreType` vs. `store.Type`).
18+
* **Idiomatic Go:** Follows the common practice seen in the Go standard library and many popular Go projects.
19+
20+
**Examples:**
21+
22+
```go
23+
// --- Package: store ---
24+
25+
// BAD: Repeats "store"
26+
package store
27+
28+
type StoreConfig struct { ... }
29+
func NewStore(cfg StoreConfig) (*Store, error) { ... }
30+
var DefaultStoreOptions StoreOptions
31+
32+
// GOOD: Avoids repeating "store"
33+
package store
34+
35+
type Config struct { ... } // Type name is clear within package 'store'
36+
func New(cfg Config) (*Store, error) { ... } // Function name 'New' is clear
37+
var DefaultOptions Options // Variable name is clear
38+
39+
type Store struct { ... } // OK: Identifier itself IS the package name conceptually
40+
```
41+
42+
When importing and using the "good" example:
43+
44+
```go
45+
import "path/to/store"
46+
47+
// ...
48+
cfg := store.Config{ ... }
49+
activityStore, err := store.New(cfg)
50+
opts := store.DefaultOptions
51+
var s store.Store
52+
```
53+
54+
This reads much better than:
55+
56+
```go
57+
import "path/to/store"
58+
59+
// ...
60+
cfg := store.StoreConfig{ ... }
61+
activityStore, err := store.NewStore(cfg)
62+
opts := store.DefaultStoreOptions
63+
var s store.Store
64+
```
65+
66+
**Exceptions:**
67+
68+
* It is acceptable if the identifier itself essentially *is* the package name (e.g., `package http; type Client`, `package store; type Store`).
69+
* Sometimes repeating a part of the package name is necessary for clarity if the package has many distinct concepts.
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
---
2+
description: Prefer getter methods over direct field access
3+
globs: *.go
4+
alwaysApply: false
5+
---
6+
# Go Standard: Prefer Getter Methods (Especially for Protobuf)
7+
8+
This rule encourages the use of getter methods over direct field access, particularly when working with structs generated from Protobuf definitions.
9+
10+
**The Standard:**
11+
12+
**Prefer using generated getter methods (e.g., `myProto.GetMyField()`) over direct field access (e.g., `myProto.MyField`) when such getters are available.** This is especially relevant for structs generated by the Protobuf compiler (`protoc-gen-go`).
13+
14+
**Rationale:**
15+
16+
* **Encapsulation and Nil Safety:** Getters often provide a layer of abstraction. For Protobuf messages, getters automatically handle `nil` checks for pointer fields (like optional message fields or fields within a `oneof`), returning a zero value instead of causing a panic. This significantly improves robustness.
17+
* **Consistency:** Using getters consistently makes the code easier to read and maintain, aligning with common Go practices for Protobuf.
18+
* **Future-Proofing:** Relying on the getter method decouples the calling code from the exact internal representation of the field. If the underlying field changes in a backward-compatible way (e.g., how a default value is handled), code using the getter is less likely to break.
19+
* **Helper Logic:** Getters might potentially include minor logic (though less common in basic Protobuf getters beyond nil checks).
20+
21+
**Example (Protobuf):**
22+
23+
```protobuf
24+
// -- Example.proto --
25+
message UserProfile {
26+
optional string name = 1;
27+
optional int32 age = 2;
28+
}
29+
```
30+
31+
```go
32+
// -- Go code --
33+
import "path/to/gen/go/examplepb"
34+
35+
func processProfile(profile *examplepb.UserProfile) {
36+
// GOOD: Uses getter, safe even if profile or profile.Name is nil.
37+
name := profile.GetName()
38+
age := profile.GetAge() // Also handles potential nil receiver safely.
39+
40+
// BAD: Direct access risks nil pointer dereference if profile is non-nil
41+
// but profile.Name is nil (for optional fields).
42+
// nameDirect := *profile.Name // PANICS if profile.Name is nil!
43+
// ageDirect := *profile.Age // PANICS if profile.Age is nil!
44+
45+
fmt.Printf("Name: %s, Age: %d\n", name, age)
46+
}
47+
```
48+
49+
**Exceptions:**
50+
51+
* **No Getter Available:** If a struct field does not have a corresponding getter method, direct access is necessary.
52+
* **Performance Critical Code:** In extremely rare, performance-critical sections where profiling has demonstrably shown the function call overhead of the getter to be a bottleneck, direct access *might* be considered cautiously. This should be well-documented and justified.
53+
* **Setting Values:** This rule applies to *reading* values. Setting struct fields typically involves direct assignment.
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
---
2+
description: Creating a new grpc connection should use csf's grpcclient, not golang/grpc
3+
globs: *.go
4+
alwaysApply: false
5+
---
6+
Pull in the package from github.cbhq.net/engineering/csf/grpcclient
7+
8+
Here is an example of how you should implement it
9+
```
10+
manager := csf.New()
11+
ctx := manager.ServiceContext()
12+
conn, err := grpcclient.Dial(
13+
ctx,
14+
endpoint,
15+
grpcclient.WithDialOpt(grpc.WithBlock()),
16+
)
17+
```

0 commit comments

Comments
 (0)