Skip to content

feat(projects): move Project membership to the workspace column - #8830

Draft
mzxchandra wants to merge 20 commits into
stagingfrom
feat/project-workspace-column-expand
Draft

mzxchandra wants to merge 20 commits into
stagingfrom
feat/project-workspace-column-expand

Conversation

@mzxchandra

@mzxchandra mzxchandra commented Oct 9, 2026 •

Copy link
Copy Markdown
Contributor

Summary

  • Move Project membership to nullable workspace.project_id. New workspace creation and reassignment write the column; compatibility reads prefer the column and fall back to existing connector assignments when it is null.
  • Preserve healthy membership indexes during schema-push reconciliation, while still rebuilding interrupted invalid indexes.
  • Keep migration 0404 additive: add the nullable foreign key and concurrent index, with no data copy or synchronization triggers. Schema push follows the same behavior.
  • Preserve legacy fork, detach, archive, authorization and account-deletion behavior during the transition, and keep public workspace responses unchanged. Compatibility reads also work after the connector is retired.
  • This is release 1 of 2. Deploy it fully and verify older application and background-worker versions have drained before merging/deploying feat(projects): enforce Project membership and retire the connector #8590. That PR runs the registered backfill, installs final constraints and retires the connector. This release is the oldest supported application rollback after contraction; retain the contracted schema.

Type of Change

  • Feature / database migration

Testing

  • All 23 expansion/schema-push integration checks passed on both PostgreSQL 16 and 17; the earlier 39 application compatibility checks also passed.
  • Integrated rollout: the same running expansion app passed 20 checks across 36 real HTTP requests before and after the actual feat(projects): enforce Project membership and retire the connector #8590 migration runner and its replay. Existing assignments survived; legacy forks and unassigned singletons were backfilled; creation, fork, detach, lookup and authorization worked after connector retirement.
  • A real schema-push replay regression failed before the healthy-index guard was added. A negative control that skipped invalid indexes failed the recovery check; restoring the validity check passed.
  • Regression controls verified failures when legacy-read, retirement-lock and obsolete-row-cleanup guards were removed, and when the former synchronization SQL was restored.
  • Full local repository tests passed: 409 root script tests and all 20 package tasks, including 36,885 application tests. All 26 workspace type-checks, lint, 58 audits, generated-artifact checks, migration safety, schema-drift checks and workflow lint passed.
  • Hosted validation is running on the pushed revision; fresh reviews are pending. Local tests do not replace the deployment drain gate or production observation.

Checklist

  • Code follows project style guidelines
  • Self-reviewed my changes
  • Tests added/updated and passing (new tests pass the test-audit authoring gate)
  • No new warnings introduced
  • I confirm that I have read and agree to the terms outlined in the Contributor License Agreement (CLA)

@vercel

vercel Bot commented Oct 9, 2026 •

Copy link
Copy Markdown

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

Project Deployment Actions Updated
docs Ready Ready Preview Oct 9, 2026 9:38pm UTC

Request Review

@mzxchandra mzxchandra changed the title feat(projects): prepare workspace project column compatibility feat(projects): move Project membership to the workspace column Oct 9, 2026
@mzxchandra

Copy link
Copy Markdown
Contributor Author

@greptile review

@mzxchandra

Copy link
Copy Markdown
Contributor Author

@cubic review

@cubic-dev-ai

cubic-dev-ai Bot commented Oct 9, 2026

Copy link
Copy Markdown
Contributor

@cubic review

@mzxchandra I have started the AI code review. It will take a few minutes to complete.

@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.

All reported issues were addressed across 25 files

Reply with feedback, questions, or to request a fix.

Turn on auto-fix | Re-trigger cubic

Comment thread packages/db/migrations/0404_workspace_project_column.sql Outdated
@greptile-apps

greptile-apps Bot commented Oct 9, 2026 •

Copy link
Copy Markdown
Contributor

RetriggerConfidence Score: 4/5

[Critical impact] Migrates project membership from a junction table to a workspace column.

The PR still needs the rolling-deployment archive issue addressed before merging.

Findings

  1. P1 Active forks get archived Projects ▶

Summary

Moves Project membership to nullable workspace.projectId, with fallback reads for existing connector assignments.

  • Migration 0404 adds the column, foreign key, and concurrent index without copying memberships.
  • New workspace and fork writes use the column. Public workspace responses omit it.
  • The latest change keeps healthy indexes during schema push and adds interrupted-build coverage.
  • mzxchandra acknowledged that feat: establish shared file ownership foundation #8609 and feat(files): add the Project file backend and APIs #8610 must update their account-deletion callers before shipping. They accepted this as a downstream requirement because early Project deletion would violate the new foreign key.

