Skip to content

Refactor/remove event sourcing and user state infrastructure#339

Merged
capy-ai[bot] merged 8 commits into
capy/migrate-writes-zero-mutatorsfrom
capy/delete-event-sourcing-user
Apr 16, 2026
Merged

Refactor/remove event sourcing and user state infrastructure#339
capy-ai[bot] merged 8 commits into
capy/migrate-writes-zero-mutatorsfrom
capy/delete-event-sourcing-user

Conversation

@urjitc

@urjitc urjitc commented Apr 10, 2026

Copy link
Copy Markdown
Member

This PR removes the event-sourcing layer (event store, reducer, projector, realtime event hooks) and drops all user state infrastructure. Reads and writes now go directly through the Zero-synced workspace items tables. All per-user state fields (flashcard currentIndex, quiz session, YouTube progress/playbackRate) are removed from schemas and persistence.

Event Sourcing & User State Removal

  • src/lib/workspace/workspace-event-store.ts: Deleted event persistence and broadcasting layer
  • src/lib/workspace/event-reducer.ts: Deleted client-side event replay reducer
  • src/lib/workspace/workspace-items-projector.ts: Deleted server-side event projection and DB writes
  • src/hooks/workspace/use-workspace-realtime.ts: Deleted Supabase Broadcast subscription for events
  • src/lib/realtime/server-broadcast.ts: Deleted server-side HTTP broadcast helper
  • src/lib/workspace/version-helpers.ts: Deleted optimistic event version computation
  • src/hooks/workspace/workspace-state-cache.ts: Deleted React Query snapshot and delta derivation
  • src/hooks/workspace/use-workspace-mutation.ts: Deleted optimistic mutation with conflict retry
  • src/hooks/workspace/use-workspace-events.ts: Deleted event log fetch hook
  • src/lib/workspace/events.ts: Deleted WorkspaceEvent and EventResponse types
  • src/lib/workspace/workspace-event-client-payload.ts: Deleted payload sanitization for per-user state
  • src/app/api/workspaces/[id]/events/route.ts: Deleted GET/POST events API endpoint
  • src/app/api/workspaces/[id]/state/route.ts: Deleted GET state endpoint

Types and Schema Cleanup

  • src/lib/workspace/workspace-item-model-types.ts: Removed WorkspaceItemUserStateProjection, user_state capability, and constants
  • src/lib/workspace/workspace-item-model-shared.ts: Removed findPrimaryUserState helper
  • src/lib/workspace/workspace-item-model-schemas.ts: Removed user_state capability from itemCapabilities and quizSessionSchema
  • src/lib/workspace-state/types.ts: Removed FlashcardData.currentIndex, QuizData.session, QuizSessionData interface, YouTubeData.progress, playbackRate
  • src/lib/workspace-state/item-data-schemas.ts: Removed optional user state fields from schemas
  • src/lib/workspace-state/state.ts: Removed currentIndex from flashcard defaultDataFor
  • src/lib/db/schema.ts: Removed workspaceEvents, workspaceItemUserState, workspaceItemProjectionState tables
  • src/lib/db/relations.ts: Removed relations for deleted tables
  • src/lib/db/types.ts: Removed type exports for deleted tables

Component and Hook Updates

  • src/lib/workspace/workspace-item-model.ts: Simplified rehydrateWorkspaceItemData and splitWorkspaceItem to ignore userStates; removed extractWorkspaceItemUserStates
  • src/lib/workspace/workspace-state-read.ts: New direct table loader replacing state-loader
  • src/lib/workspace/workspace-item-sanitize.ts: New stub file for sanitization helpers split from workspace-item-write
  • src/components/workspace-canvas/FlashcardWorkspaceCard.tsx: currentIndex is local-only state (useState(0))
  • src/components/workspace-canvas/QuizContent.tsx: session data is local-only state
  • src/app/dashboard/page.tsx: Removed useWorkspaceEvents usage
  • src/lib/auth.ts: Removed workspaceEvents references from account linking migration

Database Migration

  • drizzle/0003_drop_workspace_event_tables.sql: Migration to drop workspace_events, workspace_item_user_state, and workspace_item_projection_state tables

Open in Capy ENG-17 · 5.4

@vercel

