Skip to content

Commit ffa5226

Browse files
authored
Merge pull request #4 from Paca-AI/feature/enhance-activity-logging
Feature/enhance activity logging
2 parents db630ec + 3fdb748 commit ffa5226

8 files changed

Lines changed: 275 additions & 4 deletions

File tree

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
name: backend-pr-ci
2+
3+
on:
4+
pull_request:
5+
paths:
6+
- "backend/**"
7+
- ".github/workflows/backend-pr-ci.yml"
8+
workflow_dispatch:
9+
10+
permissions:
11+
contents: read
12+
13+
concurrency:
14+
group: backend-pr-ci-${{ github.event.pull_request.number || github.ref }}
15+
cancel-in-progress: true
16+
17+
env:
18+
GO_VERSION: "1.24"
19+
20+
jobs:
21+
lint:
22+
name: Lint
23+
runs-on: ubuntu-latest
24+
timeout-minutes: 10
25+
26+
defaults:
27+
run:
28+
working-directory: backend
29+
30+
steps:
31+
- name: Checkout repository
32+
uses: actions/checkout@v4
33+
with:
34+
fetch-depth: 1
35+
36+
- name: Setup Go
37+
uses: actions/setup-go@v5
38+
with:
39+
go-version: ${{ env.GO_VERSION }}
40+
cache-dependency-path: backend/go.sum
41+
42+
- name: Install golangci-lint
43+
run: go install github.com/golangci/golangci-lint/v2/cmd/golangci-lint@latest
44+
45+
- name: Run golangci-lint
46+
run: golangci-lint run --timeout=5m
47+
48+
build:
49+
name: Build
50+
runs-on: ubuntu-latest
51+
timeout-minutes: 10
52+
53+
defaults:
54+
run:
55+
working-directory: backend
56+
57+
steps:
58+
- name: Checkout repository
59+
uses: actions/checkout@v4
60+
with:
61+
fetch-depth: 1
62+
63+
- name: Setup Go
64+
uses: actions/setup-go@v5
65+
with:
66+
go-version: ${{ env.GO_VERSION }}
67+
cache-dependency-path: backend/go.sum
68+
69+
- name: Build WASM
70+
run: GOOS=wasip1 GOARCH=wasm go build -buildmode=c-shared -o checklist.wasm .
71+
72+
test:
73+
name: Tests
74+
runs-on: ubuntu-latest
75+
timeout-minutes: 15
76+
77+
defaults:
78+
run:
79+
working-directory: backend
80+
81+
steps:
82+
- name: Checkout repository
83+
uses: actions/checkout@v4
84+
with:
85+
fetch-depth: 1
86+
87+
- name: Setup Go
88+
uses: actions/setup-go@v5
89+
with:
90+
go-version: ${{ env.GO_VERSION }}
91+
cache-dependency-path: backend/go.sum
92+
93+
- name: Run tests (race detector)
94+
run: go test -race -timeout 60s -coverprofile=coverage.out $(go list ./...)
95+
96+
- name: Upload coverage report
97+
uses: actions/upload-artifact@v4
98+
with:
99+
name: coverage-report
100+
path: backend/coverage.out
101+
retention-days: 7
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
name: frontend-pr-ci
2+
3+
on:
4+
pull_request:
5+
paths:
6+
- "frontend/**"
7+
- ".github/workflows/frontend-pr-ci.yml"
8+
workflow_dispatch:
9+
10+
permissions:
11+
contents: read
12+
13+
concurrency:
14+
group: frontend-pr-ci-${{ github.event.pull_request.number || github.ref }}
15+
cancel-in-progress: true
16+
17+
jobs:
18+
web-quality:
19+
name: Typecheck and build frontend
20+
runs-on: ubuntu-latest
21+
timeout-minutes: 20
22+
23+
defaults:
24+
run:
25+
working-directory: frontend
26+
27+
steps:
28+
- name: Checkout repository
29+
uses: actions/checkout@v4
30+
with:
31+
fetch-depth: 1
32+
33+
- name: Setup Bun
34+
uses: oven-sh/setup-bun@v2
35+
with:
36+
bun-version: "1.2.23"
37+
38+
- name: Cache Bun packages
39+
uses: actions/cache@v4
40+
with:
41+
path: ~/.bun/install/cache
42+
key: ${{ runner.os }}-bun-${{ hashFiles('frontend/bun.lock') }}
43+
restore-keys: |
44+
${{ runner.os }}-bun-
45+
46+
- name: Install dependencies
47+
run: bun install --frozen-lockfile
48+
49+
- name: Typecheck
50+
run: bun run typecheck
51+
52+
- name: Build production bundle
53+
run: bun run build