Diagram

%%{init: {'theme': 'neutral'}}%%
flowchart TD
  A[Read workspace membership] --> B{Column populated?}
  B -->|Yes| C[Use column]
  B -->|No| D{Connector exists?}
  D -->|Yes| E[Read legacy assignment]
  D -->|No| F[No assignment]
  G[Create or reassign workspace] --> H[Write workspace.projectId]
Loading

Reviews (10) · Last reviewed commit: "fix(projects): retain healthy indexes du..." · Reviewed by Greptile

Comment thread packages/db/migrations/0404_workspace_project_column.sql Outdated
@greptile-apps

This comment has been minimized.

@mzxchandra

Copy link
Copy Markdown
Contributor Author

The removed-helper warning is a required downstream integration step. #8830 and #8590 use createProjectRecord before inserting workspace.project_id in the same transaction; the connector-based createProjectForWorkspace must not be restored. #8609 and #8610 must merge the final #8590 head and reconcile their creation/fixture callers before merging. Their shared foundation files are still awaiting that parent synchronization, so local feature-specific conversions alone do not establish a green combined stack. Preserve the downstream account-deletion storage cleanup effects and deferred Project deletion when resolving those conflicts.

@mzxchandra

Copy link
Copy Markdown
Contributor Author

@greptile

@mzxchandra

Copy link
Copy Markdown
Contributor Author

@cubic-dev-ai review this PR

@cubic-dev-ai

cubic-dev-ai Bot commented Oct 9, 2026

Copy link
Copy Markdown
Contributor

@cubic-dev-ai review this PR

@mzxchandra I have started the AI code review. It will take a few minutes to complete.

@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.

All reported issues were addressed across 26 files

Reply with feedback, questions, or to request a fix.

Turn on auto-fix | Re-trigger cubic

Comment thread packages/db/migrations/0404_workspace_project_column.sql Outdated
@mzxchandra

Copy link
Copy Markdown
Contributor Author

@greptile

@mzxchandra

Copy link
Copy Markdown
Contributor Author

@cubic-dev-ai review this PR

@cubic-dev-ai

cubic-dev-ai Bot commented Oct 9, 2026

Copy link
Copy Markdown
Contributor

@cubic-dev-ai review this PR

@mzxchandra I have started the AI code review. It will take a few minutes to complete.

@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.

No issues found across 30 files

Confidence score: 5/5

  • Automated review surfaced no issues in the provided summaries.
  • No files require special attention.

You've manually re-run cubic several times on this PR. Each manual re-review checks the full PR again and counts toward your usage quota. To preserve your usage limits, we recommend letting cubic automatically review new commits.

Turn on auto-fix | Re-trigger cubic

@mzxchandra

Copy link
Copy Markdown
Contributor Author

@greptile

@mzxchandra

Copy link
Copy Markdown
Contributor Author

@cubic-dev-ai review this PR

@cubic-dev-ai

cubic-dev-ai Bot commented Oct 9, 2026

Copy link
Copy Markdown
Contributor

@cubic-dev-ai review this PR

@mzxchandra I have started the AI code review. It will take a few minutes to complete.

@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.

No issues found across 31 files

Confidence score: 5/5

  • Automated review surfaced no issues in the provided summaries.
  • No files require special attention.

You've manually re-run cubic several times on this PR. Each manual re-review checks the full PR again and counts toward your usage quota. To preserve your usage limits, we recommend letting cubic automatically review new commits.

Turn on auto-fix | Re-trigger cubic

@mzxchandra

Copy link
Copy Markdown
Contributor Author

@greptile

@mzxchandra

Copy link
Copy Markdown
Contributor Author

@cubic-dev-ai review this PR

@cubic-dev-ai

cubic-dev-ai Bot commented Oct 9, 2026

Copy link
Copy Markdown
Contributor

@cubic-dev-ai review this PR

@mzxchandra I have started the AI code review. It will take a few minutes to complete.

@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.

All reported issues were addressed across 30 files

You've manually re-run cubic several times on this PR. Each manual re-review checks the full PR again and counts toward your usage quota. To preserve your usage limits, we recommend letting cubic automatically review new commits.

Turn on auto-fix | Re-trigger cubic

Comment thread packages/db/scripts/workspace-project-column.integration.ts Outdated
Comment thread apps/sim/lib/workspaces/__integration__/fork-sync.integration.ts
Comment thread packages/db/migrations/0404_workspace_project_column.sql
@mzxchandra