vercel Bot commented Apr 10, 2026

Copy link
Copy Markdown
Contributor

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
thinkex Ready Ready Preview, Comment Apr 16, 2026 10:13pm

Request Review

@urjitc urjitc added the capy Generated by capy.ai label Apr 10, 2026 — with Capy AI
@github-project-automation github-project-automation Bot moved this to Backlog in Dev Board Apr 10, 2026
@coderabbitai

coderabbitai Bot commented Apr 10, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 112643bd-989b-4753-b7da-19b21af1ca26

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch capy/delete-event-sourcing-user

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@capy-ai capy-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added 1 comment

Comment thread src/lib/auth.ts Outdated

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1 issue found across 58 files

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="src/lib/auth.ts">

<violation number="1" location="src/lib/auth.ts:28">
P0: Hardcoded auth secret fallback is a security risk in production. If both `BETTER_AUTH_SECRET` and `AUTH_SECRET` env vars are unset (e.g., misconfiguration during deploy), the app silently uses a publicly visible secret, enabling session forgery. Since this repo is open source, the fallback value is known to everyone.

Restrict the fallback to development only, and throw at startup if no secret is configured in production.</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

Comment thread src/lib/auth.ts Outdated
@greptile-apps

greptile-apps Bot commented Apr 10, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR removes the entire event-sourcing infrastructure (event store, reducer, projector, realtime hooks) and all per-user state persistence (flashcard currentIndex, quiz session, YouTube progress), replacing server-side event-sourced writes with direct Zero-synced table reads/writes via @rocicorp/zero mutators. The refactor is large but coherent — deleted code is cleanly reflected in schema, types, migrations, and components.

Confidence Score: 5/5

Safe to merge — all remaining findings are P2 style/cleanup items with no correctness impact.

All six findings are P2: dead parameter, no-op stubs without comments, a stale developer note, and a defensive migration suggestion. No logic errors, data loss paths, or broken contracts were found. The core refactor (Zero mutators, server auth guards, direct DB loader, local-only flashcard/quiz state) is coherent and correct.

drizzle/0003_drop_workspace_event_tables.sql (add CASCADE for safety), src/lib/zero/mutators.ts (remove dead userId parameter).

Important Files Changed

Filename Overview
drizzle/0003_drop_workspace_event_tables.sql Drops three event-sourcing tables; missing CASCADE may cause FK constraint errors if cross-table dependencies exist.
src/lib/workspace/workspace-item-sanitize.ts New file with two no-op identity functions; lacks explanatory comment on why sanitization is intentionally skipped.
src/lib/zero/mutators.ts Zero client mutators look correct; userId parameter in insertItem/upsertItem is dead code left from user-state era.
src/lib/zero/server-mutators.ts Server-side auth guard and extracted-row sync logic are correct; move/moveMany correctly skip extracted sync since content is unchanged.
src/lib/workspace/workspace-state-read.ts New direct loader replacing event-sourced state; _options / userId parameter is unused dead signature surface.
src/hooks/workspace/use-workspace-state.ts Zero-backed hook is correct; hardcoded version: 0 and no-op refetch are unexplained stubs that may mislead callers.
src/components/workspace-canvas/FlashcardWorkspaceCard.tsx currentIndex correctly moved to local useState; stale developer-notes comment remains at handleIndexChange.
src/components/workspace-canvas/QuizContent.tsx Quiz session state correctly moved to local useState; _onUpdateData is intentionally unused after removing server-side session persistence.
src/lib/workspace/workspace-item-write.ts Insert/upsert/delete helpers look correct; folder-child unparenting during delete properly propagates extracted row updates.
src/lib/workspace/mutation-helpers.ts Simplified mutation helpers correctly use the new loadWorkspaceState; auth and permission checks are preserved.