.github/workflows/mcp-pr-ci.yml

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
name: mcp-pr-ci
2+
3+
on:
4+
pull_request:
5+
paths:
6+
- "mcp/**"
7+
- ".github/workflows/mcp-pr-ci.yml"
8+
workflow_dispatch:
9+
10+
permissions:
11+
contents: read
12+
13+
concurrency:
14+
group: mcp-pr-ci-${{ github.event.pull_request.number || github.ref }}
15+
cancel-in-progress: true
16+
17+
jobs:
18+
mcp-quality:
19+
name: Typecheck and build MCP server
20+
runs-on: ubuntu-latest
21+
timeout-minutes: 10
22+
23+
defaults:
24+
run:
25+
working-directory: mcp
26+
27+
steps:
28+
- name: Checkout repository
29+
uses: actions/checkout@v4
30+
with:
31+
fetch-depth: 1
32+
33+
- name: Setup Bun
34+
uses: oven-sh/setup-bun@v2
35+
with:
36+
bun-version: "1.2.23"
37+
38+
- name: Cache Bun packages
39+
uses: actions/cache@v4
40+
with:
41+
path: ~/.bun/install/cache
42+
key: ${{ runner.os }}-bun-mcp-${{ hashFiles('mcp/bun.lock') }}
43+
restore-keys: |
44+
${{ runner.os }}-bun-mcp-
45+
46+
- name: Install dependencies
47+
run: bun install --frozen-lockfile
48+
49+
- name: Typecheck
50+
run: bun run typecheck
51+
52+
- name: Build
53+
run: bun run build

backend/checklists.go

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,8 @@ func (p *checklistPlugin) createChecklist(req *plugin.Request, res *plugin.Respo
162162
CreatedAt: now,
163163
UpdatedAt: now,
164164
}
165+
plugin.RecordActivity(taskID, projectID, req.Caller.UserID, "task.checklist.created",
166+
map[string]any{"title": b.Title, "_description": "created checklist: \"" + b.Title + "\""})
165167
created(res, cl)
166168
}
167169

@@ -230,6 +232,8 @@ func (p *checklistPlugin) updateChecklist(req *plugin.Request, res *plugin.Respo
230232
CreatedAt: sc.str("created_at"),
231233
UpdatedAt: now,
232234
}
235+
plugin.RecordActivity(taskID, projectID, req.Caller.UserID, "task.checklist.updated",
236+
map[string]any{"title": *b.Title, "_description": "renamed checklist to \"" + *b.Title + "\""})
233237
ok(res, cl)
234238
}
235239

@@ -243,6 +247,23 @@ func (p *checklistPlugin) deleteChecklist(req *plugin.Request, res *plugin.Respo
243247
return
244248
}
245249

250+
// Fetch title before deletion so it can be included in the activity record.
251+
titleResult, err := p.db.Query(
252+
`SELECT title FROM task_checklists WHERE id = $1 AND task_id = $2`,
253+
checklistID, taskID,
254+
)
255+
if err != nil {
256+
p.log.Error("deleteChecklist title fetch: " + err.Error())
257+
res.Error(500, "failed to delete checklist")
258+
return
259+
}
260+
if len(titleResult.Rows) == 0 {
261+
res.Error(404, "checklist not found")
262+
return
263+
}
264+
titleSC := newRowScanner(titleResult.Columns, titleResult.Rows[0])
265+
clTitle := titleSC.str("title")
266+
246267
affected, err := p.db.Exec(
247268
`DELETE FROM task_checklists WHERE id = $1 AND task_id = $2`,
248269
checklistID, taskID,
@@ -256,6 +277,8 @@ func (p *checklistPlugin) deleteChecklist(req *plugin.Request, res *plugin.Respo
256277
res.Error(404, "checklist not found")
257278
return
258279
}
280+
plugin.RecordActivity(taskID, projectID, req.Caller.UserID, "task.checklist.deleted",
281+
map[string]any{"title": clTitle, "_description": "deleted checklist: \"" + clTitle + "\""})
259282
res.NoContent()
260283
}
261284

backend/go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,6 @@ module github.com/Paca-AI/first-party/checklist
22

33
go 1.24
44

5-
require github.com/Paca-AI/plugin-sdk-go v0.2.0-rc.3
5+
require github.com/Paca-AI/plugin-sdk-go v0.2.0-rc.5
66

77
require github.com/google/uuid v1.6.0

backend/go.sum

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
github.com/Paca-AI/plugin-sdk-go v0.2.0-rc.3 h1:2MFHmdVIKVo1/Cyo7GL3S/LsAFxpsqhJSAbTao+xNEw=
2-
github.com/Paca-AI/plugin-sdk-go v0.2.0-rc.3/go.mod h1:5WeC6cSEf2wM1ovICZbDaVky9oi5id/Qpdfc5LDAQnw=
1+
github.com/Paca-AI/plugin-sdk-go v0.2.0-rc.5 h1:xrEPnJLM2sdwtY/wRaGOdfeDPv5zPUpR8QZJ/w2nQVU=
2+
github.com/Paca-AI/plugin-sdk-go v0.2.0-rc.5/go.mod h1:5WeC6cSEf2wM1ovICZbDaVky9oi5id/Qpdfc5LDAQnw=
33
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
44
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=

backend/items.go

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,8 @@ func (p *checklistPlugin) createItem(req *plugin.Request, res *plugin.Response)
6767
CreatedAt: now,
6868
UpdatedAt: now,
6969
}
70+
plugin.RecordActivity(taskID, projectID, req.Caller.UserID, "task.checklist_item.created",
71+
map[string]any{"text": b.Title, "_description": "added checklist item: \"" + b.Title + "\""})
7072
created(res, item)
7173
}
7274

@@ -161,6 +163,26 @@ func (p *checklistPlugin) updateItem(req *plugin.Request, res *plugin.Response)
161163
CreatedAt: createdAt,
162164
UpdatedAt: now,
163165
}
166+
// Build change list for the activity record.
167+
changes := []map[string]any{}
168+
oldTitle := sc.str("title")
169+
if b.Title != nil && *b.Title != oldTitle {
170+
changes = append(changes, map[string]any{"field": "title", "old": oldTitle, "new": *b.Title})
171+
}
172+
oldChecked := sc.boolVal("is_checked")
173+
if b.IsChecked != nil && *b.IsChecked != oldChecked {
174+
changes = append(changes, map[string]any{"field": "is_checked", "old": oldChecked, "new": *b.IsChecked})
175+
}
176+
oldAssignee := sc.strPtr("assignee_id")
177+
if b.AssigneeID != nil && (oldAssignee == nil || *oldAssignee != *b.AssigneeID) {
178+
var oldAssigneeActivity any
179+
if oldAssignee != nil {
180+
oldAssigneeActivity = *oldAssignee
181+
}
182+
changes = append(changes, map[string]any{"field": "assignee_id", "old": oldAssigneeActivity, "new": *b.AssigneeID})
183+
}
184+
plugin.RecordActivity(taskID, projectID, req.Caller.UserID, "task.checklist_item.updated",
185+
map[string]any{"text": updTitle, "changes": changes, "_description": "updated checklist item: \"" + updTitle + "\""})
164186
ok(res, item)
165187
}
166188

@@ -175,6 +197,23 @@ func (p *checklistPlugin) deleteItem(req *plugin.Request, res *plugin.Response)
175197
return
176198
}
177199

200+
// Fetch item title before deletion for activity record.
201+
titleResult, err := p.db.Query(
202+
`SELECT title FROM task_checklist_items WHERE id = $1 AND checklist_id = $2`,
203+
itemID, checklistID,
204+
)
205+
if err != nil {
206+
p.log.Error("deleteItem title fetch: " + err.Error())
207+
res.Error(500, "failed to delete item")
208+
return
209+
}
210+
if len(titleResult.Rows) == 0 {
211+
res.Error(404, "item not found")
212+
return
213+
}
214+
itemTitleSC := newRowScanner(titleResult.Columns, titleResult.Rows[0])
215+
itemTitle := itemTitleSC.str("title")
216+
178217
affected, err := p.db.Exec(
179218
`DELETE FROM task_checklist_items WHERE id = $1 AND checklist_id = $2`,
180219
itemID, checklistID,
@@ -188,5 +227,7 @@ func (p *checklistPlugin) deleteItem(req *plugin.Request, res *plugin.Response)
188227
res.Error(404, "item not found")
189228
return
190229
}
230+
plugin.RecordActivity(taskID, projectID, req.Caller.UserID, "task.checklist_item.deleted",
231+
map[string]any{"text": itemTitle, "_description": "removed checklist item: \"" + itemTitle + "\""})
191232
res.NoContent()
192233
}

plugin.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
"id": "com.paca.checklist",
33
"displayName": "Checklist",
44
"description": "Adds named checklists with checkable items to tasks.",
5-
"version": "0.1.0",
5+
"version": "0.2.1",
66
"permissions": ["db.read", "db.write", "events.subscribe"],
77
"backend": {
88
"eventSubscriptions": ["task.deleted"],

0 commit comments

Comments
 (0)