-
Notifications
You must be signed in to change notification settings - Fork 855
feat: replace user_last_active event with semantic activity events #1408
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
tamassoltesz
merged 7 commits into
agent/issue-1397-emit-creation-disassoc
from
agent/issue-1407-semantic-activity-events
Sep 1, 2026
+989
−101
Merged
Changes from 3 commits
Commits
Show all changes
7 commits
Select commit
Hold shift + click to select a range
145a376
feat: replace user_last_active event with semantic activity events
9957bcb
docs: condense semantic-activity-events changelog entry to a one-liner
2e1886b
feat: write semantic activity events on a fail-loud audited transaction
35f8610
fix: keep semantic activity events best-effort, make the throttle con…
da767fe
fix: wake the last-active rollup on user_creation and account_linking
65aaf78
refactor: consume shared plugin-interface activity-event vocabulary
37b2520
test: pin the account_linking rollup nudge with a link-only promptnes…
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Some comments aren't visible on the classic Files Changed page.
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
63 changes: 63 additions & 0 deletions
63
src/main/java/io/supertokens/auditlog/lifecycle/ActivityEventType.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,63 @@ | ||
| /* | ||
| * Copyright (c) 2026, VRAI Labs and/or its affiliates. All rights reserved. | ||
| * | ||
| * This software is licensed under the Apache License, Version 2.0 (the | ||
| * "License") as published by the Apache Software Foundation. | ||
| * | ||
| * You may not use this file except in compliance with the License. You may | ||
| * obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 | ||
| * | ||
| * Unless required by applicable law or agreed to in writing, software | ||
| * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT | ||
| * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the | ||
| * License for the specific language governing permissions and limitations | ||
| * under the License. | ||
| */ | ||
|
|
||
| package io.supertokens.auditlog.lifecycle; | ||
|
|
||
| /** | ||
| * The vocabulary of "activity" events written to the activity log — user-initiated interactions that mark a | ||
| * user as recently active. Like {@link LifecycleEventType lifecycle events}, an activity event is a true audit | ||
| * row: {@code ActiveUsers.updateLastActive} writes it through {@code startAuditedTransaction} (a real, | ||
| * fail-loud transaction on the same table), not a best-effort ping. Activity events feed the last-active | ||
| * rollup fold: {@code last_active(user) = MAX(created_at)} over these events (plus the activity-implying | ||
| * lifecycle events {@code user_creation} and {@code account_linking}). | ||
| * | ||
| * <p>The string {@link #getValue() value} is what lands in the {@code activity_log.event_type} column. These | ||
| * replaced the single synthetic {@code user_last_active} event, which is retired: the concrete interaction | ||
| * (a sign-in, a refresh, a session create, ...) is now recorded directly and the fold counts it. | ||
| * | ||
| * <p>Every activity is recorded; there is no throttle — a true audit trail cannot skip rows. | ||
| */ | ||
| public enum ActivityEventType { | ||
|
tamassoltesz marked this conversation as resolved.
Outdated
|
||
|
|
||
| /** An interactive sign-in of an existing user (emailpassword / webauthn / thirdparty / passwordless). */ | ||
| SIGN_IN("sign_in"), | ||
|
|
||
| /** A session was explicitly revoked for a user. */ | ||
| SIGN_OUT("sign_out"), | ||
|
|
||
| /** A session's tokens were refreshed. */ | ||
| TOKEN_REFRESH("token_refresh"), | ||
|
|
||
| /** A new session was created for a user. */ | ||
| SESSION_CREATE("session_create"), | ||
|
|
||
| /** An OAuth token exchange resolved to a session user. */ | ||
| OAUTH_TOKEN_EXCHANGE("oauth_token_exchange"), | ||
|
|
||
| /** An OAuth authorization request resolved to a session user. */ | ||
| OAUTH_AUTHORIZE("oauth_authorize"); | ||
|
|
||
| private final String value; | ||
|
|
||
| ActivityEventType(String value) { | ||
| this.value = value; | ||
| } | ||
|
|
||
| /** The string stored in the {@code activity_log.event_type} column. */ | ||
| public String getValue() { | ||
| return value; | ||
| } | ||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
61 changes: 61 additions & 0 deletions
61
src/main/java/io/supertokens/auditlog/lifecycle/LastActiveFoldEvents.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,61 @@ | ||
| /* | ||
| * Copyright (c) 2026, VRAI Labs and/or its affiliates. All rights reserved. | ||
| * | ||
| * This software is licensed under the Apache License, Version 2.0 (the | ||
| * "License") as published by the Apache Software Foundation. | ||
| * | ||
| * You may not use this file except in compliance with the License. You may | ||
| * obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 | ||
| * | ||
| * Unless required by applicable law or agreed to in writing, software | ||
| * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT | ||
| * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the | ||
| * License for the specific language governing permissions and limitations | ||
| * under the License. | ||
| */ | ||
|
|
||
| package io.supertokens.auditlog.lifecycle; | ||
|
|
||
| import java.util.Collections; | ||
| import java.util.LinkedHashSet; | ||
| import java.util.Set; | ||
| import java.util.stream.Collectors; | ||
|
|
||
| /** | ||
| * Single source of truth for the {@code activity_log.event_type} values that feed the last-active rollup | ||
| * fold, so the fold query and the {@code hasUnfoldedActivitySince} existence check cannot drift apart. The | ||
| * PostgreSQL plugin mirrors the same set in its own SQL (supertokens-postgresql-plugin#398); both halves must | ||
| * ship together. | ||
| * | ||
| * <p>The set is the six {@link ActivityEventType activity events} plus the two lifecycle events that imply | ||
| * activity: {@code user_creation} (an interactive creation counts as activity — the fold reads it in place of | ||
| * a sign-up ping) and {@code account_linking} (credits the primary user via {@code primary_or_recipe_user_id}; | ||
| * the reconcile separately drops the linked-away recipe user's row). Everything else is excluded — notably | ||
| * {@code user_import} (imported != active) and the retired {@code user_last_active} (no writer remains). | ||
| */ | ||
| public final class LastActiveFoldEvents { | ||
|
|
||
| private LastActiveFoldEvents() { | ||
| } | ||
|
|
||
| /** The {@code event_type} values the fold credits toward a user's recency. Insertion order is preserved. */ | ||
| public static final Set<String> FOLD_EVENT_TYPES; | ||
|
|
||
| static { | ||
| Set<String> types = new LinkedHashSet<>(); | ||
| for (ActivityEventType type : ActivityEventType.values()) { | ||
| types.add(type.getValue()); | ||
| } | ||
| types.add(LifecycleEventType.USER_CREATION.getValue()); | ||
| types.add(LifecycleEventType.ACCOUNT_LINKING.getValue()); | ||
|
tamassoltesz marked this conversation as resolved.
Outdated
|
||
| FOLD_EVENT_TYPES = Collections.unmodifiableSet(types); | ||
| } | ||
|
|
||
| /** | ||
| * @return the fold set as a SQL {@code IN}-list body, e.g. {@code 'sign_in', 'token_refresh', ...}. Safe to | ||
| * inline into a query string: every value is a compile-time enum constant, never user input. | ||
| */ | ||
| public static String sqlInList() { | ||
| return FOLD_EVENT_TYPES.stream().map(v -> "'" + v + "'").collect(Collectors.joining(", ")); | ||
| } | ||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.