Comments Outside Diff (3)

  1. src/lib/zero/mutators.ts, line 296-313 (link)

    P2 Dead userId parameter in insertItem and upsertItem

    Both insertItem (line 296) and upsertItem (line 316) accept userId: string | null in their params, but userId is never read inside either function body. This was presumably used to write per-user state previously; now it is dead code that can be confusing and pollutes every call site.

    Fix in Cursor

  2. src/components/workspace-canvas/FlashcardWorkspaceCard.tsx, line 191-196 (link)

    P2 Stale developer-notes comment

    The comment block ("Don't persist on every click…Let's keep it local for now, prop update on unmount?") describes a decision that was already made — index is local-only state after this refactor. The comment no longer reflects an open question and should be removed.

    Fix in Cursor

  3. src/hooks/workspace/use-workspace-state.ts, line 80-82 (link)

    P2 Hardcoded version: 0 and no-op refetch may mislead callers

    version is hardcoded to 0 and refetch is a no-op async () => {}. If any consumer checks version to gate optimistic writes or calls refetch expecting data to re-load, these silently do nothing. Documenting that these are intentional stubs (Zero provides real-time sync so polling is unnecessary) would prevent confusion — or remove them if no consumer depends on them.

    Fix in Cursor

Fix All in Cursor

Reviews (1): Last reviewed commit: "Remove auth secret fallback" | Re-trigger Greptile

Comment on lines +1 to +11
import type { Item } from "@/lib/workspace-state/types";

export function sanitizeWorkspaceItemForPersistence(item: Item): Item {
return item;
}

