@@ -24,13 +24,19 @@ describe('LoggingService', () => {
2424 it ( 'should create signing log entry' , async ( ) => {
2525 await service . logSigningAction ( {
2626 connectionId : 'conn-1' ,
27+ userId : 'user-1' ,
28+ connectionName : 'My App' ,
29+ clientPubkey : 'a' . repeat ( 64 ) ,
2730 method : 'sign_event' ,
2831 result : 'APPROVED' ,
2932 durationMs : 100 ,
3033 } ) ;
3134 expect ( prisma . signingLog ?. create ) . toHaveBeenCalledWith ( {
3235 data : expect . objectContaining ( {
3336 connectionId : 'conn-1' ,
37+ userId : 'user-1' ,
38+ connectionName : 'My App' ,
39+ clientPubkey : 'a' . repeat ( 64 ) ,
3440 method : 'sign_event' ,
3541 result : 'APPROVED' ,
3642 durationMs : 100 ,
@@ -43,6 +49,9 @@ describe('LoggingService', () => {
4349 it ( 'should include eventKind and metadata when provided' , async ( ) => {
4450 await service . logSigningAction ( {
4551 connectionId : 'conn-1' ,
52+ userId : 'user-1' ,
53+ connectionName : 'My App' ,
54+ clientPubkey : 'a' . repeat ( 64 ) ,
4655 method : 'sign_event' ,
4756 eventKind : 1 ,
4857 result : 'DENIED' ,
@@ -58,6 +67,54 @@ describe('LoggingService', () => {
5867 } ) ;
5968 } ) ;
6069
70+ describe ( 'getDashboardActivity' , ( ) => {
71+ it ( 'scopes by denormalized userId (not the connection relation) so deleted-connection logs survive' , async ( ) => {
72+ vi . mocked ( prisma . signingLog ! . findMany ! ) . mockResolvedValue ( [
73+ {
74+ id : 'log-1' ,
75+ connectionId : null , // connection was deleted; FK is SET NULL
76+ connectionName : 'Deleted App' ,
77+ method : 'sign_event' ,
78+ eventKind : 1 ,
79+ result : 'APPROVED' ,
80+ createdAt : new Date ( '2026-01-01T00:00:00Z' ) ,
81+ } as never ,
82+ ] ) ;
83+ vi . mocked ( prisma . signingLog ! . count ! ) . mockResolvedValue ( 1 ) ;
84+
85+ const result = await service . getDashboardActivity ( 'user-1' ) ;
86+
87+ // Must filter on the denormalized userId, never via `connection: { userId }`,
88+ // otherwise orphaned (connectionId=null) logs drop out of the feed.
89+ const findManyArgs = vi . mocked ( prisma . signingLog ! . findMany ! ) . mock . calls [ 0 ] ! [ 0 ] ! ;
90+ expect ( findManyArgs . where ) . toEqual ( { userId : 'user-1' } ) ;
91+ expect ( findManyArgs . where ) . not . toHaveProperty ( 'connection' ) ;
92+ // No relation include anymore — the name comes from the denormalized column.
93+ expect ( findManyArgs ) . not . toHaveProperty ( 'include' ) ;
94+
95+ expect ( result . data [ 0 ] ) . toMatchObject ( {
96+ id : 'log-1' ,
97+ connectionName : 'Deleted App' ,
98+ method : 'sign_event' ,
99+ } ) ;
100+ expect ( result . total ) . toBe ( 1 ) ;
101+ } ) ;
102+
103+ it ( 'applies connectionName and method filters against denormalized columns' , async ( ) => {
104+ vi . mocked ( prisma . signingLog ! . findMany ! ) . mockResolvedValue ( [ ] ) ;
105+ vi . mocked ( prisma . signingLog ! . count ! ) . mockResolvedValue ( 0 ) ;
106+
107+ await service . getDashboardActivity ( 'user-1' , 1 , 15 , 'My App' , 'sign_event' ) ;
108+
109+ const findManyArgs = vi . mocked ( prisma . signingLog ! . findMany ! ) . mock . calls [ 0 ] ! [ 0 ] ! ;
110+ expect ( findManyArgs . where ) . toEqual ( {
111+ userId : 'user-1' ,
112+ connectionName : 'My App' ,
113+ method : 'sign_event' ,
114+ } ) ;
115+ } ) ;
116+ } ) ;
117+
61118 describe ( 'getLogsForConnection' , ( ) => {
62119 it ( 'should return paginated logs with total' , async ( ) => {
63120 vi . mocked ( prisma . signingLog ! . findMany ! ) . mockResolvedValue ( [
0 commit comments