Copy link
Copy Markdown
Contributor Author

@greptile

@mzxchandra

Copy link
Copy Markdown
Contributor Author

@cubic-dev-ai review this PR

@cubic-dev-ai

cubic-dev-ai Bot commented Oct 9, 2026

Copy link
Copy Markdown
Contributor

@cubic-dev-ai review this PR

@mzxchandra I have started the AI code review. It will take a few minutes to complete.

Comment on lines +10 to +16
DO $$ BEGIN
IF NOT EXISTS (SELECT 1 FROM pg_constraint
WHERE conrelid = 'workspace'::regclass AND conname = 'workspace_project_id_project_id_fk') THEN
ALTER TABLE "workspace" ADD CONSTRAINT "workspace_project_id_project_id_fk"
FOREIGN KEY ("project_id") REFERENCES "project"("id") ON DELETE RESTRICT NOT VALID;
END IF;
END $$;

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 Active forks get archived Projects

Removing the membership bridge breaks archive decisions during the rolling deployment. Start with a legacy parent assigned through project_workspace, then create its fork on the new release. The fork gets only workspace.projectId. If an older server archives the parent, its archiveProjectWithLastEnvironment query misses the fork and archives the Project even though the child is still active. The new release then refuses further forks and disconnects from that child.

Keep older lifecycle writers aware of new memberships, or stop them from serving these operations before column-only writes begin. Draining them only before #8590 is too late.

Knowledge Base Used: Database schema and migrations

@mzxchandra

Copy link
Copy Markdown
Contributor Author

@greptile

@mzxchandra

Copy link
Copy Markdown
Contributor Author

@cubic-dev-ai review this PR

@cubic-dev-ai

cubic-dev-ai Bot commented Oct 9, 2026

Copy link
Copy Markdown
Contributor

@cubic-dev-ai review this PR

@mzxchandra I have started the AI code review. It will take a few minutes to complete.

@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.

4 issues found across 31 files

Confidence score: 3/5

  • create.ts stops writing project_workspace, so older app or worker versions can miss Project membership for newly created workspaces during the rollout. Keep the legacy assignment while versions are mixed.
  • schema.ts creates the index before the post-push replay without a concurrent build, which can block writes on large workspace tables. Make the index build concurrent or prepare it through the replay.
  • organization-workspaces.integration.ts omits forked_from_workspace_id, so the detachment integration test fails when transferWorkspaceProjects selects it. Add the column to the fixture.
  • foundation.integration.ts can release the legacy writer after matching an unrelated query, before splitForkProject reaches the Project lock. Capture the detaching transaction’s backend PID and use it to identify the intended query.
Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. When an issue isn't valid or won't be fixed in this PR, reply in its thread with the reason and then resolve the thread. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="apps/sim/lib/workspaces/create.ts">

<violation number="1" location="apps/sim/lib/workspaces/create.ts:125">
P2: New workspace creation no longer writes `project_workspace`, so older app or worker versions still running during this rollout see no Project membership for these workspaces. Preserve the legacy assignment until those versions have drained, or prevent them from handling these workspaces.</violation>
</file>

<file name="apps/sim/lib/workspaces/organization-workspaces.integration.ts">

<violation number="1" location="apps/sim/lib/workspaces/organization-workspaces.integration.ts:45">
P2: This fixture omits `forked_from_workspace_id`, which `transferWorkspaceProjects` selects through `getProjectEnvironmentSource`; the detachment integration test therefore fails with a missing-column error. Add the column to this table definition.</violation>
</file>

<file name="apps/sim/lib/projects/__integration__/foundation.integration.ts">

<violation number="1" location="apps/sim/lib/projects/__integration__/foundation.integration.ts:1404">
P2: This barrier can match an unrelated query blocked by `blockerPid`, allowing the test to release the legacy writer before `splitForkProject` reaches the Project lock. Capture the detaching transaction's backend PID and require that PID in the poll.