export function sanitizeWorkspaceItemChanges(
changes: Partial<Item>,
): Partial<Item> {
return changes;
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 No-op sanitize stubs without explanation

Both exported functions are pure identity pass-throughs with no comment explaining whether this is intentional (user-state fields no longer exist in the type, so nothing to strip), or whether real sanitization logic is deferred. A brief comment would prevent future contributors from accidentally skipping a needed implementation.

Suggested change
import type { Item } from "@/lib/workspace-state/types";
export function sanitizeWorkspaceItemForPersistence(item: Item): Item {
return item;
}
export function sanitizeWorkspaceItemChanges(
changes: Partial<Item>,
): Partial<Item> {
return changes;
}
import type { Item } from "@/lib/workspace-state/types";
// User-state fields (currentIndex, quiz session, YouTube progress) were
// removed from Item in this refactor, so no sanitization is currently needed.
// These stubs are kept as extension points for future server-side field filtering.
export function sanitizeWorkspaceItemForPersistence(item: Item): Item {
return item;
}
export function sanitizeWorkspaceItemChanges(
changes: Partial<Item>,
): Partial<Item> {
return changes;
}

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

Fix in Cursor

Comment on lines +103 to +108
export async function loadWorkspaceState(
workspaceId: string,
_options?: { userId?: string | null },
): Promise<Item[]> {
return db.transaction((tx) => readWorkspaceState(tx, workspaceId));
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Unused _options parameter is dead API surface

_options (including userId) was used by the old state loader to fetch per-user projections. Now that user state is gone it is truly dead. Keeping it preserves a confusing call-site signature across all callers (e.g., mutation-helpers.ts, API routes). Consider removing it or replacing with a comment explaining the deliberate signature omission.

Suggested change
export async function loadWorkspaceState(
workspaceId: string,
_options?: { userId?: string | null },
): Promise<Item[]> {
return db.transaction((tx) => readWorkspaceState(tx, workspaceId));
}
export async function loadWorkspaceState(
workspaceId: string,
): Promise<Item[]> {
return db.transaction((tx) => readWorkspaceState(tx, workspaceId));
}

Fix in Cursor

Comment on lines +1 to +8
-- Drop user state table (user state persistence removed entirely)
DROP TABLE IF EXISTS workspace_item_user_state;

-- Drop projection state table (no longer needed - Zero syncs directly)
DROP TABLE IF EXISTS workspace_item_projection_state;

-- Drop events table (no longer needed - no event sourcing)
DROP TABLE IF EXISTS workspace_events;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 DROP TABLE IF EXISTS without CASCADE may fail if cross-table FKs exist

In PostgreSQL, DROP TABLE (even with IF EXISTS) will still raise an error if another table has a foreign-key constraint pointing at the table being dropped. If workspace_item_projection_state or workspace_events cross-reference workspace_item_user_state, dropping workspace_item_user_state first would abort the migration. Adding CASCADE makes the drops unconditionally safe regardless of FK dependency order.

Suggested change
-- Drop user state table (user state persistence removed entirely)
DROP TABLE IF EXISTS workspace_item_user_state;
-- Drop projection state table (no longer needed - Zero syncs directly)
DROP TABLE IF EXISTS workspace_item_projection_state;
-- Drop events table (no longer needed - no event sourcing)
DROP TABLE IF EXISTS workspace_events;
-- Drop user state table (user state persistence removed entirely)
DROP TABLE IF EXISTS workspace_item_user_state CASCADE;
-- Drop projection state table (no longer needed - Zero syncs directly)
DROP TABLE IF EXISTS workspace_item_projection_state CASCADE;
-- Drop events table (no longer needed - no event sourcing)
DROP TABLE IF EXISTS workspace_events CASCADE;

Fix in Cursor

@urjitc

urjitc commented Apr 10, 2026

Copy link
Copy Markdown
Member Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Apr 10, 2026

Copy link
Copy Markdown
✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

3 issues found across 12 files (changes from recent commits).

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="src/app/api/zero/query/route.ts">

<violation number="1" location="src/app/api/zero/query/route.ts:9">
P1: Missing auth guard allows unauthenticated query execution on `/api/zero/query`.</violation>
</file>

<file name="src/lib/zero/client.ts">

<violation number="1" location="src/lib/zero/client.ts:9">
P1: Avoid defaulting public API URLs to localhost in client code; this breaks production clients when the env var is missing.</violation>
</file>

<file name="src/lib/zero/mutators.ts">

<violation number="1" location="src/lib/zero/mutators.ts:60">
P2: The custom JSON validator is too permissive and accepts non-plain objects (e.g. Date/Map), allowing invalid JSON-like payloads into mutators.</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

Comment thread src/app/api/zero/query/route.ts Outdated
Comment thread src/lib/zero/client.ts Outdated
Comment thread src/lib/zero/mutators.ts
Comment on lines +60 to +62
if (typeof value === "object") {
return Object.values(value as Record<string, unknown>).every(isJsonValue);
}

@cubic-dev-ai cubic-dev-ai Bot Apr 13, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: The custom JSON validator is too permissive and accepts non-plain objects (e.g. Date/Map), allowing invalid JSON-like payloads into mutators.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At src/lib/zero/mutators.ts, line 60:

<comment>The custom JSON validator is too permissive and accepts non-plain objects (e.g. Date/Map), allowing invalid JSON-like payloads into mutators.</comment>

<file context>
@@ -41,21 +38,43 @@ type JsonValue =
+    return value.every(isJsonValue);
+  }
+
+  if (typeof value === "object") {
+    return Object.values(value as Record<string, unknown>).every(isJsonValue);
+  }
</file context>
Suggested change
if (typeof value === "object") {
return Object.values(value as Record<string, unknown>).every(isJsonValue);
}
if (
typeof value === "object" &&
value !== null &&
(Object.getPrototypeOf(value) === Object.prototype ||
Object.getPrototypeOf(value) === null)
) {
return Object.values(value as Record<string, unknown>).every(isJsonValue);
}
Fix with Cubic

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

2 issues found across 11 files (changes from recent commits).

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="src/lib/auth.ts">

<violation number="1" location="src/lib/auth.ts:107">
P1: The hard-coded fallback cookie domain can break auth sessions on production deployments outside `thinkex.app`.</violation>
</file>

<file name=".env.example">

<violation number="1" location=".env.example:51">
P1: Do not hard-code the production cookie domain in `.env.example`; use a placeholder so self-hosted deployments don't inherit an invalid cookie domain and break auth cookies.</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

Comment thread src/lib/auth.ts
Comment on lines +107 to +108
enabled: process.env.NODE_ENV === "production",
domain: process.env.ZERO_COOKIE_DOMAIN ?? ".thinkex.app",

@cubic-dev-ai cubic-dev-ai Bot Apr 13, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1: The hard-coded fallback cookie domain can break auth sessions on production deployments outside thinkex.app.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At src/lib/auth.ts, line 107:

<comment>The hard-coded fallback cookie domain can break auth sessions on production deployments outside `thinkex.app`.</comment>

<file context>
@@ -95,6 +103,10 @@ export const auth = betterAuth({
     // Force secure cookies (HTTPS only) - critical for preventing session hijacking
     useSecureCookies: process.env.NODE_ENV === "production",
+    crossSubDomainCookies: {
+      enabled: process.env.NODE_ENV === "production",
+      domain: process.env.ZERO_COOKIE_DOMAIN ?? ".thinkex.app",
+    },
</file context>
Suggested change
enabled: process.env.NODE_ENV === "production",
domain: process.env.ZERO_COOKIE_DOMAIN ?? ".thinkex.app",
enabled: process.env.NODE_ENV === "production" && !!process.env.ZERO_COOKIE_DOMAIN,
domain: process.env.ZERO_COOKIE_DOMAIN,
Fix with Cubic

Comment thread .env.example
# Zero Sync
NEXT_PUBLIC_ZERO_SERVER=http://localhost:4848
ZERO_AUTH_SECRET=your-shared-secret-for-jwt-signing
ZERO_COOKIE_DOMAIN=.thinkex.app

@cubic-dev-ai cubic-dev-ai Bot Apr 13, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1: Do not hard-code the production cookie domain in .env.example; use a placeholder so self-hosted deployments don't inherit an invalid cookie domain and break auth cookies.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At .env.example, line 51:

<comment>Do not hard-code the production cookie domain in `.env.example`; use a placeholder so self-hosted deployments don't inherit an invalid cookie domain and break auth cookies.</comment>

<file context>
@@ -48,4 +48,4 @@ MISTRAL_API_KEY=your-mistral-api-key
 # Zero Sync
 NEXT_PUBLIC_ZERO_SERVER=http://localhost:4848
-ZERO_AUTH_SECRET=your-shared-secret-for-jwt-signing
+ZERO_COOKIE_DOMAIN=.thinkex.app
</file context>
Suggested change
ZERO_COOKIE_DOMAIN=.thinkex.app
ZERO_COOKIE_DOMAIN=.your-domain.com
Fix with Cubic

* Enforce authentication and workspace read access checks on Zero query endpoint

* Fix Zero query workspace context checks

Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>

---------

Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
@capy-ai
capy-ai Bot merged commit 9e05a36 into capy/migrate-writes-zero-mutators Apr 16, 2026
4 of 5 checks passed
@github-project-automation github-project-automation Bot moved this from Backlog to Done in Dev Board Apr 16, 2026
capy-ai Bot added a commit that referenced this pull request Apr 16, 2026
* Replace event-sourcing writes with Zero mutators

* Fix audio duration persistence

* Make workflow persistence atomic

* Refactor: remove event sourcing and user state infrastructure (#339)

* Delete event-sourcing infrastructure and remove per-user state persistence

* Remove auth secret fallback

* Preserve legacy workspace tables

* Remove unused workspace table migration

* Fix Zero createdAt column type

* Migrate Zero integration to 1.x query/mutator architecture

* Refactor Zero auth to cookie-based + dedup server mutators

* Fix Zero query auth: fail-closed + rename hasWorkspaceReadAccess (#385)

* Enforce authentication and workspace read access checks on Zero query endpoint

* Fix Zero query workspace context checks

Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>

---------

Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>

---------

Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>

---------

Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
capy-ai Bot added a commit that referenced this pull request Apr 16, 2026
* Wire ZeroProvider and replace event-sourced reads with Zero useQuery

* Fix ZeroProvider unauthenticated render

* Fix ZeroProvider token initialization

* Refactor: workspace writes to Zero mutators (#336)

* Replace event-sourcing writes with Zero mutators

* Fix audio duration persistence

* Make workflow persistence atomic

* Refactor: remove event sourcing and user state infrastructure (#339)

* Delete event-sourcing infrastructure and remove per-user state persistence

* Remove auth secret fallback

* Preserve legacy workspace tables

* Remove unused workspace table migration

* Fix Zero createdAt column type

* Migrate Zero integration to 1.x query/mutator architecture

* Refactor Zero auth to cookie-based + dedup server mutators

* Fix Zero query auth: fail-closed + rename hasWorkspaceReadAccess (#385)

* Enforce authentication and workspace read access checks on Zero query endpoint

* Fix Zero query workspace context checks

Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>

---------

Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>

---------

Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>

---------

Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>

---------

Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
@urjitc
urjitc deleted the capy/delete-event-sourcing-user branch June 29, 2026 17:29
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

capy Generated by capy.ai

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

1 participant