(Based on your team's feedback about scoping PostgreSQL lock barriers to the tested backend.)</violation>
</file>

<file name="packages/db/schema.ts">

<violation number="1" location="packages/db/schema.ts:2064">
P2: `db:push` creates this index before the post-push 0404 replay, and this declaration omits `.concurrently()`. Large workspace tables therefore get a blocking index build; mark the index concurrent or prepare it with 0404 before Drizzle push.</violation>
</file>

You've manually re-run cubic several times on this PR. Each manual re-review checks the full PR again and counts toward your usage quota. To preserve your usage limits, we recommend letting cubic automatically review new commits.

Turn on auto-fix | Re-trigger cubic

? lockedCreationContext.billedAccountUserId
: billedAccountUserId

const projectId = await createProjectRecord(tx, {

@cubic-dev-ai cubic-dev-ai Bot Oct 9, 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: New workspace creation no longer writes project_workspace, so older app or worker versions still running during this rollout see no Project membership for these workspaces. Preserve the legacy assignment until those versions have drained, or prevent them from handling these workspaces.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. When an issue isn't valid or won't be fixed in this PR, reply in its thread with the reason and then resolve the thread. At apps/sim/lib/workspaces/create.ts, line 125:

<comment>New workspace creation no longer writes `project_workspace`, so older app or worker versions still running during this rollout see no Project membership for these workspaces. Preserve the legacy assignment until those versions have drained, or prevent them from handling these workspaces.</comment>

<file context>
@@ -121,8 +122,16 @@ export async function createWorkspaceWithProjectInTransaction(
       ? lockedCreationContext.billedAccountUserId
       : billedAccountUserId
 
+  const projectId = await createProjectRecord(tx, {
+    projectName,
+    name,
</file context>
Fix with cubic

CREATE TABLE user_stats (user_id text PRIMARY KEY, storage_used_bytes bigint NOT NULL);
CREATE TABLE workspace (
id text PRIMARY KEY, name text, owner_id text, organization_id text, workspace_mode text,
project_id text NOT NULL REFERENCES project(id) ON DELETE RESTRICT,

@cubic-dev-ai cubic-dev-ai Bot Oct 9, 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: This fixture omits forked_from_workspace_id, which transferWorkspaceProjects selects through getProjectEnvironmentSource; the detachment integration test therefore fails with a missing-column error. Add the column to this table definition.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. When an issue isn't valid or won't be fixed in this PR, reply in its thread with the reason and then resolve the thread. At apps/sim/lib/workspaces/organization-workspaces.integration.ts, line 45:

<comment>This fixture omits `forked_from_workspace_id`, which `transferWorkspaceProjects` selects through `getProjectEnvironmentSource`; the detachment integration test therefore fails with a missing-column error. Add the column to this table definition.</comment>

<file context>
@@ -26,15 +26,23 @@ const database = drizzle(connection, { schema })
     CREATE TABLE user_stats (user_id text PRIMARY KEY, storage_used_bytes bigint NOT NULL);
     CREATE TABLE workspace (
       id text PRIMARY KEY, name text, owner_id text, organization_id text, workspace_mode text,
+      project_id text NOT NULL REFERENCES project(id) ON DELETE RESTRICT,
       billed_account_user_id text, allow_personal_api_keys boolean DEFAULT true,
       archived_at timestamp, organization_assigned_at timestamp, updated_at timestamp,
</file context>
Suggested change
project_id text NOT NULL REFERENCES project(id) ON DELETE RESTRICT,
project_id text NOT NULL REFERENCES project(id) ON DELETE RESTRICT,
forked_from_workspace_id text,
Fix with cubic

(error: unknown) => error
)
try {
await waitUntilBlockedBy(blocker, "lock='project'")

@cubic-dev-ai cubic-dev-ai Bot Oct 9, 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: This barrier can match an unrelated query blocked by blockerPid, allowing the test to release the legacy writer before splitForkProject reaches the Project lock. Capture the detaching transaction's backend PID and require that PID in the poll.

(Based on your team's feedback about scoping PostgreSQL lock barriers to the tested backend.)

View Feedback

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. When an issue isn't valid or won't be fixed in this PR, reply in its thread with the reason and then resolve the thread. At apps/sim/lib/projects/__integration__/foundation.integration.ts, line 1404:

<comment>This barrier can match an unrelated query blocked by `blockerPid`, allowing the test to release the legacy writer before `splitForkProject` reaches the Project lock. Capture the detaching transaction's backend PID and require that PID in the poll.

(Based on your team's feedback about scoping PostgreSQL lock barriers to the tested backend.) </comment>

<file context>
@@ -1173,12 +1360,62 @@ describe('Project foundation at the database and application boundary', () => {
+          (error: unknown) => error
+        )
+      try {
+        await waitUntilBlockedBy(blocker, "lock='project'")
+      } finally {
+        release.resolve()
</file context>
Fix with cubic

Comment thread packages/db/schema.ts
(table) => ({
ownerIdIdx: index('workspace_owner_id_idx').on(table.ownerId),
organizationIdIdx: index('workspace_organization_id_idx').on(table.organizationId),
projectIdIdx: index('workspace_project_id_id_idx').on(table.projectId, table.id),

@cubic-dev-ai cubic-dev-ai Bot Oct 9, 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: db:push creates this index before the post-push 0404 replay, and this declaration omits .concurrently(). Large workspace tables therefore get a blocking index build; mark the index concurrent or prepare it with 0404 before Drizzle push.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. When an issue isn't valid or won't be fixed in this PR, reply in its thread with the reason and then resolve the thread. At packages/db/schema.ts, line 2064:

<comment>`db:push` creates this index before the post-push 0404 replay, and this declaration omits `.concurrently()`. Large workspace tables therefore get a blocking index build; mark the index concurrent or prepare it with 0404 before Drizzle push.</comment>

<file context>
@@ -2059,6 +2061,7 @@ export const workspace = pgTable(
   (table) => ({
     ownerIdIdx: index('workspace_owner_id_idx').on(table.ownerId),
     organizationIdIdx: index('workspace_organization_id_idx').on(table.organizationId),
+    projectIdIdx: index('workspace_project_id_id_idx').on(table.projectId, table.id),
     nonNegativeStorage: check(
       'workspace_storage_used_bytes_non_negative',
</file context>
Suggested change
projectIdIdx: index('workspace_project_id_id_idx').on(table.projectId, table.id),
projectIdIdx: index('workspace_project_id_id_idx').on(table.projectId, table.id).concurrently(),
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.

1 existing issue remains and 1 new issue found across 31 files

Confidence score: 3/5

  • environment-source.ts can return the wrong environment when an older app instance reassigns only project_workspace and workspace.project_id is already set. Keep both representations synchronized until old writers are gone.
  • organization-workspaces.integration.ts no longer creates project_workspace, but the reader can query the deployed public table through the test schema’s search_path, causing detachment to fail. Update the fixture so the table is available to the test.
Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. When an issue isn't valid or won't be fixed in this PR, reply in its thread with the reason and then resolve the thread. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="apps/sim/lib/workspaces/organization-workspaces.integration.ts">

<violation number="1" location="apps/sim/lib/workspaces/organization-workspaces.integration.ts:45">
P2: This fixture no longer creates `project_workspace`, but `getProjectEnvironmentSource` detects the deployed public table and queries it through the test schema's `search_path`; detachment then fails with `relation does not exist`. Keep the legacy table in this fixture until the fallback is retired.</violation>
</file>

Requires human review: Auto-approval blocked because this review re-detected 1 unresolved issue already reported by Cubic.
You've manually re-run cubic several times on this PR. Each manual re-review checks the full PR again and counts toward your usage quota. To preserve your usage limits, we recommend letting cubic automatically review new commits.

Turn on auto-fix | Re-trigger cubic

CREATE TABLE user_stats (user_id text PRIMARY KEY, storage_used_bytes bigint NOT NULL);
CREATE TABLE workspace (
id text PRIMARY KEY, name text, owner_id text, organization_id text, workspace_mode text,
project_id text NOT NULL REFERENCES project(id) ON DELETE RESTRICT,

@cubic-dev-ai cubic-dev-ai Bot Oct 9, 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: This fixture no longer creates project_workspace, but getProjectEnvironmentSource detects the deployed public table and queries it through the test schema's search_path; detachment then fails with relation does not exist. Keep the legacy table in this fixture until the fallback is retired.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. When an issue isn't valid or won't be fixed in this PR, reply in its thread with the reason and then resolve the thread. At apps/sim/lib/workspaces/organization-workspaces.integration.ts, line 45:

<comment>This fixture no longer creates `project_workspace`, but `getProjectEnvironmentSource` detects the deployed public table and queries it through the test schema's `search_path`; detachment then fails with `relation does not exist`. Keep the legacy table in this fixture until the fallback is retired.</comment>

<file context>
@@ -26,15 +26,23 @@ const database = drizzle(connection, { schema })
     CREATE TABLE user_stats (user_id text PRIMARY KEY, storage_used_bytes bigint NOT NULL);
     CREATE TABLE workspace (
       id text PRIMARY KEY, name text, owner_id text, organization_id text, workspace_mode text,
+      project_id text NOT NULL REFERENCES project(id) ON DELETE RESTRICT,
       billed_account_user_id text, allow_personal_api_keys boolean DEFAULT true,
       archived_at timestamp, organization_assigned_at timestamp, updated_at timestamp,
</file context>
Fix with cubic

This branch was successfully deployed

1 active deployment
Preview — f0ce0899 Deployed Oct 9, 2026 by vercel[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants