diff --git a/Cargo.lock b/Cargo.lock
index fde973e92b..f76efb8dde 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -315,7 +315,6 @@ dependencies = [
  "upload-get",
  "url",
  "user",
- "user-identity-get",
  "uuid",
 ]
 
@@ -359,7 +358,6 @@ dependencies = [
  "tracing-subscriber",
  "url",
  "user",
- "user-identity-get",
  "uuid",
 ]
 
@@ -508,7 +506,6 @@ dependencies = [
  "upload-prepare",
  "url",
  "user",
- "user-identity-create",
  "uuid",
 ]
 
@@ -568,7 +565,6 @@ dependencies = [
  "upload-get",
  "url",
  "user",
- "user-identity-get",
  "uuid",
 ]
 
@@ -695,7 +691,6 @@ dependencies = [
  "faker-game-namespace",
  "faker-game-version",
  "faker-region",
- "faker-user",
  "futures-util",
  "game-get",
  "game-namespace-get",
@@ -842,7 +837,6 @@ dependencies = [
  "tracing",
  "tracing-subscriber",
  "url",
- "user-identity-get",
  "uuid",
 ]
 
@@ -2172,7 +2166,6 @@ dependencies = [
  "chirp-worker",
  "faker-build",
  "faker-game",
- "faker-user",
  "game-get",
  "game-namespace-get",
  "prost 0.10.4",
@@ -5290,7 +5283,6 @@ dependencies = [
  "token-create",
  "tracing-subscriber",
  "upload-get",
- "user-identity-get",
  "uuid",
 ]
 
@@ -5890,18 +5882,6 @@ dependencies = [
  "team-get",
 ]
 
-[[package]]
-name = "faker-user"
-version = "25.1.1"
-dependencies = [
- "chirp-client",
- "chirp-worker",
- "chirp-workflow",
- "prost 0.10.4",
- "rivet-operation",
- "user",
-]
-
 [[package]]
 name = "fallible-iterator"
 version = "0.3.0"
@@ -8416,7 +8396,6 @@ dependencies = [
  "tracing",
  "tracing-logfmt",
  "tracing-subscriber",
- "user-identity-create",
 ]
 
 [[package]]
@@ -9211,7 +9190,6 @@ dependencies = [
  "tracing",
  "tracing-subscriber",
  "upload-worker",
- "user-worker",
 ]
 
 [[package]]
@@ -14645,7 +14623,6 @@ dependencies = [
  "team-user-ban-get",
  "team-validate",
  "user",
- "user-identity-get",
 ]
 
 [[package]]
@@ -15893,7 +15870,6 @@ dependencies = [
  "cluster",
  "email-address-parser",
  "faker",
- "faker-user",
  "lazy_static",
  "linode",
  "rand",
@@ -15912,22 +15888,6 @@ dependencies = [
  "upload-prepare",
 ]
 
-[[package]]
-name = "user-avatar-upload-complete"
-version = "25.1.1"
-dependencies = [
- "chirp-client",
- "chirp-worker",
- "faker-user",
- "prost 0.10.4",
- "reqwest 0.11.27",
- "rivet-operation",
- "sqlx",
- "upload-complete",
- "upload-get",
- "upload-prepare",
-]
-
 [[package]]
 name = "user-delete-pending"
 version = "25.1.1"
@@ -15952,151 +15912,6 @@ dependencies = [
  "user",
 ]
 
-[[package]]
-name = "user-get"
-version = "25.1.1"
-dependencies = [
- "chirp-client",
- "chirp-worker",
- "faker-user",
- "prost 0.10.4",
- "rand",
- "rivet-operation",
- "sqlx",
- "upload-file-list",
- "upload-get",
-]
-
-[[package]]
-name = "user-identity-create"
-version = "25.1.1"
-dependencies = [
- "chirp-client",
- "chirp-worker",
- "email-address-parser",
- "faker-user",
- "prost 0.10.4",
- "rivet-operation",
-]
-
-[[package]]
-name = "user-identity-delete"
-version = "25.1.1"
-dependencies = [
- "chirp-client",
- "chirp-worker",
- "faker-user",
- "prost 0.10.4",
- "rivet-operation",
- "sqlx",
- "user-identity-create",
-]
-
-[[package]]
-name = "user-identity-get"
-version = "25.1.1"
-dependencies = [
- "chirp-client",
- "chirp-worker",
- "faker-user",
- "prost 0.10.4",
- "rivet-config",
- "rivet-operation",
- "sqlx",
- "user-get",
- "user-identity-create",
-]
-
-[[package]]
-name = "user-pending-delete-toggle"
-version = "25.1.1"
-dependencies = [
- "chirp-client",
- "chirp-worker",
- "faker-user",
- "prost 0.10.4",
- "rivet-operation",
- "sqlx",
- "user-identity-create",
- "user-identity-get",
-]
-
-[[package]]
-name = "user-profile-validate"
-version = "25.1.1"
-dependencies = [
- "chirp-client",
- "chirp-worker",
- "chirp-workflow",
- "faker-user",
- "prost 0.10.4",
- "rivet-operation",
- "sqlx",
- "user",
-]
-
-[[package]]
-name = "user-resolve-email"
-version = "25.1.1"
-dependencies = [
- "chirp-client",
- "chirp-worker",
- "faker-user",
- "prost 0.10.4",
- "rivet-operation",
- "sqlx",
- "user-identity-create",
-]
-
-[[package]]
-name = "user-team-list"
-version = "25.1.1"
-dependencies = [
- "chirp-client",
- "chirp-worker",
- "prost 0.10.4",
- "rivet-operation",
- "sqlx",
-]
-
-[[package]]
-name = "user-token-create"
-version = "25.1.1"
-dependencies = [
- "chirp-client",
- "chirp-worker",
- "faker-user",
- "prost 0.10.4",
- "rivet-operation",
- "sqlx",
- "token-create",
-]
-
-[[package]]
-name = "user-worker"
-version = "25.1.1"
-dependencies = [
- "chirp-client",
- "chirp-worker",
- "chirp-workflow",
- "chrono",
- "faker-user",
- "game-get",
- "game-namespace-get",
- "lazy_static",
- "rivet-config",
- "rivet-convert",
- "rivet-health-checks",
- "rivet-metrics",
- "rivet-runtime",
- "team-get",
- "team-member-list",
- "upload-get",
- "upload-list-for-user",
- "upload-prepare",
- "user",
-]
-
 [[package]]
 name = "utf-8"
 version = "0.7.6"
diff --git a/Cargo.toml b/Cargo.toml
index 53deea530c..0980c4a2f4 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -1,7 +1,7 @@
 
 [workspace]
 resolver = "2"
-members = ["packages/api/actor","packages/api/auth","packages/api/cf-verification","packages/api/cloud","packages/api/games","packages/api/group","packages/api/identity","packages/api/job","packages/api/matchmaker","packages/api/monolith-edge","packages/api/monolith-public","packages/api/portal","packages/api/provision","packages/api/status","packages/api/traefik-provider","packages/api/ui","packages/common/api-helper/build","packages/common/api-helper/macros","packages/common/cache/build","packages/common/cache/result","packages/common/chirp-workflow/core","packages/common/chirp-workflow/macros","packages/common/chirp/client","packages/common/chirp/metrics","packages/common/chirp/perf","packages/common/chirp/types","packages/common/chirp/worker","packages/common/chirp/worker-attributes","packages/common/claims","packages/common/config","packages/common/connection","packages/common/convert","packages/common/deno-embed","packages/common/env","packages/common/formatted-error","packages/common/global-error","packages/common/health-checks","packages/common/hub-embed","packages/common/kv-str","packages/common/metrics","packages/common/migrate","packages/common/nomad-util","packages/common/operation/core","packages/common/operation/macros","packages/common/pools","packages/common/redis-util","packages/common/runtime","packages/common/s3-util","packages/common/schemac","packages/common/service-manager","packages/common/smithy-output/api-auth/rust","packages/common/smithy-output/api-auth/rust-server","packages/common/smithy-output/api-cf-verification/rust","packages/common/smithy-output/api-cf-verification/rust-server","packages/common/smithy-output/api-cloud/rust","packages/common/smithy-output/api-cloud/rust-server","packages/common/smithy-output/api-group/rust","packages/common/smithy-output/api-group/rust-server","packages/common/smithy-output/api-identity/rust","packages/common/smithy-output/api-identity/rust-server","packages/common/smithy-output/api-job/rust","packages/common/smithy-output/api-job/rust-server","packages/common/smithy-output/api-kv/rust","packages/common/smithy-output/api-kv/rust-server","packages/common/smithy-output/api-matchmaker/rust","packages/common/smithy-output/api-matchmaker/rust-server","packages/common/smithy-output/api-party/rust","packages/common/smithy-output/api-party/rust-server","packages/common/smithy-output/api-portal/rust","packages/common/smithy-output/api-portal/rust-server","packages/common/smithy-output/api-status/rust","packages/common/smithy-output/api-status/rust-server","packages/common/smithy-output/api-traefik-provider/rust","packages/common/smithy-output/api-traefik-provider/rust-server","packages/common/test","packages/common/test-images","packages/common/types-proto/build","packages/common/types-proto/core","packages/common/util/core","packages/common/util/macros","packages/common/util/search","packages/infra/client/actor-kv","packages/infra/client/config","packages/infra/client/container-runner","packages/infra/client/echo","packages/infra/client/isolate-v8-runner","packages/infra/client/logs","packages/infra/client/manager","packages/infra/legacy/job-runner","packages/infra/schema-generator","packages/infra/server","packages/services/build","packages/services/build/ops/create","packages/services/build/ops/get","packages/services/build/ops/list-for-env","packages/services/build/ops/list-for-game","packages/services/build/standalone/default-create","packages/services/build/util","packages/services/captcha/ops/hcaptcha-config-get","packages/services/captcha/ops/hcaptcha-verify","packages/services/captcha/ops/request","packages/services/captcha/ops/turnstile-config-get","packages/services/captcha/ops/turnstile-verify","packages/services/captcha/ops/verify","packages/services/captcha/util","packages/services/cdn/ops/namespace-auth-user-remove","packages/services/cdn/ops/namespace-auth-user-update","packages/services/cdn/ops/namespace-create","packages/services/cdn/ops/namespace-domain-create","packages/services/cdn/ops/namespace-domain-remove","packages/services/cdn/ops/namespace-get","packages/services/cdn/ops/namespace-resolve-domain","packages/services/cdn/ops/ns-auth-type-set","packages/services/cdn/ops/ns-enable-domain-public-auth-set","packages/services/cdn/ops/site-create","packages/services/cdn/ops/site-get","packages/services/cdn/ops/site-list-for-game","packages/services/cdn/ops/version-get","packages/services/cdn/ops/version-prepare","packages/services/cdn/ops/version-publish","packages/services/cdn/util","packages/services/cdn/worker","packages/services/cf-custom-hostname/ops/get","packages/services/cf-custom-hostname/ops/list-for-namespace-id","packages/services/cf-custom-hostname/ops/resolve-hostname","packages/services/cf-custom-hostname/worker","packages/services/cloud/ops/device-link-create","packages/services/cloud/ops/game-config-create","packages/services/cloud/ops/game-config-get","packages/services/cloud/ops/game-token-create","packages/services/cloud/ops/namespace-create","packages/services/cloud/ops/namespace-get","packages/services/cloud/ops/namespace-token-development-create","packages/services/cloud/ops/namespace-token-public-create","packages/services/cloud/ops/version-get","packages/services/cloud/ops/version-publish","packages/services/cloud/standalone/default-create","packages/services/cloud/worker","packages/services/cluster","packages/services/cluster/standalone/datacenter-tls-renew","packages/services/cluster/standalone/default-update","packages/services/cluster/standalone/gc","packages/services/cluster/standalone/metrics-publish","packages/services/custom-user-avatar/ops/list-for-game","packages/services/custom-user-avatar/ops/upload-complete","packages/services/debug/ops/email-res","packages/services/ds","packages/services/ds-log/ops/export","packages/services/ds-log/ops/read","packages/services/dynamic-config","packages/services/email-verification/ops/complete","packages/services/email-verification/ops/create","packages/services/email/ops/send","packages/services/external/ops/request-validate","packages/services/external/worker","packages/services/faker/ops/build","packages/services/faker/ops/cdn-site","packages/services/faker/ops/game","packages/services/faker/ops/game-namespace","packages/services/faker/ops/game-version","packages/services/faker/ops/job-run","packages/services/faker/ops/job-template","packages/services/faker/ops/mm-lobby","packages/services/faker/ops/mm-lobby-row","packages/services/faker/ops/mm-player","packages/services/faker/ops/region","packages/services/faker/ops/team","packages/services/faker/ops/user","packages/services/game/ops/banner-upload-complete","packages/services/game/ops/create","packages/services/game/ops/get","packages/services/game/ops/list-all","packages/services/game/ops/list-for-team","packages/services/game/ops/logo-upload-complete","packages/services/game/ops/namespace-create","packages/services/game/ops/namespace-get","packages/services/game/ops/namespace-list","packages/services/game/ops/namespace-resolve-name-id","packages/services/game/ops/namespace-resolve-url","packages/services/game/ops/namespace-validate","packages/services/game/ops/namespace-version-history-list","packages/services/game/ops/namespace-version-set","packages/services/game/ops/recommend","packages/services/game/ops/resolve-name-id","packages/services/game/ops/resolve-namespace-id","packages/services/game/ops/token-development-validate","packages/services/game/ops/validate","packages/services/game/ops/version-create","packages/services/game/ops/version-get","packages/services/game/ops/version-list","packages/services/game/ops/version-validate","packages/services/ip/ops/info","packages/services/job-log/ops/read","packages/services/job-log/worker","packages/services/job-run","packages/services/job/standalone/gc","packages/services/job/util","packages/services/linode","packages/services/linode/standalone/gc","packages/services/load-test/standalone/api-cloud","packages/services/load-test/standalone/mm","packages/services/load-test/standalone/mm-sustain","packages/services/load-test/standalone/sqlx","packages/services/load-test/standalone/watch-requests","packages/services/mm-config/ops/game-get","packages/services/mm-config/ops/game-upsert","packages/services/mm-config/ops/lobby-group-get","packages/services/mm-config/ops/lobby-group-resolve-name-id","packages/services/mm-config/ops/lobby-group-resolve-version","packages/services/mm-config/ops/namespace-config-set","packages/services/mm-config/ops/namespace-config-validate","packages/services/mm-config/ops/namespace-create","packages/services/mm-config/ops/namespace-get","packages/services/mm-config/ops/version-get","packages/services/mm-config/ops/version-prepare","packages/services/mm-config/ops/version-publish","packages/services/mm/ops/dev-player-token-create","packages/services/mm/ops/lobby-find-fail","packages/services/mm/ops/lobby-find-lobby-query-list","packages/services/mm/ops/lobby-find-try-complete","packages/services/mm/ops/lobby-for-run-id","packages/services/mm/ops/lobby-get","packages/services/mm/ops/lobby-history","packages/services/mm/ops/lobby-idle-update","packages/services/mm/ops/lobby-list-for-namespace","packages/services/mm/ops/lobby-list-for-user-id","packages/services/mm/ops/lobby-player-count","packages/services/mm/ops/lobby-runtime-aggregate","packages/services/mm/ops/lobby-state-get","packages/services/mm/ops/player-count-for-namespace","packages/services/mm/ops/player-get","packages/services/mm/standalone/gc","packages/services/mm/util","packages/services/mm/worker","packages/services/monolith/standalone/worker","packages/services/monolith/standalone/workflow-worker","packages/services/nomad/standalone/monitor","packages/services/pegboard","packages/services/pegboard/standalone/dc-init","packages/services/pegboard/standalone/gc","packages/services/pegboard/standalone/metrics-publish","packages/services/pegboard/standalone/ws","packages/services/region/ops/get","packages/services/region/ops/list","packages/services/region/ops/list-for-game","packages/services/region/ops/recommend","packages/services/region/ops/resolve","packages/services/region/ops/resolve-for-game","packages/services/server-spec","packages/services/team-invite/ops/get","packages/services/team-invite/worker","packages/services/team/ops/avatar-upload-complete","packages/services/team/ops/get","packages/services/team/ops/join-request-list","packages/services/team/ops/member-count","packages/services/team/ops/member-get","packages/services/team/ops/member-list","packages/services/team/ops/member-relationship-get","packages/services/team/ops/profile-validate","packages/services/team/ops/recommend","packages/services/team/ops/resolve-display-name","packages/services/team/ops/user-ban-get","packages/services/team/ops/user-ban-list","packages/services/team/ops/validate","packages/services/team/util","packages/services/team/worker","packages/services/telemetry/standalone/beacon","packages/services/tier","packages/services/token/ops/create","packages/services/token/ops/exchange","packages/services/token/ops/get","packages/services/token/ops/revoke","packages/services/upload/ops/complete","packages/services/upload/ops/file-list","packages/services/upload/ops/get","packages/services/upload/ops/list-for-user","packages/services/upload/ops/prepare","packages/services/upload/worker","packages/services/user","packages/services/user-identity/ops/create","packages/services/user-identity/ops/delete","packages/services/user-identity/ops/get","packages/services/user/ops/avatar-upload-complete","packages/services/user/ops/get","packages/services/user/ops/pending-delete-toggle","packages/services/user/ops/profile-validate","packages/services/user/ops/resolve-email","packages/services/user/ops/team-list","packages/services/user/ops/token-create","packages/services/user/standalone/delete-pending","packages/services/user/worker","packages/services/workflow/standalone/gc","packages/services/workflow/standalone/metrics-publish","packages/toolchain/actors-sdk-embed","packages/toolchain/cli","packages/toolchain/js-utils-embed","packages/toolchain/toolchain","sdks/api/full/rust"]
+members = ["packages/api/actor","packages/api/auth","packages/api/cf-verification","packages/api/cloud","packages/api/games","packages/api/group","packages/api/identity","packages/api/job","packages/api/matchmaker","packages/api/monolith-edge","packages/api/monolith-public","packages/api/portal","packages/api/provision","packages/api/status","packages/api/traefik-provider","packages/api/ui","packages/common/api-helper/build","packages/common/api-helper/macros","packages/common/cache/build","packages/common/cache/result","packages/common/chirp-workflow/core","packages/common/chirp-workflow/macros","packages/common/chirp/client","packages/common/chirp/metrics","packages/common/chirp/perf","packages/common/chirp/types","packages/common/chirp/worker","packages/common/chirp/worker-attributes","packages/common/claims","packages/common/config","packages/common/connection","packages/common/convert","packages/common/deno-embed","packages/common/env","packages/common/formatted-error","packages/common/global-error","packages/common/health-checks","packages/common/hub-embed","packages/common/kv-str","packages/common/metrics","packages/common/migrate","packages/common/nomad-util","packages/common/operation/core","packages/common/operation/macros","packages/common/pools","packages/common/redis-util","packages/common/runtime","packages/common/s3-util","packages/common/schemac","packages/common/service-manager","packages/common/smithy-output/api-auth/rust","packages/common/smithy-output/api-auth/rust-server","packages/common/smithy-output/api-cf-verification/rust","packages/common/smithy-output/api-cf-verification/rust-server","packages/common/smithy-output/api-cloud/rust","packages/common/smithy-output/api-cloud/rust-server","packages/common/smithy-output/api-group/rust","packages/common/smithy-output/api-group/rust-server","packages/common/smithy-output/api-identity/rust","packages/common/smithy-output/api-identity/rust-server","packages/common/smithy-output/api-job/rust","packages/common/smithy-output/api-job/rust-server","packages/common/smithy-output/api-kv/rust","packages/common/smithy-output/api-kv/rust-server","packages/common/smithy-output/api-matchmaker/rust","packages/common/smithy-output/api-matchmaker/rust-server","packages/common/smithy-output/api-party/rust","packages/common/smithy-output/api-party/rust-server","packages/common/smithy-output/api-portal/rust","packages/common/smithy-output/api-portal/rust-server","packages/common/smithy-output/api-status/rust","packages/common/smithy-output/api-status/rust-server","packages/common/smithy-output/api-traefik-provider/rust","packages/common/smithy-output/api-traefik-provider/rust-server","packages/common/test","packages/common/test-images","packages/common/types-proto/build","packages/common/types-proto/core","packages/common/util/core","packages/common/util/macros","packages/common/util/search","packages/infra/client/actor-kv","packages/infra/client/config","packages/infra/client/container-runner","packages/infra/client/echo","packages/infra/client/isolate-v8-runner","packages/infra/client/logs","packages/infra/client/manager","packages/infra/legacy/job-runner","packages/infra/schema-generator","packages/infra/server","packages/services/build","packages/services/build/ops/create","packages/services/build/ops/get","packages/services/build/ops/list-for-env","packages/services/build/ops/list-for-game","packages/services/build/standalone/default-create","packages/services/build/util","packages/services/captcha/ops/hcaptcha-config-get","packages/services/captcha/ops/hcaptcha-verify","packages/services/captcha/ops/request","packages/services/captcha/ops/turnstile-config-get","packages/services/captcha/ops/turnstile-verify","packages/services/captcha/ops/verify","packages/services/captcha/util","packages/services/cdn/ops/namespace-auth-user-remove","packages/services/cdn/ops/namespace-auth-user-update","packages/services/cdn/ops/namespace-create","packages/services/cdn/ops/namespace-domain-create","packages/services/cdn/ops/namespace-domain-remove","packages/services/cdn/ops/namespace-get","packages/services/cdn/ops/namespace-resolve-domain","packages/services/cdn/ops/ns-auth-type-set","packages/services/cdn/ops/ns-enable-domain-public-auth-set","packages/services/cdn/ops/site-create","packages/services/cdn/ops/site-get","packages/services/cdn/ops/site-list-for-game","packages/services/cdn/ops/version-get","packages/services/cdn/ops/version-prepare","packages/services/cdn/ops/version-publish","packages/services/cdn/util","packages/services/cdn/worker","packages/services/cf-custom-hostname/ops/get","packages/services/cf-custom-hostname/ops/list-for-namespace-id","packages/services/cf-custom-hostname/ops/resolve-hostname","packages/services/cf-custom-hostname/worker","packages/services/cloud/ops/device-link-create","packages/services/cloud/ops/game-config-create","packages/services/cloud/ops/game-config-get","packages/services/cloud/ops/game-token-create","packages/services/cloud/ops/namespace-create","packages/services/cloud/ops/namespace-get","packages/services/cloud/ops/namespace-token-development-create","packages/services/cloud/ops/namespace-token-public-create","packages/services/cloud/ops/version-get","packages/services/cloud/ops/version-publish","packages/services/cloud/standalone/default-create","packages/services/cloud/worker","packages/services/cluster","packages/services/cluster/standalone/datacenter-tls-renew","packages/services/cluster/standalone/default-update","packages/services/cluster/standalone/gc","packages/services/cluster/standalone/metrics-publish","packages/services/custom-user-avatar/ops/list-for-game","packages/services/custom-user-avatar/ops/upload-complete","packages/services/debug/ops/email-res","packages/services/ds","packages/services/ds-log/ops/export","packages/services/ds-log/ops/read","packages/services/dynamic-config","packages/services/email-verification/ops/complete","packages/services/email-verification/ops/create","packages/services/email/ops/send","packages/services/external/ops/request-validate","packages/services/external/worker","packages/services/faker","packages/services/faker/ops/build","packages/services/faker/ops/cdn-site","packages/services/faker/ops/game","packages/services/faker/ops/game-namespace","packages/services/faker/ops/game-version","packages/services/faker/ops/job-run","packages/services/faker/ops/job-template","packages/services/faker/ops/mm-lobby","packages/services/faker/ops/mm-lobby-row","packages/services/faker/ops/mm-player","packages/services/faker/ops/region","packages/services/faker/ops/team","packages/services/game/ops/banner-upload-complete","packages/services/game/ops/create","packages/services/game/ops/get","packages/services/game/ops/list-all","packages/services/game/ops/list-for-team","packages/services/game/ops/logo-upload-complete","packages/services/game/ops/namespace-create","packages/services/game/ops/namespace-get","packages/services/game/ops/namespace-list","packages/services/game/ops/namespace-resolve-name-id","packages/services/game/ops/namespace-resolve-url","packages/services/game/ops/namespace-validate","packages/services/game/ops/namespace-version-history-list","packages/services/game/ops/namespace-version-set","packages/services/game/ops/recommend","packages/services/game/ops/resolve-name-id","packages/services/game/ops/resolve-namespace-id","packages/services/game/ops/token-development-validate","packages/services/game/ops/validate","packages/services/game/ops/version-create","packages/services/game/ops/version-get","packages/services/game/ops/version-list","packages/services/game/ops/version-validate","packages/services/ip/ops/info","packages/services/job-log/ops/read","packages/services/job-log/worker","packages/services/job-run","packages/services/job/standalone/gc","packages/services/job/util","packages/services/linode","packages/services/linode/standalone/gc","packages/services/load-test/standalone/api-cloud","packages/services/load-test/standalone/mm","packages/services/load-test/standalone/mm-sustain","packages/services/load-test/standalone/sqlx","packages/services/load-test/standalone/watch-requests","packages/services/mm-config/ops/game-get","packages/services/mm-config/ops/game-upsert","packages/services/mm-config/ops/lobby-group-get","packages/services/mm-config/ops/lobby-group-resolve-name-id","packages/services/mm-config/ops/lobby-group-resolve-version","packages/services/mm-config/ops/namespace-config-set","packages/services/mm-config/ops/namespace-config-validate","packages/services/mm-config/ops/namespace-create","packages/services/mm-config/ops/namespace-get","packages/services/mm-config/ops/version-get","packages/services/mm-config/ops/version-prepare","packages/services/mm-config/ops/version-publish","packages/services/mm/ops/dev-player-token-create","packages/services/mm/ops/lobby-find-fail","packages/services/mm/ops/lobby-find-lobby-query-list","packages/services/mm/ops/lobby-find-try-complete","packages/services/mm/ops/lobby-for-run-id","packages/services/mm/ops/lobby-get","packages/services/mm/ops/lobby-history","packages/services/mm/ops/lobby-idle-update","packages/services/mm/ops/lobby-list-for-namespace","packages/services/mm/ops/lobby-list-for-user-id","packages/services/mm/ops/lobby-player-count","packages/services/mm/ops/lobby-runtime-aggregate","packages/services/mm/ops/lobby-state-get","packages/services/mm/ops/player-count-for-namespace","packages/services/mm/ops/player-get","packages/services/mm/standalone/gc","packages/services/mm/util","packages/services/mm/worker","packages/services/monolith/standalone/worker","packages/services/monolith/standalone/workflow-worker","packages/services/nomad/standalone/monitor","packages/services/pegboard","packages/services/pegboard/standalone/dc-init","packages/services/pegboard/standalone/gc","packages/services/pegboard/standalone/metrics-publish","packages/services/pegboard/standalone/ws","packages/services/region/ops/get","packages/services/region/ops/list","packages/services/region/ops/list-for-game","packages/services/region/ops/recommend","packages/services/region/ops/resolve","packages/services/region/ops/resolve-for-game","packages/services/server-spec","packages/services/team-invite/ops/get","packages/services/team-invite/worker","packages/services/team/ops/avatar-upload-complete","packages/services/team/ops/get","packages/services/team/ops/join-request-list","packages/services/team/ops/member-count","packages/services/team/ops/member-get","packages/services/team/ops/member-list","packages/services/team/ops/member-relationship-get","packages/services/team/ops/profile-validate","packages/services/team/ops/recommend","packages/services/team/ops/resolve-display-name","packages/services/team/ops/user-ban-get","packages/services/team/ops/user-ban-list","packages/services/team/ops/validate","packages/services/team/util","packages/services/team/worker","packages/services/telemetry/standalone/beacon","packages/services/tier","packages/services/token/ops/create","packages/services/token/ops/exchange","packages/services/token/ops/get","packages/services/token/ops/revoke","packages/services/upload/ops/complete","packages/services/upload/ops/file-list","packages/services/upload/ops/get","packages/services/upload/ops/list-for-user","packages/services/upload/ops/prepare","packages/services/upload/worker","packages/services/user","packages/services/user/standalone/delete-pending","packages/services/workflow/standalone/gc","packages/services/workflow/standalone/metrics-publish","packages/toolchain/actors-sdk-embed","packages/toolchain/cli","packages/toolchain/js-utils-embed","packages/toolchain/toolchain","sdks/api/full/rust"]
 
 [workspace.package]
 version = "25.1.1"
@@ -599,9 +599,6 @@ path = "packages/services/faker/ops/region"
 [workspace.dependencies.faker-team]
 path = "packages/services/faker/ops/team"
 
-[workspace.dependencies.faker-user]
-path = "packages/services/faker/ops/user"
-
 [workspace.dependencies.game-banner-upload-complete]
 path = "packages/services/game/ops/banner-upload-complete"
 
@@ -947,42 +944,9 @@ path = "packages/services/upload/worker"
 [workspace.dependencies.user]
 path = "packages/services/user"
 
-[workspace.dependencies.user-identity-create]
-path = "packages/services/user-identity/ops/create"
-
-[workspace.dependencies.user-identity-delete]
-path = "packages/services/user-identity/ops/delete"
-
-[workspace.dependencies.user-identity-get]
-path = "packages/services/user-identity/ops/get"
-
-[workspace.dependencies.user-avatar-upload-complete]
-path = "packages/services/user/ops/avatar-upload-complete"
-
-[workspace.dependencies.user-get]
-path = "packages/services/user/ops/get"
-
-[workspace.dependencies.user-pending-delete-toggle]
-path = "packages/services/user/ops/pending-delete-toggle"
-
-[workspace.dependencies.user-profile-validate]
-path = "packages/services/user/ops/profile-validate"
-
-[workspace.dependencies.user-resolve-email]
-path = "packages/services/user/ops/resolve-email"
-
-[workspace.dependencies.user-team-list]
-path = "packages/services/user/ops/team-list"
-
-[workspace.dependencies.user-token-create]
-path = "packages/services/user/ops/token-create"
-
 [workspace.dependencies.user-delete-pending]
 path = "packages/services/user/standalone/delete-pending"
 
-[workspace.dependencies.user-worker]
-path = "packages/services/user/worker"
-
 [workspace.dependencies.workflow-gc]
 path = "packages/services/workflow/standalone/gc"
 
diff --git a/packages/api/actor/Cargo.toml b/packages/api/actor/Cargo.toml
index 98cfab5fbf..75fecedf66 100644
--- a/packages/api/actor/Cargo.toml
+++ b/packages/api/actor/Cargo.toml
@@ -55,7 +55,6 @@ token-revoke.workspace = true
 upload-complete.workspace = true
 upload-get.workspace = true
 user.workspace = true
-user-identity-get.workspace = true
 
 [dev-dependencies]
 rivet-connection.workspace = true
diff --git a/packages/api/actor/src/auth.rs b/packages/api/actor/src/auth.rs
index fc38a9cea4..a700a97813 100644
--- a/packages/api/actor/src/auth.rs
+++ b/packages/api/actor/src/auth.rs
@@ -159,7 +159,7 @@ impl Auth {
 			let (user_res, game_res, team_list_res) = tokio::try_join!(
 				chirp_workflow::compat::op(
 					&ctx,
-					::user::ops::get::Input {
+					user::ops::get::Input {
 						user_ids: vec![user_ent.user_id],
 					},
 				),
diff --git a/packages/api/auth/Cargo.toml b/packages/api/auth/Cargo.toml
index eadce4d46f..ebcda033ff 100644
--- a/packages/api/auth/Cargo.toml
+++ b/packages/api/auth/Cargo.toml
@@ -46,5 +46,4 @@ rivet-auth.workspace = true
 rivet-connection.workspace = true
 
 debug-email-res.workspace = true
-user-identity-get.workspace = true
 
diff --git a/packages/api/auth/src/auth.rs b/packages/api/auth/src/auth.rs
index c82045d618..e49f10b74c 100644
--- a/packages/api/auth/src/auth.rs
+++ b/packages/api/auth/src/auth.rs
@@ -53,7 +53,7 @@ impl Auth {
 
 		let user_res = chirp_workflow::compat::op(
 			&ctx,
-			::user::ops::get::Input {
+			user::ops::get::Input {
 				user_ids: vec![user_ent.user_id],
 			},
 		)
diff --git a/packages/api/cloud/Cargo.toml b/packages/api/cloud/Cargo.toml
index 4f9bbb82df..50bfe4d27d 100644
--- a/packages/api/cloud/Cargo.toml
+++ b/packages/api/cloud/Cargo.toml
@@ -118,5 +118,3 @@ rivet-connection.workspace = true
 
 faker-region.workspace = true
 faker-team.workspace = true
-token-create.workspace = true
-user-identity-create.workspace = true
diff --git a/packages/api/cloud/src/assert.rs b/packages/api/cloud/src/assert.rs
index aa5bfeaffd..afa18deb4d 100644
--- a/packages/api/cloud/src/assert.rs
+++ b/packages/api/cloud/src/assert.rs
@@ -9,7 +9,7 @@ pub async fn user_registered(ctx: &OperationContext<()>, user_id: Uuid) -> Globa
 	// If the user has at least one identity they are considered registered
 	let identity = chirp_workflow::compat::op(
 		&ctx,
-		::user::ops::identity::get::Input {
+		user::ops::identity::get::Input {
 			user_ids: vec![user_id]
 		},
 	)
diff --git a/packages/api/cloud/src/auth.rs b/packages/api/cloud/src/auth.rs
index 772e35f94a..54a299e395 100644
--- a/packages/api/cloud/src/auth.rs
+++ b/packages/api/cloud/src/auth.rs
@@ -62,7 +62,7 @@ impl Auth {
 
 		let user_res = chirp_workflow::compat::op(
 			&ctx,
-			::user::ops::get::Input {
+			user::ops::get::Input {
 				user_ids: vec![user_ent.user_id],
 			},
 		)
@@ -279,7 +279,7 @@ impl Auth {
 			// Fetch teams associated with user
 			let teams_res = chirp_workflow::compat::op(
 				&ctx,
-				::user::ops::team_list::Input {
+				user::ops::team_list::Input {
 					user_ids: vec![user_ent.user_id.into()],
 				},
 			)
diff --git a/packages/api/games/Cargo.toml b/packages/api/games/Cargo.toml
index 77a274cdf1..e58359af51 100644
--- a/packages/api/games/Cargo.toml
+++ b/packages/api/games/Cargo.toml
@@ -47,7 +47,6 @@ token-create.workspace = true
 upload-complete.workspace = true
 upload-get.workspace = true
 user.workspace = true
-user-identity-get.workspace = true
 rivet-config.workspace = true
 rivet-env.workspace = true
 
diff --git a/packages/api/games/src/auth.rs b/packages/api/games/src/auth.rs
index aeef00de9e..070879a39f 100644
--- a/packages/api/games/src/auth.rs
+++ b/packages/api/games/src/auth.rs
@@ -99,7 +99,7 @@ impl Auth {
 			let (user_res, game_res, team_list_res) = tokio::try_join!(
 				chirp_workflow::compat::op(
 					&ctx,
-					::user::ops::get::Input {
+					user::ops::get::Input {
 						user_ids: vec![user_ent.user_id],
 					},
 				),
@@ -108,7 +108,7 @@ impl Auth {
 				}),
 				chirp_workflow::compat::op(
 					&ctx,
-					::user::ops::team_list::Input {
+					user::ops::team_list::Input {
 						user_ids: vec![user_ent.user_id.into()],
 					},
 				)
diff --git a/packages/api/group/src/assert.rs b/packages/api/group/src/assert.rs
index 1cc5697346..5c6223a756 100644
--- a/packages/api/group/src/assert.rs
+++ b/packages/api/group/src/assert.rs
@@ -6,7 +6,7 @@ use crate::auth::Auth;
 /// Validates that a given user ID is registered.
 pub async fn user_registered(ctx: &Ctx<Auth>, user_id: Uuid) -> GlobalResult<()> {
 	// If the user has at least one identity they are considered registered
-	let identity = ctx.op(::user::ops::identity::get::Input {
+	let identity = ctx.op(user::ops::identity::get::Input {
 		user_ids: vec![user_id]
 	})
 	.await?;
diff --git a/packages/api/group/src/auth.rs b/packages/api/group/src/auth.rs
index a2da76fdd5..5f121b9c57 100644
--- a/packages/api/group/src/auth.rs
+++ b/packages/api/group/src/auth.rs
@@ -58,7 +58,7 @@ impl Auth {
 
 		let user_res = chirp_workflow::compat::op(
 			&ctx,
-			::user::ops::get::Input {
+			user::ops::get::Input {
 				user_ids: vec![user_ent.user_id],
 			},
 		)
diff --git a/packages/api/group/src/fetch/group.rs b/packages/api/group/src/fetch/group.rs
index 201422ecd7..c1e23e1fc4 100644
--- a/packages/api/group/src/fetch/group.rs
+++ b/packages/api/group/src/fetch/group.rs
@@ -18,7 +18,7 @@ pub async fn summaries(
 	// Fetch team metadata
 	let (user_team_list_res, teams_res, team_member_count_res) = tokio::try_join!(
 		ctx.op(
-			::user::ops::team_list::Input {
+			user::ops::team_list::Input {
 				user_ids: vec![current_user_id.into()],
 			}
 		),
diff --git a/packages/api/group/src/fetch/identity.rs b/packages/api/group/src/fetch/identity.rs
index ac2b2b91ae..3d34c5768e 100644
--- a/packages/api/group/src/fetch/identity.rs
+++ b/packages/api/group/src/fetch/identity.rs
@@ -10,8 +10,8 @@ use crate::{auth::Auth, convert};
 pub async fn users(
 	ctx: &Ctx<Auth>,
 	user_ids: Vec<Uuid>,
-) -> GlobalResult<::user::ops::get::Output> {
-	ctx.op(::user::ops::get::Input {
+) -> GlobalResult<user::ops::get::Output> {
+	ctx.op(user::ops::get::Input {
 		user_ids,
 	})
 	.await
diff --git a/packages/api/group/tests/basic.rs b/packages/api/group/tests/basic.rs
index 7279473de3..ff20d7930b 100644
--- a/packages/api/group/tests/basic.rs
+++ b/packages/api/group/tests/basic.rs
@@ -64,7 +64,7 @@ impl Ctx {
 
 		let token_res = chirp_workflow::compat::op(
 			&ctx,
-			::user::ops::token_create::Input {
+			user::ops::token_create::Input {
 				user_id,
 				client: backend::net::ClientInfo {
 					user_agent: Some(USER_AGENT.into()),
diff --git a/packages/api/identity/Cargo.toml b/packages/api/identity/Cargo.toml
index 216a97bf22..51bc10a7e9 100644
--- a/packages/api/identity/Cargo.toml
+++ b/packages/api/identity/Cargo.toml
@@ -69,4 +69,3 @@ faker-game.workspace = true
 faker-game-namespace.workspace = true
 faker-game-version.workspace = true
 faker-region.workspace = true
-faker-user.workspace = true
diff --git a/packages/api/identity/src/assert.rs b/packages/api/identity/src/assert.rs
index 1cc5697346..5c6223a756 100644
--- a/packages/api/identity/src/assert.rs
+++ b/packages/api/identity/src/assert.rs
@@ -6,7 +6,7 @@ use crate::auth::Auth;
 /// Validates that a given user ID is registered.
 pub async fn user_registered(ctx: &Ctx<Auth>, user_id: Uuid) -> GlobalResult<()> {
 	// If the user has at least one identity they are considered registered
-	let identity = ctx.op(::user::ops::identity::get::Input {
+	let identity = ctx.op(user::ops::identity::get::Input {
 		user_ids: vec![user_id]
 	})
 	.await?;
diff --git a/packages/api/identity/src/auth.rs b/packages/api/identity/src/auth.rs
index 62308c24d6..795ae3f54c 100644
--- a/packages/api/identity/src/auth.rs
+++ b/packages/api/identity/src/auth.rs
@@ -118,7 +118,7 @@ impl Auth {
 
 		let user_res = chirp_workflow::compat::op(
 			&ctx,
-			::user::ops::get::Input {
+			user::ops::get::Input {
 				user_ids: vec![user_ent.user_id],
 			},
 		)
@@ -148,7 +148,7 @@ impl Auth {
 		// Get user
 		let user_res = chirp_workflow::compat::op(
 			&ctx,
-			::user::ops::get::Input {
+			user::ops::get::Input {
 				user_ids: vec![user_ent.user_id],
 			},
 		)
diff --git a/packages/api/identity/src/route/identities.rs b/packages/api/identity/src/route/identities.rs
index 654fca9c2c..31b17c83f0 100644
--- a/packages/api/identity/src/route/identities.rs
+++ b/packages/api/identity/src/route/identities.rs
@@ -142,10 +142,10 @@ pub async fn update_profile(
 	);
 
 	let mut sub = ctx
-		.subscribe::<::user::workflows::user::ProfileSetStatus>(("user_id", user_ent.user_id))
+		.subscribe::<user::workflows::user::ProfileSetStatus>(("user_id", user_ent.user_id))
 		.await?;
 
-	ctx.signal(::user::workflows::user::ProfileSet {
+	ctx.signal(user::workflows::user::ProfileSet {
 		display_name: body.display_name.clone(),
 		account_number: body.account_number.map(|n| n.api_try_into()).transpose()?,
 		bio: body.bio.clone(),
@@ -172,7 +172,7 @@ pub async fn validate_profile(
 		"invalid parameter account_number"
 	);
 
-	let res =  ctx.op(::user::ops::profile_validate::Input {
+	let res =  ctx.op(user::ops::profile_validate::Input {
 		user_id: user_ent.user_id,
 		display_name: body.display_name.clone(),
 		account_number: body.account_number
@@ -245,7 +245,7 @@ pub async fn complete_avatar_upload(
 ) -> GlobalResult<serde_json::Value> {
 	let user_ent = ctx.auth().user(ctx.op_ctx()).await?;
 
-	ctx.op(::user::ops::avatar_upload_complete::Input {
+	ctx.op(user::ops::avatar_upload_complete::Input {
 		user_id: user_ent.user_id,
 		upload_id: upload_id,
 	})
@@ -261,7 +261,7 @@ pub async fn mark_deletion(
 ) -> GlobalResult<serde_json::Value> {
 	let user_ent = ctx.auth().user(ctx.op_ctx()).await?;
 
-	ctx.op(::user::ops::pending_delete_toggle::Input {
+	ctx.op(user::ops::pending_delete_toggle::Input {
 		user_id: user_ent.user_id,
 		active: true,
 	})
@@ -274,7 +274,7 @@ pub async fn mark_deletion(
 pub async fn unmark_deletion(ctx: Ctx<Auth>) -> GlobalResult<serde_json::Value> {
 	let user_ent = ctx.auth().user(ctx.op_ctx()).await?;
 
-	ctx.op(::user::ops::pending_delete_toggle::Input {
+	ctx.op(user::ops::pending_delete_toggle::Input {
 		user_id: user_ent.user_id,
 		active: false,
 	})
diff --git a/packages/api/matchmaker/Cargo.toml b/packages/api/matchmaker/Cargo.toml
index 71fa656af3..f517531026 100644
--- a/packages/api/matchmaker/Cargo.toml
+++ b/packages/api/matchmaker/Cargo.toml
@@ -58,7 +58,6 @@ region-recommend.workspace = true
 region-resolve-for-game.workspace = true
 token-create.workspace = true
 token-revoke.workspace = true
-user-identity-get.workspace = true
 rivet-config.workspace = true
 rivet-env.workspace = true
 
diff --git a/packages/api/portal/src/auth.rs b/packages/api/portal/src/auth.rs
index 84ff88dddf..da25422d56 100644
--- a/packages/api/portal/src/auth.rs
+++ b/packages/api/portal/src/auth.rs
@@ -55,7 +55,7 @@ impl Auth {
 
 		let user_res = chirp_workflow::compat::op(
 			&ctx,
-			::user::ops::get::Input {
+			user::ops::get::Input {
 				user_ids: vec![user_ent.user_id],
 			},
 		)
@@ -85,7 +85,7 @@ impl Auth {
 		// Get user
 		let user_res = chirp_workflow::compat::op(
 			&ctx,
-			::user::ops::get::Input {
+			user::ops::get::Input {
 				user_ids: vec![user_ent.user_id],
 			},
 		)
diff --git a/packages/api/portal/src/build.rs b/packages/api/portal/src/build.rs
index 186f38bb9b..dbbe1df9f1 100644
--- a/packages/api/portal/src/build.rs
+++ b/packages/api/portal/src/build.rs
@@ -14,7 +14,7 @@ pub async fn group_summaries(
 	// Fetch team metadata
 	let (user_team_list_res, teams_res, team_member_count_res) = tokio::try_join!(
 		ctx.op(
-			::user::ops::team_list::Input {
+			user::ops::team_list::Input {
 				user_ids: vec![current_user_id.into()],
 			}
 		),
diff --git a/packages/api/portal/tests/basic.rs b/packages/api/portal/tests/basic.rs
index 5861990022..743c76f23f 100644
--- a/packages/api/portal/tests/basic.rs
+++ b/packages/api/portal/tests/basic.rs
@@ -63,7 +63,7 @@ impl Ctx {
 
 		let token_res = chirp_workflow::compat::op(
 			&ctx,
-			::user::ops::token_create::Input {
+			user::ops::token_create::Input {
 				user_id,
 				client: backend::net::ClientInfo {
 					user_agent: Some(USER_AGENT.into()),
diff --git a/packages/common/convert/src/convert/identity.rs b/packages/common/convert/src/convert/identity.rs
index 48c3731a6a..c6f5ce4b6a 100644
--- a/packages/common/convert/src/convert/identity.rs
+++ b/packages/common/convert/src/convert/identity.rs
@@ -51,7 +51,7 @@ pub fn summary(
 #[derive(Debug)]
 pub struct ProfileCtx<'a> {
 	pub teams_ctx: &'a fetch::identity::TeamsCtx,
-	pub linked_accounts: &'a [::user::ops::identity::get::User],
+	pub linked_accounts: &'a [user::ops::identity::get::User],
 	pub self_is_game_linked: bool,
 }
 
diff --git a/packages/common/convert/src/fetch/group.rs b/packages/common/convert/src/fetch/group.rs
index 43c90fccfd..32be09627a 100644
--- a/packages/common/convert/src/fetch/group.rs
+++ b/packages/common/convert/src/fetch/group.rs
@@ -24,7 +24,7 @@ pub async fn summaries(
 			if let Some(current_user_id) = current_user_id {
 				let user_team_list_res = chirp_workflow::compat::op(
 					&ctx,
-					::user::ops::team_list::Input {
+					user::ops::team_list::Input {
 						user_ids: vec![current_user_id.into()],
 					},
 				)
diff --git a/packages/common/convert/src/fetch/identity.rs b/packages/common/convert/src/fetch/identity.rs
index 9ec9177af9..0885834a82 100644
--- a/packages/common/convert/src/fetch/identity.rs
+++ b/packages/common/convert/src/fetch/identity.rs
@@ -9,7 +9,7 @@ use crate::convert;
 
 #[derive(Debug)]
 pub struct TeamsCtx {
-	pub user_teams: ::user::ops::team_list::Output,
+	pub user_teams: user::ops::team_list::Output,
 	pub teams: Vec<backend::team::Team>,
 }
 
@@ -94,10 +94,10 @@ pub async fn profiles(
 pub async fn users(
 	ctx: &OperationContext<()>,
 	user_ids: Vec<Uuid>,
-) -> GlobalResult<::user::ops::get::Output> {
+) -> GlobalResult<user::ops::get::Output> {
 	chirp_workflow::compat::op(
 		&ctx,
-		::user::ops::get::Input {
+		user::ops::get::Input {
 			user_ids,
 		},
 	)
@@ -107,7 +107,7 @@ pub async fn users(
 async fn teams(ctx: &OperationContext<()>, user_ids: Vec<common::Uuid>) -> GlobalResult<TeamsCtx> {
 	let user_teams_res = chirp_workflow::compat::op(
 		&ctx,
-		::user::ops::team_list::Input {
+		user::ops::team_list::Input {
 			user_ids: user_ids
 				.iter()
 				.map(|x| (*x).into())
@@ -147,10 +147,10 @@ async fn teams(ctx: &OperationContext<()>, user_ids: Vec<common::Uuid>) -> Globa
 async fn linked_accounts(
 	ctx: &OperationContext<()>,
 	user_ids: Vec<common::Uuid>,
-) -> GlobalResult<::user::ops::identity::get::Output> {
+) -> GlobalResult<user::ops::identity::get::Output> {
 	Ok(chirp_workflow::compat::op(
 		&ctx,
-		::user::ops::identity::get::Input {
+		user::ops::identity::get::Input {
 			user_ids: user_ids
 				.iter()
 				.map(|i| i.as_uuid())
diff --git a/packages/services/build/ops/create/Cargo.toml b/packages/services/build/ops/create/Cargo.toml
index 37093c21b6..44450fd6d9 100644
--- a/packages/services/build/ops/create/Cargo.toml
+++ b/packages/services/build/ops/create/Cargo.toml
@@ -24,6 +24,5 @@ reqwest = "0.11"
 
 faker-build.workspace = true
 faker-game.workspace = true
-faker-user.workspace = true
 upload-complete.workspace = true
 upload-get.workspace = true
diff --git a/packages/services/ds/Cargo.toml b/packages/services/ds/Cargo.toml
index afb29ce7ca..716d877e5b 100644
--- a/packages/services/ds/Cargo.toml
+++ b/packages/services/ds/Cargo.toml
@@ -57,7 +57,6 @@ region-get.workspace = true
 tier.workspace = true
 token-create.workspace = true
 upload-get.workspace = true
-user-identity-get.workspace = true
 game-namespace-get.workspace = true
 game-get.workspace = true
 
diff --git a/packages/services/faker/ops/user/Cargo.toml b/packages/services/faker/ops/user/Cargo.toml
deleted file mode 100644
index 9043aa7d3e..0000000000
--- a/packages/services/faker/ops/user/Cargo.toml
+++ /dev/null
@@ -1,16 +0,0 @@
-[package]
-name = "faker-user"
-version.workspace = true
-authors.workspace = true
-license.workspace = true
-edition.workspace = true
-
-[dependencies]
-chirp-client.workspace = true
-prost = "0.10"
-rivet-operation.workspace = true
-
-[dev-dependencies]
-chirp-worker.workspace = true
-chirp-workflow.workspace = true
-user.workspace = true
diff --git a/packages/services/faker/ops/user/README.md b/packages/services/faker/ops/user/README.md
deleted file mode 100644
index 418cbe23a1..0000000000
--- a/packages/services/faker/ops/user/README.md
+++ /dev/null
@@ -1 +0,0 @@
-# faker-user
diff --git a/packages/services/faker/ops/user/src/lib.rs b/packages/services/faker/ops/user/src/lib.rs
deleted file mode 100644
index 78d19a952d..0000000000
--- a/packages/services/faker/ops/user/src/lib.rs
+++ /dev/null
@@ -1,20 +0,0 @@
-use proto::backend::pkg::*;
-use rivet_operation::prelude::*;
-
-#[operation(name = "faker-user")]
-async fn handle(
-	ctx: OperationContext<faker::user::Request>,
-) -> GlobalResult<faker::user::Response> {
-	let user_id = Uuid::new_v4();
-
-	msg!([ctx] user::msg::create(user_id) -> user::msg::create_complete {
-		user_id: Some(user_id.into()),
-		namespace_id: None,
-		display_name: None,
-	})
-	.await?;
-
-	Ok(faker::user::Response {
-		user_id: Some(user_id.into()),
-	})
-}
diff --git a/packages/services/faker/ops/user/tests/integration.rs b/packages/services/faker/ops/user/tests/integration.rs
deleted file mode 100644
index 05c0c08fb2..0000000000
--- a/packages/services/faker/ops/user/tests/integration.rs
+++ /dev/null
@@ -1,14 +0,0 @@
-use chirp_worker::prelude::*;
-
-#[worker_test]
-async fn empty(ctx: TestCtx) {
-	let res = op!([ctx] faker_user {}).await.unwrap();
-
-	let get_res = (*ctx).op(::user::ops::get::Input {
-		user_ids: vec![res.user_id.unwrap().as_uuid()],
-	})
-	.await
-	.unwrap();
-
-	assert_eq!(1, get_res.users.len(), "user not created");
-}
diff --git a/packages/services/faker/tests/user.rs b/packages/services/faker/tests/user.rs
index 8c632a2bbe..d6d4e33607 100644
--- a/packages/services/faker/tests/user.rs
+++ b/packages/services/faker/tests/user.rs
@@ -4,7 +4,7 @@ use chirp_workflow::prelude::*;
 async fn empty(ctx: TestCtx) {
 	let res = ctx.op(faker::ops::user::Input {}).await.unwrap();
 
-	let get_res = ctx.op(::user::ops::get::Input {
+	let get_res = ctx.op(user::ops::get::Input {
 		user_ids: vec![res.user_id],
 	})
 	.await
diff --git a/packages/services/load-test/standalone/mm-sustain/Cargo.toml b/packages/services/load-test/standalone/mm-sustain/Cargo.toml
index 26b9ea21c9..a01b1a14bd 100644
--- a/packages/services/load-test/standalone/mm-sustain/Cargo.toml
+++ b/packages/services/load-test/standalone/mm-sustain/Cargo.toml
@@ -28,7 +28,6 @@ mm-config-version-get.workspace = true
 game-namespace-version-set.workspace = true
 mm-lobby-get.workspace = true
 job-run.workspace = true
-user-identity-create.workspace = true
 token-create.workspace = true
 util-mm.workspace = true
 rivet-config.workspace = true
diff --git a/packages/services/mm/worker/tests/lobby_find.rs b/packages/services/mm/worker/tests/lobby_find.rs
index 0f8f2c45d8..054cbd21fd 100644
--- a/packages/services/mm/worker/tests/lobby_find.rs
+++ b/packages/services/mm/worker/tests/lobby_find.rs
@@ -529,7 +529,7 @@ async fn registered_verification(ctx: TestCtx) {
 	);
 
 	let email = util::faker::email();
-	ctx.op(::user::ops::identity::create::Input {
+	ctx.op(user::ops::identity::create::Input {
 		user_id,
 		identity: Some(backend::user_identity::Identity {
 			kind: Some(backend::user_identity::identity::Kind::Email(
diff --git a/packages/services/monolith/standalone/worker/Cargo.toml b/packages/services/monolith/standalone/worker/Cargo.toml
index 12be7403b4..1d0015d962 100644
--- a/packages/services/monolith/standalone/worker/Cargo.toml
+++ b/packages/services/monolith/standalone/worker/Cargo.toml
@@ -31,5 +31,4 @@ mm-worker.workspace = true
 team-invite-worker.workspace = true
 team-worker.workspace = true
 upload-worker.workspace = true
-user-worker.workspace = true
 rivet-config.workspace = true
diff --git a/packages/services/monolith/standalone/worker/src/lib.rs b/packages/services/monolith/standalone/worker/src/lib.rs
index c44bbbf0e5..f4d839ecc3 100644
--- a/packages/services/monolith/standalone/worker/src/lib.rs
+++ b/packages/services/monolith/standalone/worker/src/lib.rs
@@ -34,7 +34,6 @@ pub async fn start(config: rivet_config::Config, pools: rivet_pools::Pools) -> G
 		team_invite_worker,
 		team_worker,
 		upload_worker,
-		user_worker,
 	];
 
 	// Wait for task to exit
diff --git a/packages/services/team/worker/Cargo.toml b/packages/services/team/worker/Cargo.toml
index d2f1b37545..acee6f0896 100644
--- a/packages/services/team/worker/Cargo.toml
+++ b/packages/services/team/worker/Cargo.toml
@@ -18,7 +18,6 @@ rivet-runtime.workspace = true
 team-join-request-list.workspace = true
 team-profile-validate.workspace = true
 team-validate.workspace = true
-user-identity-get.workspace = true
 game-namespace-list.workspace = true
 mm-lobby-list-for-namespace.workspace = true
 rivet-config.workspace = true
diff --git a/packages/services/user-identity/ops/create/Cargo.toml b/packages/services/user-identity/ops/create/Cargo.toml
deleted file mode 100644
index 0cce06e63f..0000000000
--- a/packages/services/user-identity/ops/create/Cargo.toml
+++ /dev/null
@@ -1,17 +0,0 @@
-[package]
-name = "user-identity-create"
-version.workspace = true
-authors.workspace = true
-license.workspace = true
-edition.workspace = true
-
-[dependencies]
-rivet-operation.workspace = true
-chirp-client.workspace = true
-prost = "0.10"
-email-address-parser = "1.0.1"
-
-[dev-dependencies]
-chirp-worker.workspace = true
-
-faker-user.workspace = true
diff --git a/packages/services/user-identity/ops/create/README.md b/packages/services/user-identity/ops/create/README.md
deleted file mode 100644
index 3c53800561..0000000000
--- a/packages/services/user-identity/ops/create/README.md
+++ /dev/null
@@ -1 +0,0 @@
-# user-identity-create
diff --git a/packages/services/user-identity/ops/create/src/lib.rs b/packages/services/user-identity/ops/create/src/lib.rs
deleted file mode 100644
index d10168c2a7..0000000000
--- a/packages/services/user-identity/ops/create/src/lib.rs
+++ /dev/null
@@ -1,66 +0,0 @@
-use email_address_parser::EmailAddress;
-use proto::backend::{self, pkg::*};
-use rivet_operation::prelude::*;
-use serde_json::json;
-
-#[operation(name = "user-identity-create")]
-async fn handle(
-	ctx: OperationContext<user_identity::create::Request>,
-) -> GlobalResult<user_identity::create::Response> {
-	let user_id = unwrap_ref!(ctx.user_id).as_uuid();
-	let identity = unwrap_ref!(ctx.identity);
-	let identity_kind = unwrap_ref!(identity.kind);
-
-	match &identity_kind {
-		backend::user_identity::identity::Kind::Email(email) => {
-			ensure!(EmailAddress::is_valid(&email.email, None), "invalid email");
-
-			sql_execute!(
-				[ctx]
-				"
-				INSERT INTO db_user_identity.emails (email, user_id, create_ts)
-				VALUES ($1, $2, $3)
-				",
-				&email.email,
-				user_id,
-				ctx.ts(),
-			)
-			.await?;
-
-			msg!([ctx] analytics::msg::event_create() {
-				events: vec![
-					analytics::msg::event_create::Event {
-						event_id: Some(Uuid::new_v4().into()),
-						name: "user_identity.create".into(),
-						properties_json: Some(serde_json::to_string(&json!({
-							"identity_email": email.email,
-							"user_id": user_id,
-						}))?),
-						..Default::default()
-					}
-				],
-			})
-			.await?;
-		}
-		backend::user_identity::identity::Kind::DefaultUser(_) => {
-			bail!("cannot create default user identity")
-		}
-	}
-
-	ctx.cache()
-		.purge("user_identity.identity", [user_id])
-		.await?;
-
-	msg!([ctx] user_identity::msg::create_complete(user_id) {
-		user_id: ctx.user_id,
-		identity: ctx.identity.clone(),
-	})
-	.await?;
-
-	msg!([ctx] user::msg::update(user_id) {
-		user_id: ctx.user_id,
-	})
-	.await?;
-
-	Ok(user_identity::create::Response {})
-}
diff --git a/packages/services/user-identity/ops/create/tests/integration.rs b/packages/services/user-identity/ops/create/tests/integration.rs
deleted file mode 100644
index 9a92dfe3af..0000000000
--- a/packages/services/user-identity/ops/create/tests/integration.rs
+++ /dev/null
@@ -1,34 +0,0 @@
-use chirp_worker::prelude::*;
-use proto::backend;
-
-#[worker_test]
-async fn email(ctx: TestCtx) {
-	let user_res = op!([ctx] faker_user {
-		..Default::default()
-	})
-	.await
-	.unwrap();
-
-	let email = util::faker::email();
-	op!([ctx] user_identity_create {
-		user_id: user_res.user_id,
-		identity: Some(backend::user_identity::Identity {
-			kind: Some(backend::user_identity::identity::Kind::Email(
-				backend::user_identity::identity::Email {
-					email: email.clone(),
-				}
-			)),
-		}),
-	})
-	.await
-	.unwrap();
-
-	let (sql_exists,) = sqlx::query_as::<_, (bool,)>(
-		"SELECT EXISTS (SELECT 1 FROM db_user_identity.emails WHERE email = $1)",
-	)
-	.bind(&email)
-	.fetch_one(&ctx.crdb().await.unwrap())
-	.await
-	.unwrap();
-	assert!(sql_exists, "identity not created");
-}
diff --git a/packages/services/user-identity/ops/delete/Cargo.toml b/packages/services/user-identity/ops/delete/Cargo.toml
deleted file mode 100644
index 9ff6d3c4dc..0000000000
--- a/packages/services/user-identity/ops/delete/Cargo.toml
+++ /dev/null
@@ -1,20 +0,0 @@
-[package]
-name = "user-identity-delete"
-version.workspace = true
-authors.workspace = true
-license.workspace = true
-edition.workspace = true
-
-[dependencies]
-rivet-operation.workspace = true
-chirp-client.workspace = true
-prost = "0.10"
-
-[dependencies.sqlx]
-workspace = true
-
-[dev-dependencies]
-chirp-worker.workspace = true
-
-faker-user.workspace = true
-user-identity-create.workspace = true
diff --git a/packages/services/user-identity/ops/delete/README.md b/packages/services/user-identity/ops/delete/README.md
deleted file mode 100644
index 8800411eb7..0000000000
--- a/packages/services/user-identity/ops/delete/README.md
+++ /dev/null
@@ -1 +0,0 @@
-# user-identity-delete
diff --git a/packages/services/user-identity/ops/delete/src/lib.rs b/packages/services/user-identity/ops/delete/src/lib.rs
deleted file mode 100644
index 86ce738708..0000000000
--- a/packages/services/user-identity/ops/delete/src/lib.rs
+++ /dev/null
@@ -1,29 +0,0 @@
-use proto::backend::pkg::*;
-use rivet_operation::prelude::*;
-
-#[operation(name = "user-identity-delete")]
-async fn handle(
-	ctx: OperationContext<user_identity::delete::Request>,
-) -> GlobalResult<user_identity::delete::Response> {
-	let user_ids = ctx
-		.user_ids
-		.iter()
-		.map(common::Uuid::as_uuid)
-		.collect::<Vec<_>>();
-
-	sql_execute!(
-		[ctx]
-		"
-		DELETE FROM db_user_identity.emails
-		WHERE user_id = ANY($1)
-		",
-		&user_ids,
-	)
-	.await?;
-
-	ctx.cache()
-		.purge("user_identity.identity", user_ids)
-		.await?;
-
-	Ok(user_identity::delete::Response {})
-}
diff --git a/packages/services/user-identity/ops/delete/tests/integration.rs b/packages/services/user-identity/ops/delete/tests/integration.rs
deleted file mode 100644
index 2fa4757398..0000000000
--- a/packages/services/user-identity/ops/delete/tests/integration.rs
+++ /dev/null
@@ -1,40 +0,0 @@
-use chirp_worker::prelude::*;
-use proto::backend;
-
-#[worker_test]
-async fn empty(ctx: TestCtx) {
-	let user_res = op!([ctx] faker_user {
-		..Default::default()
-	})
-	.await
-	.unwrap();
-
-	let email = util::faker::email();
-	op!([ctx] user_identity_create {
-		user_id: user_res.user_id,
-		identity: Some(backend::user_identity::Identity {
-			kind: Some(backend::user_identity::identity::Kind::Email(
-				backend::user_identity::identity::Email {
-					email: email.clone()
-				}
-			)),
-		}),
-	})
-	.await
-	.unwrap();
-
-	op!([ctx] user_identity_delete {
-		user_ids: vec![user_res.user_id.unwrap()],
-	})
-	.await
-	.unwrap();
-
-	let (sql_exists,) = sqlx::query_as::<_, (bool,)>(
-		"SELECT EXISTS (SELECT 1 FROM db_user_identity.emails WHERE email = $1)",
-	)
-	.bind(&email)
-	.fetch_one(&ctx.crdb().await.unwrap())
-	.await
-	.unwrap();
-	assert!(!sql_exists, "identity not deleted");
-}
diff --git a/packages/services/user-identity/ops/get/Cargo.toml b/packages/services/user-identity/ops/get/Cargo.toml
deleted file mode 100644
index 9b7ffa7c08..0000000000
--- a/packages/services/user-identity/ops/get/Cargo.toml
+++ /dev/null
@@ -1,22 +0,0 @@
-[package]
-name = "user-identity-get"
-version.workspace = true
-authors.workspace = true
-license.workspace = true
-edition.workspace = true
-
-[dependencies]
-rivet-operation.workspace = true
-chirp-client.workspace = true
-prost = "0.10"
-user-get.workspace = true
-rivet-config.workspace = true
-
-[dependencies.sqlx]
-workspace = true
-
-[dev-dependencies]
-chirp-worker.workspace = true
-
-faker-user.workspace = true
-user-identity-create.workspace = true
diff --git a/packages/services/user-identity/ops/get/README.md b/packages/services/user-identity/ops/get/README.md
deleted file mode 100644
index a6072f59bd..0000000000
--- a/packages/services/user-identity/ops/get/README.md
+++ /dev/null
@@ -1 +0,0 @@
-# user-identity-get
diff --git a/packages/services/user-identity/ops/get/src/lib.rs b/packages/services/user-identity/ops/get/src/lib.rs
deleted file mode 100644
index 3a94256e0d..0000000000
--- a/packages/services/user-identity/ops/get/src/lib.rs
+++ /dev/null
@@ -1,121 +0,0 @@
-use proto::backend::{self, pkg::*};
-use rivet_operation::prelude::*;
-
-#[derive(Debug, sqlx::FromRow)]
-struct IdentityRow {
-	user_id: Uuid,
-	email: Option<String>,
-}
-
-impl From<IdentityRow> for user_identity::get::CacheUserIdentity {
-	fn from(val: IdentityRow) -> Self {
-		user_identity::get::CacheUserIdentity {
-			user_id: Some(val.user_id.into()),
-			email: val.email,
-		}
-	}
-}
-
-#[operation(name = "user-identity-get")]
-async fn handle(
-	ctx: OperationContext<user_identity::get::Request>,
-) -> GlobalResult<user_identity::get::Response> {
-	let is_development = ctx.config().server()?.rivet.auth.access_kind
-		== rivet_config::config::rivet::AccessKind::Development;
-
-	let user_ids = ctx
-		.user_ids
-		.iter()
-		.map(common::Uuid::as_uuid)
-		.collect::<Vec<_>>();
-
-	// Get the user display names
-	let users = op!([ctx] user_get {
-		user_ids: ctx.user_ids.clone(),
-	})
-	.await?;
-
-	// Fetch the identities
-	let identities = ctx
-		.cache()
-		.fetch_all_proto("user_identity.identity", user_ids.clone(), {
-			let ctx = ctx.clone();
-			move |mut cache, user_ids| {
-				let ctx = ctx.clone();
-				async move {
-					let identity_rows = sql_fetch_all!(
-						[ctx, IdentityRow]
-						"
-						SELECT e.user_id AS user_id, e.email
-						FROM db_user_identity.emails as e
-						WHERE e.user_id = ANY($1)
-						",
-						&user_ids,
-					)
-					.await?;
-
-					for row in identity_rows {
-						cache.resolve(
-							&row.user_id.clone(),
-							user_identity::get::CacheUserIdentity::from(row),
-						);
-					}
-
-					Ok(cache)
-				}
-			}
-		})
-		.await?;
-
-	let users = user_ids
-		.iter()
-		.filter_map(|user_id| {
-			// Find matching user
-			let Some(user) = users
-				.users
-				.iter()
-				.find(|x| x.user_id.map(|x| x.as_uuid()) == Some(*user_id))
-			else {
-				return None;
-			};
-
-			// Find matching identities
-			let mut identities = identities
-				.iter()
-				.filter(|x| {
-					x.user_id
-						.as_ref()
-						.map_or(false, |x| x.as_uuid() == *user_id)
-				})
-				.flat_map(|x| {
-					IntoIterator::into_iter([x.email.as_ref().map(|email| {
-						backend::user_identity::Identity {
-							kind: Some(backend::user_identity::identity::Kind::Email(
-								backend::user_identity::identity::Email {
-									email: email.clone(),
-								},
-							)),
-						}
-					})])
-					.flatten()
-				})
-				.collect::<Vec<_>>();
-
-			// Inject identity for development users since they should behave like registered users.
-			if is_development && user.display_name == util::dev_defaults::USER_NAME {
-				identities.push(backend::user_identity::Identity {
-					kind: Some(backend::user_identity::identity::Kind::DefaultUser(
-						backend::user_identity::identity::DefaultUser {},
-					)),
-				})
-			}
-
-			Some(user_identity::get::response::User {
-				user_id: Some((*user_id).into()),
-				identities,
-			})
-		})
-		.collect::<Vec<_>>();
-
-	Ok(user_identity::get::Response { users })
-}
diff --git a/packages/services/user-identity/ops/get/tests/integration.rs b/packages/services/user-identity/ops/get/tests/integration.rs
deleted file mode 100644
index e4819e451b..0000000000
--- a/packages/services/user-identity/ops/get/tests/integration.rs
+++ /dev/null
@@ -1,41 +0,0 @@
-use chirp_worker::prelude::*;
-use proto::backend;
-
-#[worker_test]
-async fn empty(ctx: TestCtx) {
-	let user_res = op!([ctx] faker_user {
-		..Default::default()
-	})
-	.await
-	.unwrap();
-
-	let email = util::faker::email();
-	op!([ctx] user_identity_create {
-		user_id: user_res.user_id,
-		identity: Some(backend::user_identity::Identity {
-			kind: Some(backend::user_identity::identity::Kind::Email(
-				backend::user_identity::identity::Email {
-					email: email.clone()
-				}
-			)),
-		}),
-	})
-	.await
-	.unwrap();
-
-	let res = op!([ctx] user_identity_get {
-		user_ids: vec![user_res.user_id.unwrap(), Uuid::new_v4().into()],
-	})
-	.await
-	.unwrap();
-	assert_eq!(2, res.users.len());
-	assert_eq!(
-		1,
-		res.users
-			.iter()
-			.find(|u| u.user_id == user_res.user_id)
-			.unwrap()
-			.identities
-			.len()
-	);
-}
diff --git a/packages/services/user/Cargo.toml b/packages/services/user/Cargo.toml
index 4a4fea2f83..a7fc9fc3a0 100644
--- a/packages/services/user/Cargo.toml
+++ b/packages/services/user/Cargo.toml
@@ -29,7 +29,6 @@ workspace = true
 default-features = false
 
 [dev-dependencies]
-faker-user.workspace = true
 reqwest = "0.11"
 upload-prepare.workspace = true
 faker.workspace = true
diff --git a/packages/services/user/ops/avatar-upload-complete/Cargo.toml b/packages/services/user/ops/avatar-upload-complete/Cargo.toml
deleted file mode 100644
index 170f3484b9..0000000000
--- a/packages/services/user/ops/avatar-upload-complete/Cargo.toml
+++ /dev/null
@@ -1,24 +0,0 @@
-[package]
-name = "user-avatar-upload-complete"
-version.workspace = true
-authors.workspace = true
-license.workspace = true
-edition.workspace = true
-
-[dependencies]
-rivet-operation.workspace = true
-chirp-client.workspace = true
-prost = "0.10"
-
-upload-complete.workspace = true
-
-[dependencies.sqlx]
-workspace = true
-
-[dev-dependencies]
-chirp-worker.workspace = true
-reqwest = "0.11"
-
-faker-user.workspace = true
-upload-get.workspace = true
-upload-prepare.workspace = true
diff --git a/packages/services/user/ops/avatar-upload-complete/README.md b/packages/services/user/ops/avatar-upload-complete/README.md
deleted file mode 100644
index f6968420e8..0000000000
--- a/packages/services/user/ops/avatar-upload-complete/README.md
+++ /dev/null
@@ -1 +0,0 @@
-# user-avatar-upload-complete
diff --git a/packages/services/user/ops/avatar-upload-complete/src/lib.rs b/packages/services/user/ops/avatar-upload-complete/src/lib.rs
deleted file mode 100644
index e2ad1c13fc..0000000000
--- a/packages/services/user/ops/avatar-upload-complete/src/lib.rs
+++ /dev/null
@@ -1,52 +0,0 @@
-use proto::backend::pkg::*;
-use rivet_operation::prelude::*;
-use serde_json::json;
-
-#[operation(name = "user-avatar-upload-complete")]
-async fn handle(
-	ctx: OperationContext<user::avatar_upload_complete::Request>,
-) -> GlobalResult<user::avatar_upload_complete::Response> {
-	let user_id = unwrap_ref!(ctx.user_id).as_uuid();
-	let upload_id = unwrap_ref!(ctx.upload_id).as_uuid();
-
-	op!([ctx] upload_complete {
-		upload_id: ctx.upload_id,
-		bucket: Some("bucket-user-avatar".into()),
-	})
-	.await?;
-
-	// Set avatar id
-	sql_execute!(
-		[ctx]
-		"
-		UPDATE db_user.users set profile_id = $2
-		WHERE user_id = $1
-		",
-		user_id,
-		upload_id,
-	)
-	.await?;
-
-	ctx.cache().purge("user", [user_id]).await?;
-
-	msg!([ctx] user::msg::update(user_id) {
-		user_id: ctx.user_id,
-	})
-	.await?;
-
-	msg!([ctx] analytics::msg::event_create() {
-		events: vec![
-			analytics::msg::event_create::Event {
-				event_id: Some(Uuid::new_v4().into()),
-				name: "user.avatar_set".into(),
-				properties_json: Some(serde_json::to_string(&json!({
-					"user_id": user_id,
-				}))?),
-				..Default::default()
-			}
-		],
-	})
-	.await?;
-
-	Ok(user::avatar_upload_complete::Response {})
-}
diff --git a/packages/services/user/ops/avatar-upload-complete/tests/integration.rs b/packages/services/user/ops/avatar-upload-complete/tests/integration.rs
deleted file mode 100644
index a23d61bab8..0000000000
--- a/packages/services/user/ops/avatar-upload-complete/tests/integration.rs
+++ /dev/null
@@ -1,62 +0,0 @@
-use chirp_worker::prelude::*;
-use proto::backend;
-
-const TEST_BODY: &[u8] = b"test file";
-
-#[worker_test]
-async fn empty(ctx: TestCtx) {
-	let user_res = op!([ctx] faker_user {}).await.unwrap();
-	let user_id = user_res.user_id.unwrap();
-
-	// Create the upload
-	let upload_prepare_res = op!([ctx] upload_prepare {
-		bucket: "bucket-user-avatar".into(),
-		files: vec![
-			backend::upload::PrepareFile {
-				path: "image.png".to_owned(),
-				mime: Some("image/png".into()),
-				content_length: TEST_BODY.len() as u64,
-				..Default::default()
-			},
-		],
-	})
-	.await
-	.unwrap();
-	let upload_id = upload_prepare_res.upload_id.unwrap();
-	let presigned_request = upload_prepare_res.presigned_requests.first().unwrap();
-
-	tracing::info!("writing test files");
-	let res = reqwest::Client::new()
-		.put(&presigned_request.url)
-		.body(TEST_BODY.to_vec())
-		.header("content-type", "image/png")
-		.send()
-		.await
-		.expect("failed to upload");
-	if res.status().is_success() {
-		tracing::info!("uploaded successfully");
-	} else {
-		panic!(
-			"failed to upload ({}): {:?}",
-			res.status(),
-			res.text().await
-		);
-	}
-
-	op!([ctx] user_avatar_upload_complete {
-		user_id: Some(user_id),
-		upload_id: Some(upload_id)
-	})
-	.await
-	.unwrap();
-
-	let uploads_res = op!([ctx] upload_get {
-		upload_ids: vec![upload_id]
-	})
-	.await
-	.unwrap();
-
-	let upload = uploads_res.uploads.first().unwrap();
-
-	assert!(upload.complete_ts.is_some(), "Upload did not complete");
-}
diff --git a/packages/services/user/ops/get/Cargo.toml b/packages/services/user/ops/get/Cargo.toml
deleted file mode 100644
index 0c5903d43e..0000000000
--- a/packages/services/user/ops/get/Cargo.toml
+++ /dev/null
@@ -1,22 +0,0 @@
-[package]
-name = "user-get"
-version.workspace = true
-authors.workspace = true
-license.workspace = true
-edition.workspace = true
-
-[dependencies]
-chirp-client.workspace = true
-prost = "0.10"
-rivet-operation.workspace = true
-
-upload-file-list.workspace = true
-upload-get.workspace = true
-
-[dependencies.sqlx]
-workspace = true
-
-[dev-dependencies]
-chirp-worker.workspace = true
-faker-user.workspace = true
-rand = "0.8"
diff --git a/packages/services/user/ops/get/src/lib.rs b/packages/services/user/ops/get/src/lib.rs
deleted file mode 100644
index 76e8f2579c..0000000000
--- a/packages/services/user/ops/get/src/lib.rs
+++ /dev/null
@@ -1,149 +0,0 @@
-use proto::backend::{self, pkg::*};
-use rivet_operation::prelude::*;
-
-#[derive(sqlx::FromRow)]
-struct UserRow {
-	user_id: Uuid,
-	display_name: String,
-	account_number: i64,
-	avatar_id: String,
-	profile_id: Option<Uuid>,
-	join_ts: i64,
-	bio: String,
-	is_admin: bool,
-	delete_request_ts: Option<i64>,
-	delete_complete_ts: Option<i64>,
-}
-
-impl From<UserRow> for user::get::CacheUser {
-	fn from(val: UserRow) -> Self {
-		Self {
-			user_id: Some(val.user_id.into()),
-			display_name: val.display_name,
-			account_number: val.account_number,
-			avatar_id: val.avatar_id,
-			profile_id: val.profile_id.map(Into::into),
-			join_ts: val.join_ts,
-			bio: val.bio,
-			is_admin: val.is_admin,
-			delete_request_ts: val.delete_request_ts,
-			delete_complete_ts: val.delete_complete_ts,
-		}
-	}
-}
-
-#[operation(name = "user-get")]
-pub async fn handle(
-	ctx: OperationContext<user::get::Request>,
-) -> GlobalResult<user::get::Response> {
-	let user_ids = ctx
-		.user_ids
-		.iter()
-		.map(common::Uuid::as_uuid)
-		.collect::<Vec<_>>();
-
-	let users = ctx
-		.cache()
-		.fetch_all_proto("user", user_ids, {
-			let ctx = ctx.clone();
-			move |mut cache, user_ids| {
-				let ctx = ctx.clone();
-				async move {
-					let users = sql_fetch_all!(
-						[ctx, UserRow]
-						"
-						SELECT
-							user_id,
-							display_name,
-							account_number,
-							avatar_id,
-							profile_id,
-							join_ts,
-							bio,
-							is_admin,
-							delete_request_ts,
-							delete_complete_ts
-						FROM db_user.users
-						WHERE user_id = ANY($1)
-						",
-						user_ids
-					)
-					.await?;
-
-					for row in users {
-						cache.resolve(&row.user_id.clone(), user::get::CacheUser::from(row));
-					}
-
-					Ok(cache)
-				}
-			}
-		})
-		.await?;
-
-	let upload_ids = users
-		.iter()
-		.filter_map(|x| x.profile_id)
-		.collect::<Vec<_>>();
-
-	let (upload_res, files_res) = tokio::try_join!(
-		op!([ctx] upload_get {
-			upload_ids: upload_ids.clone(),
-		}),
-		op!([ctx] upload_file_list {
-			upload_ids: upload_ids.clone(),
-		})
-	)?;
-
-	Ok(user::get::Response {
-		users: users
-			.into_iter()
-			.map(|user| {
-				let profile_id = user.profile_id.map(Into::<common::Uuid>::into);
-
-				// Fetch all information relating to the profile image
-				let (profile_upload_complete_ts, profile_file_name, profile_provider) = {
-					let upload = upload_res
-						.uploads
-						.iter()
-						.find(|upload| upload.upload_id == profile_id);
-					let file = files_res
-						.files
-						.iter()
-						.find(|file| file.upload_id == profile_id);
-
-					if let (Some(upload), Some(file)) = (upload, file) {
-						// TODO: Why do we parse the file name here? Based on route.rs in utils shouldn't
-						// the entire path be present in the media url?
-						let profile_file_name = file
-							.path
-							.rsplit_once('/')
-							.map(|(_, file_name)| file_name.to_owned())
-							.or(Some(file.path.clone()));
-						(upload.complete_ts, profile_file_name, Some(upload.provider))
-					} else {
-						Default::default()
-					}
-				};
-
-				backend::user::User {
-					user_id: user.user_id,
-					display_name: user.display_name,
-					account_number: user.account_number as u32,
-					avatar_id: user.avatar_id,
-					profile_upload_id: if profile_upload_complete_ts.is_some() {
-						profile_id
-					} else {
-						None
-					},
-					profile_file_name,
-					profile_provider,
-					join_ts: user.join_ts,
-					bio: user.bio,
-					is_admin: user.is_admin,
-					delete_request_ts: user.delete_request_ts,
-					delete_complete_ts: user.delete_complete_ts,
-				}
-			})
-			.collect::<Vec<_>>(),
-	})
-}
diff --git a/packages/services/user/ops/get/tests/integration.rs b/packages/services/user/ops/get/tests/integration.rs
deleted file mode 100644
index b21007ef49..0000000000
--- a/packages/services/user/ops/get/tests/integration.rs
+++ /dev/null
@@ -1,71 +0,0 @@
-use chirp_worker::prelude::*;
-use proto::backend::pkg::*;
-use rand::Rng;
-
-#[worker_test]
-async fn empty(ctx: TestCtx) {
-	let res = op!([ctx] user_get {
-		user_ids: Vec::new(),
-	})
-	.await
-	.unwrap();
-	assert!(res.users.is_empty());
-}
-
-#[worker_test]
-async fn fetch(ctx: TestCtx) {
-	struct TestUser {
-		user_id: Option<Uuid>,
-		display_name: String,
-		account_number: i64,
-		bio: String,
-	}
-
-	// Generate test users
-	let mut users = std::iter::repeat_with(|| TestUser {
-		user_id: None,
-		display_name: util::faker::display_name(),
-		account_number: rand::thread_rng().gen_range(1..10000),
-		bio: util::faker::ident(),
-	})
-	.take(8)
-	.collect::<Vec<_>>();
-
-	// Insert test users
-	for user in &mut users {
-		let user_res = op!([ctx] faker_user { }).await.unwrap();
-		let user_id = user_res.user_id.unwrap().as_uuid();
-
-		msg!([ctx] user::msg::profile_set(user_id) -> user::msg::update {
-			user_id: Some(user_id.into()),
-			display_name: Some(user.display_name.clone()),
-			account_number: Some(user.account_number as u32),
-			bio: Some(user.bio.clone()),
-		})
-		.await
-		.unwrap();
-
-		user.user_id = Some(user_id);
-	}
-
-	// Fetch the users
-	let res = op!([ctx] user_get {
-		user_ids: users.iter().map(|u| u.user_id.unwrap().into()).collect(),
-	})
-	.await
-	.unwrap();
-
-	// Validate the users
-	assert_eq!(users.len(), res.users.len());
-	for user in &users {
-		let user_res = res
-			.users
-			.iter()
-			.find(|u| u.user_id.as_ref().unwrap().as_uuid() == user.user_id.unwrap())
-			.expect("user not returned");
-
-		assert_eq!(user.display_name, user_res.display_name);
-		assert_eq!(user.account_number, user_res.account_number as i64);
-		assert_eq!(user.bio, user_res.bio);
-	}
-}
diff --git a/packages/services/user/ops/pending-delete-toggle/Cargo.toml b/packages/services/user/ops/pending-delete-toggle/Cargo.toml
deleted file mode 100644
index 5ca2954acf..0000000000
--- a/packages/services/user/ops/pending-delete-toggle/Cargo.toml
+++ /dev/null
@@ -1,22 +0,0 @@
-[package]
-name = "user-pending-delete-toggle"
-version.workspace = true
-authors.workspace = true
-license.workspace = true
-edition.workspace = true
-
-[dependencies]
-rivet-operation.workspace = true
-chirp-client.workspace = true
-prost = "0.10"
-
-user-identity-get.workspace = true
-
-[dependencies.sqlx]
-workspace = true
-
-[dev-dependencies]
-chirp-worker.workspace = true
-
-faker-user.workspace = true
-user-identity-create.workspace = true
diff --git a/packages/services/user/ops/pending-delete-toggle/src/lib.rs b/packages/services/user/ops/pending-delete-toggle/src/lib.rs
deleted file mode 100644
index 3bb705ce33..0000000000
--- a/packages/services/user/ops/pending-delete-toggle/src/lib.rs
+++ /dev/null
@@ -1,34 +0,0 @@
-use proto::backend::pkg::*;
-use rivet_operation::prelude::*;
-
-#[operation(name = "pending-delete-toggle")]
-async fn handle(
-	ctx: OperationContext<user::pending_delete_toggle::Request>,
-) -> GlobalResult<user::pending_delete_toggle::Response> {
-	let user_id = unwrap_ref!(ctx.user_id).as_uuid();
-
-	// Verify the user is registered
-	let identity = op!([ctx] user_identity_get {
-		user_ids: vec![user_id.into()],
-	})
-	.await?;
-	let identities = &unwrap_ref!(identity.users.first()).identities;
-	ensure_with!(!identities.is_empty(), IDENTITY_NOT_REGISTERED);
-
-	sql_execute!(
-		[ctx]
-		"UPDATE db_user.users SET delete_request_ts = $2 WHERE user_id = $1",
-		user_id,
-		ctx.active.then(util::timestamp::now),
-	)
-	.await?;
-
-	ctx.cache().purge("user", [user_id]).await?;
-
-	msg!([ctx] user::msg::update(user_id) {
-		user_id: ctx.user_id,
-	})
-	.await?;
-
-	Ok(user::pending_delete_toggle::Response {})
-}
diff --git a/packages/services/user/ops/pending-delete-toggle/tests/integration.rs b/packages/services/user/ops/pending-delete-toggle/tests/integration.rs
deleted file mode 100644
index ea3181f459..0000000000
--- a/packages/services/user/ops/pending-delete-toggle/tests/integration.rs
+++ /dev/null
@@ -1,67 +0,0 @@
-use chirp_worker::prelude::*;
-use proto::backend;
-
-#[worker_test]
-async fn empty(ctx: TestCtx) {
-	let user_res = op!([ctx] faker_user {}).await.unwrap();
-	let user_id = user_res.user_id.as_ref().unwrap().as_uuid();
-
-	// Register user
-	let email = util::faker::email();
-	let _res = op!([ctx] user_identity_create {
-		user_id: Some(user_id.into()),
-		identity: Some(backend::user_identity::Identity {
-			kind: Some(backend::user_identity::identity::Kind::Email(
-				backend::user_identity::identity::Email {
-					email: email.clone()
-				}
-			)),
-		}),
-	})
-	.await
-	.unwrap();
-
-	op!([ctx] user_pending_delete_toggle {
-		user_id: Some(user_id.into()),
-		active: true,
-	})
-	.await
-	.unwrap();
-
-	let (delete_request_ts,): (Option<i64>,) = sqlx::query_as(indoc!(
-		"
-		SELECT delete_request_ts
-			FROM db_user.users
-			WHERE
-				user_id = $1
-		",
-	))
-	.bind(user_id)
-	.fetch_one(&ctx.crdb().await.unwrap())
-	.await
-	.unwrap();
-
-	assert!(delete_request_ts.is_some());
-
-	op!([ctx] user_pending_delete_toggle {
-		user_id: Some(user_id.into()),
-		active: false,
-	})
-	.await
-	.unwrap();
-
-	let (delete_request_ts,): (Option<i64>,) = sqlx::query_as(indoc!(
-		"
-		SELECT delete_request_ts
-			FROM db_user.users
-			WHERE
-				user_id = $1
-		",
-	))
-	.bind(user_id)
-	.fetch_one(&ctx.crdb().await.unwrap())
-	.await
-	.unwrap();
-
-	assert!(delete_request_ts.is_none());
-}
diff --git a/packages/services/user/ops/profile-validate/Cargo.toml b/packages/services/user/ops/profile-validate/Cargo.toml
deleted file mode 100644
index 10b62fa785..0000000000
--- a/packages/services/user/ops/profile-validate/Cargo.toml
+++ /dev/null
@@ -1,22 +0,0 @@
-[package]
-name = "user-profile-validate"
-version.workspace = true
-authors.workspace = true
-license.workspace = true
-edition.workspace = true
-
-[dependencies]
-rivet-operation.workspace = true
-chirp-client.workspace = true
-chirp-workflow.workspace = true
-prost = "0.10"
-
-user.workspace = true
-
-[dependencies.sqlx]
-workspace = true
-
-[dev-dependencies]
-chirp-worker.workspace = true
-
-faker-user.workspace = true
diff --git a/packages/services/user/ops/profile-validate/README.md b/packages/services/user/ops/profile-validate/README.md
deleted file mode 100644
index d80d8b58fa..0000000000
--- a/packages/services/user/ops/profile-validate/README.md
+++ /dev/null
@@ -1 +0,0 @@
-# user-profile-validate
diff --git a/packages/services/user/ops/profile-validate/src/lib.rs b/packages/services/user/ops/profile-validate/src/lib.rs
deleted file mode 100644
index f5a8b683d7..0000000000
--- a/packages/services/user/ops/profile-validate/src/lib.rs
+++ /dev/null
@@ -1,99 +0,0 @@
-use proto::{backend::pkg::*, common};
-use rivet_operation::prelude::*;
-
-#[operation(name = "user-profile-validate")]
-async fn handle(
-	ctx: OperationContext<user::profile_validate::Request>,
-) -> GlobalResult<user::profile_validate::Response> {
-	let mut errors = Vec::new();
-
-	// Validate display name
-	if let Some(display_name) = &ctx.display_name {
-		if display_name.is_empty() {
-			errors.push(util::err_path!["display-name", "too-short"]);
-		} else if display_name.len() > util::check::MAX_DISPLAY_NAME_LEN {
-			errors.push(util::err_path!["display-name", "too-long"]);
-		}
-
-		if !util::check::display_name(display_name) {
-			errors.push(util::err_path!["display-name", "invalid"]);
-		}
-	}
-
-	// Validate account number
-	if let Some(account_number) = &ctx.account_number {
-		if *account_number < 1 || *account_number > 9999 {
-			errors.push(util::err_path!["account-number-invalid"]);
-		}
-	}
-
-	// Validate biography
-	if let Some(bio) = &ctx.bio {
-		if bio.len() > util::check::MAX_BIOGRAPHY_LEN {
-			errors.push(util::err_path!["bio", "too-long"]);
-		}
-
-		if !util::check::biography(bio) {
-			errors.push(util::err_path!["bio", "invalid"]);
-		}
-	}
-
-	// Only validate handle uniqueness if at least one of the two handle components is given
-	if ctx.display_name.is_some() || ctx.account_number.is_some() {
-		// If either the display name or account number are missing, fetch them from the given user
-		let (display_name, account_number) =
-			if ctx.display_name.is_none() || ctx.account_number.is_none() {
-				let user_id = unwrap_ref!(ctx.user_id);
-
-				let users_res = chirp_workflow::compat::op(
-					&ctx,
-					::user::ops::get::Input {
-						user_ids: vec![(*user_id).as_uuid()],
-					},
-				)
-				.await?;
-
-				let user = users_res.users.first();
-				let user = unwrap_ref!(user, "user not found");
-
-				(
-					ctx.display_name
-						.clone()
-						.unwrap_or(user.display_name.clone()),
-					ctx.account_number.unwrap_or(user.account_number),
-				)
-			} else {
-				(
-					unwrap_ref!(ctx.display_name).clone(),
-					*unwrap_ref!(ctx.account_number),
-				)
-			};
-
-		// Find user by handle
-		let (user_exists,) = sql_fetch_one!(
-			[ctx, (bool,)]
-			"
-			SELECT EXISTS (
-				SELECT 1
-				FROM db_user.users
-				WHERE display_name = $1 and account_number = $2
-			)
-			",
-			display_name,
-			account_number as i64,
-		)
-		.await?;
-
-		// Validate handle uniqueness
-		if user_exists {
-			errors.push(util::err_path!["handle-not-unique"]);
-		}
-	}
-
-	Ok(user::profile_validate::Response {
-		errors: errors
-			.into_iter()
-			.map(|path| common::ValidationError { path })
-			.collect::<Vec<_>>(),
-	})
-}
diff --git a/packages/services/user/ops/profile-validate/tests/integration.rs b/packages/services/user/ops/profile-validate/tests/integration.rs
deleted file mode 100644
index 7cec9930ce..0000000000
--- a/packages/services/user/ops/profile-validate/tests/integration.rs
+++ /dev/null
@@ -1,18 +0,0 @@
-use chirp_worker::prelude::*;
-
-#[worker_test]
-async fn empty(ctx: TestCtx) {
-	let user_res = op!([ctx] faker_user {}).await.unwrap();
-	let user_id = user_res.user_id.unwrap();
-
-	let res = op!([ctx] user_profile_validate {
-		user_id: Some(user_id),
-		display_name: Some("  bad display name".to_owned()),
-		account_number: Some(10000),
-		bio: Some("bad\n\n\n\n\n\nbio".to_owned())
-	})
-	.await
-	.unwrap();
-
-	assert_eq!(res.errors.len(), 3, "validation failed");
-}
diff --git a/packages/services/user/ops/resolve-email/Cargo.toml b/packages/services/user/ops/resolve-email/Cargo.toml
deleted file mode 100644
index a086ccc5bc..0000000000
--- a/packages/services/user/ops/resolve-email/Cargo.toml
+++ /dev/null
@@ -1,20 +0,0 @@
-[package]
-name = "user-resolve-email"
-version.workspace = true
-authors.workspace = true
-license.workspace = true
-edition.workspace = true
-
-[dependencies]
-rivet-operation.workspace = true
-chirp-client.workspace = true
-prost = "0.10"
-
-[dependencies.sqlx]
-workspace = true
-
-[dev-dependencies]
-chirp-worker.workspace = true
-
-faker-user.workspace = true
-user-identity-create.workspace = true
diff --git a/packages/services/user/ops/resolve-email/README.md b/packages/services/user/ops/resolve-email/README.md
deleted file mode 100644
index 2e13b2fab6..0000000000
--- a/packages/services/user/ops/resolve-email/README.md
+++ /dev/null
@@ -1 +0,0 @@
-# user-resolve-email
diff --git a/packages/services/user/ops/resolve-email/src/lib.rs b/packages/services/user/ops/resolve-email/src/lib.rs
deleted file mode 100644
index 0ab4aac295..0000000000
--- a/packages/services/user/ops/resolve-email/src/lib.rs
+++ /dev/null
@@ -1,32 +0,0 @@
-use proto::backend::pkg::*;
-use rivet_operation::prelude::*;
-
-#[derive(sqlx::FromRow)]
-struct EmailRow {
-	email: String,
-	user_id: Uuid,
-}
-
-#[operation(name = "user-resolve-email")]
-async fn handle(
-	ctx: OperationContext<user::resolve_email::Request>,
-) -> GlobalResult<user::resolve_email::Response> {
-	let users = sql_fetch_all!(
-		[ctx, EmailRow]
-		"
-		SELECT email, user_id
-		FROM db_user_identity.emails
-		WHERE email = ANY($1)
-	",
-		&ctx.emails,
-	)
-	.await?
-	.into_iter()
-	.map(|row| user::resolve_email::response::User {
-		email: row.email,
-		user_id: Some(row.user_id.into()),
-	})
-	.collect::<Vec<_>>();
-
-	Ok(user::resolve_email::Response { users })
-}
diff --git a/packages/services/user/ops/resolve-email/tests/integration.rs b/packages/services/user/ops/resolve-email/tests/integration.rs
deleted file mode 100644
index e481046394..0000000000
--- a/packages/services/user/ops/resolve-email/tests/integration.rs
+++ /dev/null
@@ -1,34 +0,0 @@
-use chirp_worker::prelude::*;
-use proto::backend;
-
-#[worker_test]
-async fn empty(ctx: TestCtx) {
-	let user_res = op!([ctx] faker_user {
-		..Default::default()
-	})
-	.await
-	.unwrap();
-
-	let email = util::faker::email();
-	op!([ctx] user_identity_create {
-		user_id: user_res.user_id,
-		identity: Some(backend::user_identity::Identity {
-			kind: Some(backend::user_identity::identity::Kind::Email(
-				backend::user_identity::identity::Email {
-					email: email.clone()
-				}
-			)),
-		}),
-	})
-	.await
-	.unwrap();
-
-	let res = op!([ctx] user_resolve_email {
-		emails: vec![email.clone(), util::faker::email()],
-	})
-	.await
-	.unwrap();
-	assert_eq!(1, res.users.len());
-	let user = res.users.first().unwrap();
-	assert_eq!(user_res.user_id, user.user_id);
-}
diff --git a/packages/services/user/ops/team-list/Cargo.toml b/packages/services/user/ops/team-list/Cargo.toml
deleted file mode 100644
index 889a99099f..0000000000
--- a/packages/services/user/ops/team-list/Cargo.toml
+++ /dev/null
@@ -1,17 +0,0 @@
-[package]
-name = "user-team-list"
-version.workspace = true
-authors.workspace = true
-license.workspace = true
-edition.workspace = true
-
-[dependencies]
-rivet-operation.workspace = true
-chirp-client.workspace = true
-prost = "0.10"
-
-[dependencies.sqlx]
-workspace = true
-
-[dev-dependencies]
-chirp-worker.workspace = true
diff --git a/packages/services/user/ops/team-list/src/lib.rs b/packages/services/user/ops/team-list/src/lib.rs
deleted file mode 100644
index 2738e6d8b8..0000000000
--- a/packages/services/user/ops/team-list/src/lib.rs
+++ /dev/null
@@ -1,55 +0,0 @@
-use proto::backend::pkg::*;
-use rivet_operation::prelude::*;
-
-#[operation(name = "user-team-list")]
-async fn handle(
-	ctx: OperationContext<user::team_list::Request>,
-) -> GlobalResult<user::team_list::Response> {
-	let user_ids = ctx
-		.user_ids
-		.iter()
-		.map(common::Uuid::as_uuid)
-		.collect::<Vec<_>>();
-
-	let users = ctx
-		.cache()
-		.fetch_all_proto("user_team_list", user_ids, {
-			let ctx = ctx.clone();
-			move |mut cache, user_ids| {
-				let ctx = ctx.clone();
-				async move {
-					let team_members = sql_fetch_all!(
-						[ctx, (Uuid, Uuid)]
-						"
-					SELECT user_id, team_id
-					FROM db_team.team_members
-					WHERE user_id = ANY($1)
-					",
-						&user_ids,
-					)
-					.await?;
-
-					for user_id in user_ids {
-						// Aggregate user teams
-						let user_teams = user::team_list::response::UserTeams {
-							user_id: Some(user_id.into()),
-							teams: team_members
-								.iter()
-								.filter(|(team_user_id, _)| *team_user_id == user_id)
-								.map(|(_, team_id)| user::team_list::response::TeamMember {
-									team_id: Some((*team_id).into()),
-								})
-								.collect(),
-						};
-
-						cache.resolve(&user_id.clone(), user_teams);
-					}
-
-					Ok(cache)
-				}
-			}
-		})
-		.await?;
-
-	Ok(user::team_list::Response { users })
-}
diff --git a/packages/services/user/ops/team-list/tests/integration.rs b/packages/services/user/ops/team-list/tests/integration.rs
deleted file mode 100644
index 029a2f7831..0000000000
--- a/packages/services/user/ops/team-list/tests/integration.rs
+++ /dev/null
@@ -1,48 +0,0 @@
-use std::collections::HashMap;
-
-use chirp_worker::prelude::*;
-use proto::backend::pkg::*;
-
-#[worker_test]
-async fn empty(ctx: TestCtx) {
-	let user_a = Uuid::new_v4();
-	let user_b = Uuid::new_v4();
-	let user_c = Uuid::new_v4();
-
-	let team_a = Uuid::new_v4();
-	let team_b = Uuid::new_v4();
-	let team_c = Uuid::new_v4();
-
-	let members = vec![
-		(user_a, team_a),
-		(user_a, team_b),
-		(user_b, team_a),
-		(user_b, team_b),
-		(user_b, team_c),
-	];
-	for (user_id, team_id) in &members {
-		msg!([ctx] team::msg::member_create(team_id, user_id) -> team::msg::member_create_complete {
-			team_id: Some((*team_id).into()),
-			user_id: Some((*user_id).into()),
-			invitation: None,
-		})
-		.await
-		.unwrap();
-	}
-
-	let res = op!([ctx] user_team_list {
-		user_ids: vec![user_a.into(), user_b.into(), user_c.into()],
-	})
-	.await
-	.unwrap();
-
-	assert_eq!(3, res.users.len());
-	let users_map = res
-		.users
-		.iter()
-		.map(|u| (u.user_id.unwrap().as_uuid(), u.teams.len()))
-		.collect::<HashMap<Uuid, usize>>();
-	assert_eq!(2, *users_map.get(&user_a).unwrap());
-	assert_eq!(3, *users_map.get(&user_b).unwrap());
-	assert_eq!(0, *users_map.get(&user_c).unwrap());
-}
diff --git a/packages/services/user/ops/token-create/Cargo.toml b/packages/services/user/ops/token-create/Cargo.toml
deleted file mode 100644
index db684ed912..0000000000
--- a/packages/services/user/ops/token-create/Cargo.toml
+++ /dev/null
@@ -1,21 +0,0 @@
-[package]
-name = "user-token-create"
-version.workspace = true
-authors.workspace = true
-license.workspace = true
-edition.workspace = true
-
-[dependencies]
-rivet-operation.workspace = true
-chirp-client.workspace = true
-prost = "0.10"
-
-token-create.workspace = true
-
-[dependencies.sqlx]
-workspace = true
-
-[dev-dependencies]
-chirp-worker.workspace = true
-
-faker-user.workspace = true
diff --git a/packages/services/user/ops/token-create/README.md b/packages/services/user/ops/token-create/README.md
deleted file mode 100644
index dfb884aad3..0000000000
--- a/packages/services/user/ops/token-create/README.md
+++ /dev/null
@@ -1,6 +0,0 @@
-# user-token-create
-
-Creates a new token and refresh token for a given user.
-
-Only use this service when initiating a session with a user for the first time. You should always use the
-client's refresh token whenever possible.
diff --git a/packages/services/user/ops/token-create/src/lib.rs b/packages/services/user/ops/token-create/src/lib.rs
deleted file mode 100644
index 5edac2e59a..0000000000
--- a/packages/services/user/ops/token-create/src/lib.rs
+++ /dev/null
@@ -1,53 +0,0 @@
-use proto::backend::pkg::*;
-use rivet_operation::prelude::*;
-
-// Also see api-auth/src/route/tokens.rs
-pub const TOKEN_TTL: i64 = util::duration::minutes(15);
-pub const REFRESH_TOKEN_TTL: i64 = util::duration::days(90);
-
-#[operation(name = "user-token-create")]
-async fn handle(
-	ctx: OperationContext<user::token_create::Request>,
-) -> GlobalResult<user::token_create::Response> {
-	let user_id = unwrap_ref!(ctx.user_id).as_uuid();
-
-	let token_res = op!([ctx] token_create {
-		token_config: Some(token::create::request::TokenConfig {
-			ttl: TOKEN_TTL,
-		}),
-		refresh_token_config: Some(token::create::request::TokenConfig {
-			ttl: REFRESH_TOKEN_TTL,
-		}),
-		issuer: Self::NAME.to_owned(),
-		client: ctx.client.clone(),
-		kind: Some(token::create::request::Kind::New(
-			token::create::request::KindNew {
-				entitlements: vec![proto::claims::Entitlement {
-					kind: Some(proto::claims::entitlement::Kind::User(proto::claims::entitlement::User {
-						user_id: Some(user_id.into()),
-					})),
-				}],
-			},
-		)),
-		label: Some("usr".into()),
-		..Default::default()
-	})
-	.await?;
-
-	let token = unwrap_ref!(token_res.token);
-	let refresh_token = unwrap_ref!(token_res.refresh_token);
-	let token_session_id = unwrap_ref!(token_res.session_id).as_uuid();
-
-	sql_execute!(
-		[ctx]
-		"INSERT INTO db_user.user_tokens (user_id, token_session_id) VALUES ($1, $2)",
-		user_id,
-		token_session_id,
-	)
-	.await?;
-
-	Ok(user::token_create::Response {
-		token: token.token.clone(),
-		refresh_token: refresh_token.token.clone(),
-	})
-}
diff --git a/packages/services/user/ops/token-create/tests/integration.rs b/packages/services/user/ops/token-create/tests/integration.rs
deleted file mode 100644
index a148e36cd3..0000000000
--- a/packages/services/user/ops/token-create/tests/integration.rs
+++ /dev/null
@@ -1,17 +0,0 @@
-use chirp_worker::prelude::*;
-use proto::backend;
-
-#[worker_test]
-async fn empty(ctx: TestCtx) {
-	let user_res = op!([ctx] faker_user {}).await.unwrap();
-
-	let res = op!([ctx] user_token_create {
-		user_id: user_res.user_id,
-		client: Some(backend::net::ClientInfo {..Default::default()})
-	})
-	.await
-	.unwrap();
-
-	assert!(res.token.starts_with("usr"));
-	assert!(res.refresh_token.starts_with("usr_rf"));
-}
diff --git a/packages/services/user/standalone/delete-pending/src/lib.rs b/packages/services/user/standalone/delete-pending/src/lib.rs
index c6074e2474..107ad03a92 100644
--- a/packages/services/user/standalone/delete-pending/src/lib.rs
+++ b/packages/services/user/standalone/delete-pending/src/lib.rs
@@ -45,10 +45,10 @@ pub async fn run_from_env(
 			let ctx = ctx.clone();
 			async move {
 				let mut sub = ctx.subscribe::<
-					::user::workflows::user::DeleteComplete
+					user::workflows::user::DeleteComplete
 				>(("user_id", user_id)).await?;
 
-				ctx.signal(::user::workflows::user::Delete {})
+				let _ = ctx.signal(user::workflows::user::Delete {})
 					.tag("user_id", user_id)
 					.send();
 				
diff --git a/packages/services/user/tests/avatar_upload_complete.rs b/packages/services/user/tests/avatar_upload_complete.rs
index 92724e3e57..71d23decd0 100644
--- a/packages/services/user/tests/avatar_upload_complete.rs
+++ b/packages/services/user/tests/avatar_upload_complete.rs
@@ -43,7 +43,7 @@ async fn empty(ctx: TestCtx) {
 		);
 	}
 
-	ctx.op(::user::ops::avatar_upload_complete::Input {
+	ctx.op(user::ops::avatar_upload_complete::Input {
 		user_id,
 		upload_id: upload_id.as_uuid()
 	})
diff --git a/packages/services/user/tests/get.rs b/packages/services/user/tests/get.rs
index f43293a41f..78851c0d70 100644
--- a/packages/services/user/tests/get.rs
+++ b/packages/services/user/tests/get.rs
@@ -3,7 +3,7 @@ use rand::Rng;
 
 #[workflow_test]
 async fn empty(ctx: TestCtx) {
-	let res = ctx.op(::user::ops::get::Input {
+	let res = ctx.op(user::ops::get::Input {
 		user_ids: Vec::new(),
 	})
 	.await
@@ -35,11 +35,11 @@ async fn fetch(ctx: TestCtx) {
 		let user_res = ctx.op(faker::ops::user::Input {}).await.unwrap();
 		let user_id = user_res.user_id;
 
-		let mut update_sub = ctx.subscribe::<::user::workflows::user::Update>(
+		let mut update_sub = ctx.subscribe::<user::workflows::user::Update>(
 			("user_id", user_id)
 		).await.unwrap();
 
-		ctx.signal(::user::workflows::user::ProfileSet {
+		ctx.signal(user::workflows::user::ProfileSet {
 			display_name: Some(user.display_name.clone()),
 			account_number: Some(user.account_number as u32),
 			bio: Some(user.bio.clone()),
@@ -54,7 +54,7 @@ async fn fetch(ctx: TestCtx) {
 	}
 
 	// Fetch the users
-	let res = ctx.op(::user::ops::get::Input {
+	let res = ctx.op(user::ops::get::Input {
 		user_ids: users.iter().map(|u| u.user_id.unwrap()).collect(),
 	})
 	.await
diff --git a/packages/services/user/tests/identity_create.rs b/packages/services/user/tests/identity_create.rs
index 80bbad2aa6..993784e6fb 100644
--- a/packages/services/user/tests/identity_create.rs
+++ b/packages/services/user/tests/identity_create.rs
@@ -7,7 +7,7 @@ async fn email(ctx: TestCtx) {
 	let user_id = user_res.user_id;
 
 	let email = util::faker::email();
-	ctx.op(::user::ops::identity::create::Input {
+	ctx.op(user::ops::identity::create::Input {
 		user_id,
 		identity: backend::user_identity::Identity {
 			kind: Some(backend::user_identity::identity::Kind::Email(
diff --git a/packages/services/user/tests/identity_delete.rs b/packages/services/user/tests/identity_delete.rs
index 06dbaaca67..ce23e05e21 100644
--- a/packages/services/user/tests/identity_delete.rs
+++ b/packages/services/user/tests/identity_delete.rs
@@ -7,7 +7,7 @@ async fn empty(ctx: TestCtx) {
 	let user_id = user_res.user_id;
 
 	let email = util::faker::email();
-    ctx.op(::user::ops::identity::create::Input {
+    ctx.op(user::ops::identity::create::Input {
 		user_id,
 		identity: backend::user_identity::Identity {
 			kind: Some(backend::user_identity::identity::Kind::Email(
@@ -20,7 +20,7 @@ async fn empty(ctx: TestCtx) {
 	.await
 	.unwrap();
 
-    ctx.op(::user::ops::identity::delete::Input {
+    ctx.op(user::ops::identity::delete::Input {
 		user_ids: vec![user_id],
 	})
 	.await
diff --git a/packages/services/user/tests/identity_get.rs b/packages/services/user/tests/identity_get.rs
index 8c3af23ace..39bc7eee10 100644
--- a/packages/services/user/tests/identity_get.rs
+++ b/packages/services/user/tests/identity_get.rs
@@ -7,7 +7,7 @@ async fn empty(ctx: TestCtx) {
 	let user_id = user_res.user_id;
 
 	let email = util::faker::email();
-    ctx.op(::user::ops::identity::create::Input {
+    ctx.op(user::ops::identity::create::Input {
 		user_id,
 		identity: backend::user_identity::Identity {
 			kind: Some(backend::user_identity::identity::Kind::Email(
@@ -20,7 +20,7 @@ async fn empty(ctx: TestCtx) {
 	.await
 	.unwrap();
 
-	let res = ctx.op(::user::ops::identity::get::Input {
+	let res = ctx.op(user::ops::identity::get::Input {
 		user_ids: vec![user_id, Uuid::new_v4()],
 	})
 	.await
diff --git a/packages/services/user/tests/pending_delete_toggle.rs b/packages/services/user/tests/pending_delete_toggle.rs
index 78ba6a2a53..8e03b77995 100644
--- a/packages/services/user/tests/pending_delete_toggle.rs
+++ b/packages/services/user/tests/pending_delete_toggle.rs
@@ -8,7 +8,7 @@ async fn empty(ctx: TestCtx) {
 
 	// Register user
 	let email = util::faker::email();
-	let _res = ctx.op(::user::ops::identity::create::Input {
+	let _res = ctx.op(user::ops::identity::create::Input {
 		user_id,
 		identity: backend::user_identity::Identity {
 			kind: Some(backend::user_identity::identity::Kind::Email(
@@ -21,7 +21,7 @@ async fn empty(ctx: TestCtx) {
 	.await
 	.unwrap();
 
-	ctx.op(::user::ops::pending_delete_toggle::Input {
+	ctx.op(user::ops::pending_delete_toggle::Input {
 		user_id,
 		active: true,
 	})
@@ -43,7 +43,7 @@ async fn empty(ctx: TestCtx) {
 
 	assert!(delete_request_ts.is_some());
 
-	ctx.op(::user::ops::pending_delete_toggle::Input {
+	ctx.op(user::ops::pending_delete_toggle::Input {
 		user_id,
 		active: false,
 	})
diff --git a/packages/services/user/tests/profile_validate.rs b/packages/services/user/tests/profile_validate.rs
index 226c9c7d8a..665d7fffce 100644
--- a/packages/services/user/tests/profile_validate.rs
+++ b/packages/services/user/tests/profile_validate.rs
@@ -5,7 +5,7 @@ async fn empty(ctx: TestCtx) {
 	let user_res = ctx.op(faker::ops::user::Input {}).await.unwrap();
 	let user_id = user_res.user_id;
 
-	let res = ctx.op(::user::ops::profile_validate::Input {
+	let res = ctx.op(user::ops::profile_validate::Input {
 		user_id,
 		display_name: Some("  bad display name".to_owned()),
 		account_number: Some(10000),
diff --git a/packages/services/user/tests/resolve_email.rs b/packages/services/user/tests/resolve_email.rs
index 38d45761ff..94a9e29373 100644
--- a/packages/services/user/tests/resolve_email.rs
+++ b/packages/services/user/tests/resolve_email.rs
@@ -7,7 +7,7 @@ async fn empty(ctx: TestCtx) {
 	let user_id = user_res.user_id;
 
 	let email = util::faker::email();
-	ctx.op(::user::ops::identity::create::Input {
+	ctx.op(user::ops::identity::create::Input {
 		user_id,
 		identity: backend::user_identity::Identity {
 			kind: Some(backend::user_identity::identity::Kind::Email(
@@ -20,7 +20,7 @@ async fn empty(ctx: TestCtx) {
 	.await
 	.unwrap();
 
-	let res = ctx.op(::user::ops::resolve_email::Input {
+	let res = ctx.op(user::ops::resolve_email::Input {
 		emails: vec![email.clone(), util::faker::email()],
 	})
 	.await
diff --git a/packages/services/user/tests/team_list.rs b/packages/services/user/tests/team_list.rs
index 00b18e682f..2db416a74e 100644
--- a/packages/services/user/tests/team_list.rs
+++ b/packages/services/user/tests/team_list.rs
@@ -31,7 +31,7 @@ async fn empty(ctx: TestCtx) {
 		.unwrap();
 	}
 
-	let res = ctx.op(::user::ops::team_list::Input {
+	let res = ctx.op(user::ops::team_list::Input {
 		user_ids: vec![user_a, user_b, user_c],
 	})
 	.await
diff --git a/packages/services/user/tests/token_create.rs b/packages/services/user/tests/token_create.rs
index 8c6f26d175..8bd4340df1 100644
--- a/packages/services/user/tests/token_create.rs
+++ b/packages/services/user/tests/token_create.rs
@@ -6,7 +6,7 @@ async fn empty(ctx: TestCtx) {
 	let user_res = ctx.op(faker::ops::user::Input {}).await.unwrap();
 	let user_id = user_res.user_id;
 
-	let res = ctx.op(::user::ops::token_create::Input {
+	let res = ctx.op(user::ops::token_create::Input {
 		user_id,
 		client: backend::net::ClientInfo::default()
 	})
diff --git a/packages/services/user/worker/Cargo.toml b/packages/services/user/worker/Cargo.toml
index d46c5d5b7c..8d528492d8 100644
--- a/packages/services/user/worker/Cargo.toml
+++ b/packages/services/user/worker/Cargo.toml
@@ -26,6 +26,5 @@ rivet-config.workspace = true
 [dev-dependencies]
 chirp-worker.workspace = true
 
-faker-user.workspace = true
 upload-get.workspace = true
 upload-prepare.workspace = true
diff --git a/packages/services/user/worker/src/lib.rs b/packages/services/user/worker/src/lib.rs
deleted file mode 100644
index 3719b10aa8..0000000000
--- a/packages/services/user/worker/src/lib.rs
+++ /dev/null
@@ -1 +0,0 @@
-pub mod workers;
diff --git a/packages/services/user/worker/src/workers/admin_set.rs b/packages/services/user/worker/src/workers/admin_set.rs
deleted file mode 100644
index 35c05a64e7..0000000000
--- a/packages/services/user/worker/src/workers/admin_set.rs
+++ /dev/null
@@ -1,28 +0,0 @@
-use chirp_worker::prelude::*;
-use proto::backend::pkg::*;
-
-#[worker(name = "user-admin-set")]
-async fn worker(ctx: &OperationContext<user::msg::admin_set::Message>) -> GlobalResult<()> {
-	let user_id = unwrap!(ctx.user_id);
-
-	// TODO: Don't run if already admin
-
-	sql_execute!(
-		[ctx]
-		"
-		UPDATE db_user.users
-		SET
-			is_admin = true
-		WHERE user_id = $1
-		",
-		*user_id,
-	)
-	.await?;
-
-	msg!([ctx] user::msg::update(user_id) {
-		user_id: Some(user_id),
-	})
-	.await?;
-
-	Ok(())
-}
diff --git a/packages/services/user/worker/src/workers/create.rs b/packages/services/user/worker/src/workers/create.rs
deleted file mode 100644
index fd9de00ae2..0000000000
--- a/packages/services/user/worker/src/workers/create.rs
+++ /dev/null
@@ -1,160 +0,0 @@
-use chirp_worker::prelude::*;
-use lazy_static::lazy_static;
-use proto::backend::pkg::*;
-use rand::{seq::IteratorRandom, Rng};
-use serde_json::json;
-
-lazy_static! {
-	// Load adjectives from file
-	static ref ADJECTIVES: Vec<&'static str> = include_str!("../../adjectives.txt")
-		.split('\n')
-		.filter(|l| !l.is_empty())
-		.map(|l| l.trim())
-		.collect();
-}
-
-#[worker(name = "user-create")]
-async fn worker(ctx: &OperationContext<user::msg::create::Message>) -> GlobalResult<()> {
-	let user_id = unwrap_ref!(ctx.user_id).as_uuid();
-
-	let join_ts = ctx.ts();
-
-	// Attempt to create a unique handle 3 times
-	let mut attempts = 3u32;
-	let (display_name, _account_number) = loop {
-		if attempts == 0 {
-			bail!("failed all attempts to create unique user handle");
-		}
-		attempts -= 1;
-
-		let display_name = if let Some(display_name) = ctx.display_name.clone() {
-			display_name
-		} else {
-			gen_display_name("Guest")
-		};
-
-		if let Some(x) = insert_user(ctx, user_id, display_name.clone(), None, join_ts).await? {
-			break x;
-		}
-	};
-
-	msg!([ctx] user::msg::create_complete(user_id) {
-		user_id: ctx.user_id,
-	})
-	.await?;
-
-	let properties_json = Some(serde_json::to_string(&json!({
-		"user_id": user_id,
-		"display_name": display_name,
-	}))?);
-
-	msg!([ctx] analytics::msg::event_create() {
-		events: vec![
-			analytics::msg::event_create::Event {
-				event_id: Some(Uuid::new_v4().into()),
-				name: "user.create".into(),
-				properties_json: properties_json.clone(),
-				..Default::default()
-			},
-			analytics::msg::event_create::Event {
-				event_id: Some(Uuid::new_v4().into()),
-				name: "user.profile_set".into(),
-				properties_json,
-				..Default::default()
-			},
-		],
-	})
-	.await?;
-
-	Ok(())
-}
-
-// Handles unique constraint violations
-async fn insert_user(
-	ctx: &OperationContext<user::msg::create::Message>,
-	user_id: Uuid,
-	display_name: String,
-	avatar_upload_id: Option<Uuid>,
-	join_ts: i64,
-) -> GlobalResult<Option<(String, i64)>> {
-	let account_number = gen_account_number();
-	tracing::debug!(%display_name, %account_number, "insert user attempt");
-
-	let res = if let Some(avatar_upload_id) = avatar_upload_id {
-		sql_execute!(
-			[ctx]
-			"
-			INSERT INTO db_user.users (
-				user_id,
-				display_name,
-				account_number,
-				avatar_id,
-				profile_id,
-				join_ts
-			)
-			VALUES ($1, $2, $3, $4, $5, $6)
-			ON CONFLICT (display_name, account_number) DO NOTHING
-			",
-			user_id,
-			&display_name,
-			account_number,
-			gen_avatar_id(),
-			avatar_upload_id,
-			join_ts,
-		)
-		.await?
-	} else {
-		sql_execute!(
-			[ctx]
-			"
-			INSERT INTO db_user.users (
-				user_id,
-				display_name,
-				account_number,
-				avatar_id,
-				join_ts
-			)
-			VALUES ($1, $2, $3, $4, $5)
-			ON CONFLICT (display_name, account_number) DO NOTHING
-			",
-			user_id,
-			&display_name,
-			gen_account_number(),
-			gen_avatar_id(),
-			join_ts,
-		)
-		.await?
-	};
-
-	if res.rows_affected() == 1 {
-		Ok(Some((display_name, account_number)))
-	} else {
-		Ok(None)
-	}
-}
-
-// Generates a display name with the format `{adjective:7}{space:1}{base:11}{space:1}{number:4}`
-fn gen_display_name(base: impl std::fmt::Display) -> String {
-	let base_str = format!("{}", base);
-
-	let mut rand = rand::thread_rng();
-	let adj = ADJECTIVES.iter().choose(&mut rand).unwrap_or(&"Unknown");
-
-	format!(
-		"{} {} {}",
-		adj,
-		base_str,
-		std::iter::repeat_with(|| rand.gen_range(0..10))
-			.map(|d| d.to_string())
-			.take(4)
-			.collect::<String>()
-	)
-}
-
-fn gen_account_number() -> i64 {
-	rand::thread_rng().gen_range(1..10000)
-}
-
-fn gen_avatar_id() -> String {
-	format!("avatar-{}", rand::thread_rng().gen_range(0..7))
-}
diff --git a/packages/services/user/worker/src/workers/delete.rs b/packages/services/user/worker/src/workers/delete.rs
deleted file mode 100644
index eec89d14ef..0000000000
--- a/packages/services/user/worker/src/workers/delete.rs
+++ /dev/null
@@ -1,167 +0,0 @@
-use chirp_worker::prelude::*;
-use futures_util::{StreamExt, TryStreamExt};
-use proto::backend::pkg::*;
-use rand::Rng;
-use serde_json::json;
-
-const MESSAGE_BATCH_SIZE: usize = 256;
-const UPLOAD_BATCH_SIZE: usize = 256;
-
-#[worker(name = "user-delete")]
-async fn worker(ctx: &OperationContext<user::msg::delete::Message>) -> GlobalResult<()> {
-	let user_id = unwrap_ref!(ctx.user_id).as_uuid();
-
-	// Delete user identities
-	{
-		chirp_workflow::compat::op(
-			&ctx,
-			::user::ops::identity::delete::Input {
-				user_ids: vec![user_id]
-			}
-		)
-		.await?;
-	}
-
-	// Remove uploads
-	{
-		tracing::info!(?user_id, "removing uploads");
-		let mut last_create_ts = 0;
-
-		loop {
-			let uploads_res = op!([ctx] upload_list_for_user {
-				user_ids: vec![user_id.into()],
-				anchor: Some(last_create_ts),
-				limit: UPLOAD_BATCH_SIZE as u32,
-			})
-			.await?;
-			let user = unwrap!(uploads_res.users.first());
-
-			let request_id = Uuid::new_v4();
-			msg!([ctx] upload::msg::delete(request_id) -> upload::msg::delete_complete {
-				request_id: Some(request_id.into()),
-				upload_ids: user.upload_ids.clone(),
-			})
-			.await?;
-
-			// Update last timestamp
-			if let Some(anchor) = user.anchor {
-				last_create_ts = anchor;
-			}
-
-			if user.upload_ids.len() < UPLOAD_BATCH_SIZE {
-				break;
-			}
-		}
-	}
-
-	// Remove from teams
-	{
-		tracing::info!(?user_id, "removing teams");
-
-		let user_teams_res = chirp_workflow::compat::op(
-			&ctx,
-			::user::ops::team_list::Input {
-				user_ids: vec![user_id.into()],
-			},
-		)
-		.await?;
-		let user_teams = unwrap!(user_teams_res.users.first());
-
-		let teams_res = op!([ctx] team_get {
-			team_ids: user_teams.teams
-				.iter()
-				.map(|member| Ok(member.team_id.into()))
-				.collect::<GlobalResult<Vec<_>>>()?
-		})
-		.await?;
-
-		// Filter out teams where the user is the owner
-		let non_owner_teams = teams_res
-			.teams
-			.clone()
-			.into_iter()
-			.filter(|team| team.owner_user_id != ctx.user_id);
-		futures_util::stream::iter(non_owner_teams)
-			.map(|team| {
-				let team_id_proto = team.team_id;
-
-				async move {
-					let team_id = unwrap!(team_id_proto).as_uuid();
-
-					msg!([ctx] team::msg::member_remove(team_id, user_id) -> team::msg::member_remove_complete {
-						user_id: ctx.user_id,
-						team_id: team_id_proto,
-						silent: false,
-					})
-					.await
-					.map_err(Into::<GlobalError>::into)
-				}
-			})
-			.buffer_unordered(32)
-			.try_collect::<Vec<_>>()
-			.await?;
-	}
-
-	// Redact user record
-	{
-		tracing::info!(?user_id, "removing user record");
-
-		sql_execute!(
-			[ctx]
-			"
-			UPDATE db_user.users
-			SET
-				display_name = $2,
-				profile_id = NULL,
-				bio = '',
-				delete_complete_ts = $3
-			WHERE user_id = $1
-			",
-			user_id,
-			gen_display_name(),
-			util::timestamp::now(),
-		)
-		.await?;
-
-		ctx.cache().purge("user", [user_id]).await?;
-	}
-
-	msg!([ctx] user::msg::delete_complete(user_id) {
-		user_id: ctx.user_id,
-	})
-	.await?;
-
-	msg!([ctx] user::msg::update(user_id) {
-		user_id: ctx.user_id,
-	})
-	.await?;
-
-	msg!([ctx] analytics::msg::event_create() {
-		events: vec![
-			analytics::msg::event_create::Event {
-				event_id: Some(Uuid::new_v4().into()),
-				name: "user.delete".into(),
-				properties_json: Some(serde_json::to_string(&json!({
-					"deleted_user_id": user_id
-				}))?),
-				..Default::default()
-			}
-		],
-	})
-	.await?;
-
-	tracing::info!(?user_id, "complete");
-
-	Ok(())
-}
-
-fn gen_display_name() -> String {
-	format!(
-		"Deleted User {}",
-		rand::thread_rng()
-			.sample_iter(rand::distributions::Alphanumeric)
-			.map(char::from)
-			.take(10)
-			.collect::<String>()
-	)
-}
diff --git a/packages/services/user/worker/src/workers/event_party_member_update.rs b/packages/services/user/worker/src/workers/event_party_member_update.rs
deleted file mode 100644
index 86d49805c8..0000000000
--- a/packages/services/user/worker/src/workers/event_party_member_update.rs
+++ /dev/null
@@ -1,17 +0,0 @@
-use chirp_worker::prelude::*;
-use proto::backend::{self, pkg::*};
-
-#[worker(name = "user-event-party-member-update")]
-async fn worker(ctx: &OperationContext<party::msg::member_update::Message>) -> GlobalResult<()> {
-	let user_id = unwrap_ref!(ctx.user_id).as_uuid();
-
-	msg!([ctx] user::msg::event(user_id) {
-		user_id: Some(user_id.into()),
-		event: Some(backend::user::event::Event {
-			kind: Some(backend::user::event::event::Kind::PartyUpdate(backend::user::event::PartyUpdate {})),
-		}),
-	})
-	.await?;
-
-	Ok(())
-}
diff --git a/packages/services/user/worker/src/workers/event_party_update.rs b/packages/services/user/worker/src/workers/event_party_update.rs
deleted file mode 100644
index 2aa2d43b9c..0000000000
--- a/packages/services/user/worker/src/workers/event_party_update.rs
+++ /dev/null
@@ -1,25 +0,0 @@
-use chirp_worker::prelude::*;
-use proto::backend::{self, pkg::*};
-
-#[worker(name = "user-event-party-update")]
-async fn worker(ctx: &OperationContext<party::msg::update::Message>) -> GlobalResult<()> {
-	let party_id = unwrap_ref!(ctx.party_id).as_uuid();
-
-	let member_list = op!([ctx] party_member_list {
-		party_ids: vec![party_id.into()],
-	})
-	.await?;
-	let party = unwrap!(member_list.parties.first());
-
-	for user_id in &party.user_ids {
-		msg!([ctx] user::msg::event(user_id) {
-			user_id: Some(*user_id),
-			event: Some(backend::user::event::Event {
-				kind: Some(backend::user::event::event::Kind::PartyUpdate(backend::user::event::PartyUpdate {})),
-			}),
-		})
-		.await?;
-	}
-
-	Ok(())
-}
diff --git a/packages/services/user/worker/src/workers/event_team_member_remove.rs b/packages/services/user/worker/src/workers/event_team_member_remove.rs
deleted file mode 100644
index 44ae7a96db..0000000000
--- a/packages/services/user/worker/src/workers/event_team_member_remove.rs
+++ /dev/null
@@ -1,19 +0,0 @@
-use chirp_worker::prelude::*;
-use proto::backend::{self, pkg::*};
-
-#[worker(name = "user-event-team-member-remove")]
-async fn worker(ctx: &OperationContext<team::msg::member_remove::Message>) -> GlobalResult<()> {
-	let user_id = unwrap_ref!(ctx.user_id);
-
-	msg!([ctx] user::msg::event(user_id) {
-		user_id: ctx.user_id,
-		event: Some(backend::user::event::Event {
-			kind: Some(backend::user::event::event::Kind::TeamMemberRemove(backend::user::event::TeamMemberRemove {
-				team_id: ctx.team_id,
-			})),
-		}),
-	})
-	.await?;
-
-	Ok(())
-}
diff --git a/packages/services/user/worker/src/workers/event_user_update.rs b/packages/services/user/worker/src/workers/event_user_update.rs
deleted file mode 100644
index a85d687ff4..0000000000
--- a/packages/services/user/worker/src/workers/event_user_update.rs
+++ /dev/null
@@ -1,18 +0,0 @@
-use chirp_worker::prelude::*;
-use proto::backend::{self, pkg::*};
-
-#[worker(name = "user-event-user-update")]
-async fn worker(ctx: &OperationContext<user::msg::update::Message>) -> GlobalResult<()> {
-	let user_id = unwrap_ref!(ctx.user_id);
-
-	msg!([ctx] user::msg::event(user_id) {
-		user_id: ctx.user_id,
-		event: Some(backend::user::event::Event {
-			kind: Some(backend::user::event::event::Kind::UserUpdate(backend::user::event::UserUpdate {
-			})),
-		}),
-	})
-	.await?;
-
-	Ok(())
-}
diff --git a/packages/services/user/worker/src/workers/game_update.rs b/packages/services/user/worker/src/workers/game_update.rs
deleted file mode 100644
index 7230f76f6d..0000000000
--- a/packages/services/user/worker/src/workers/game_update.rs
+++ /dev/null
@@ -1,48 +0,0 @@
-use chirp_worker::prelude::*;
-use futures_util::{
-	stream::{StreamExt, TryStreamExt},
-	FutureExt,
-};
-use proto::backend::pkg::*;
-
-#[worker(name = "user-dev-game-update")]
-async fn worker(ctx: &OperationContext<game::msg::update::Message>) -> GlobalResult<()> {
-	let game_id = unwrap_ref!(ctx.game_id).as_uuid();
-
-	let game_res = op!([ctx] game_get {
-		game_ids: vec![game_id.into()],
-	})
-	.await?;
-	let game = unwrap!(game_res.games.first());
-	let developer_team_id = unwrap_ref!(game.developer_team_id);
-
-	let members_res = op!([ctx] team_member_list {
-		team_ids: vec![*developer_team_id],
-		limit: None,
-		anchor: None,
-	})
-	.await?;
-	let team = unwrap!(members_res.teams.first());
-
-	// Insert event for each team member
-	let mut events = Vec::new();
-	for member in &team.members {
-		let user_id = unwrap_ref!(member.user_id).as_uuid();
-
-		events.push(
-			msg!([ctx] user::msg::game_update(user_id) {
-				user_id: member.user_id,
-				game_id: ctx.game_id,
-			})
-			.boxed(),
-		);
-	}
-
-	// Dispatch events
-	futures_util::stream::iter(events)
-		.buffer_unordered(32)
-		.try_collect::<Vec<_>>()
-		.await?;
-
-	Ok(())
-}
diff --git a/packages/services/user/worker/src/workers/mod.rs b/packages/services/user/worker/src/workers/mod.rs
deleted file mode 100644
index 3da2c902e1..0000000000
--- a/packages/services/user/worker/src/workers/mod.rs
+++ /dev/null
@@ -1,19 +0,0 @@
-mod admin_set;
-mod create;
-mod delete;
-mod event_team_member_remove;
-mod event_user_update;
-mod game_update;
-mod profile_set;
-mod updated_user_update;
-
-chirp_worker::workers![
-	admin_set,
-	create,
-	delete,
-	event_team_member_remove,
-	event_user_update,
-	game_update,
-	profile_set,
-	updated_user_update,
-];
diff --git a/packages/services/user/worker/src/workers/profile_set.rs b/packages/services/user/worker/src/workers/profile_set.rs
deleted file mode 100644
index 14017206ca..0000000000
--- a/packages/services/user/worker/src/workers/profile_set.rs
+++ /dev/null
@@ -1,109 +0,0 @@
-use chirp_worker::prelude::*;
-use proto::backend::pkg::*;
-use serde_json::json;
-
-#[worker(name = "user-profile-set")]
-async fn worker(ctx: &OperationContext<user::msg::profile_set::Message>) -> GlobalResult<()> {
-	let body = ctx.body();
-	let user::msg::profile_set::Message {
-		user_id,
-		display_name,
-		account_number,
-		bio,
-	} = body;
-	let user_id = unwrap_ref!(user_id);
-
-	let mut query_components = Vec::new();
-
-	// Check if each component exists
-	if display_name.is_some() {
-		query_components.push(format!("display_name = ${}", query_components.len() + 2));
-	}
-	if account_number.is_some() {
-		query_components.push(format!("account_number = ${}", query_components.len() + 2));
-	}
-	if bio.is_some() {
-		query_components.push(format!("bio = ${}", query_components.len() + 2));
-	}
-
-	ensure!(!query_components.is_empty());
-
-	// Validate profile
-	let validation_res = chirp_workflow::compat::op(
-		&ctx,
-		::user::ops::profile_validate::Input {
-			user_id: user_id.as_uuid(),
-			display_name: display_name.clone(),
-			account_number: *account_number,
-			bio: bio.clone()
-		},
-	)
-	.await?;
-	if !validation_res.errors.is_empty() {
-		tracing::warn!(errors = ?validation_res.errors, "validation errors");
-
-		let readable_errors = validation_res
-			.errors
-			.iter()
-			.map(|err| err.path.join("."))
-			.collect::<Vec<_>>()
-			.join(", ");
-		bail_with!(VALIDATION_ERROR, error = readable_errors);
-	}
-
-	// Build query
-	let built_query = query_components.join(",");
-	let query_string = format!(
-		"UPDATE db_user.users SET {} WHERE user_id = $1",
-		built_query
-	);
-
-	// TODO: Convert this to sql_execute! macro
-	let query = sqlx::query(&query_string).bind(**user_id);
-
-	ctx.cache().purge("user", [user_id.as_uuid()]).await?;
-
-	// Bind display name
-	let query = if let Some(display_name) = display_name {
-		query.bind(display_name)
-	} else {
-		query
-	};
-
-	// Bind account number
-	let query = if let Some(account_number) = account_number {
-		query.bind(*account_number as i64)
-	} else {
-		query
-	};
-
-	// Bind bio
-	let query = if let Some(bio) = bio {
-		query.bind(util::format::biography(bio))
-	} else {
-		query
-	};
-
-	query.execute(&ctx.crdb().await?).await?;
-
-	msg!([ctx] user::msg::update(user_id) {
-		user_id: Some(*user_id),
-	})
-	.await?;
-
-	msg!([ctx] analytics::msg::event_create() {
-		events: vec![
-			analytics::msg::event_create::Event {
-				event_id: Some(Uuid::new_v4().into()),
-				name: "user.profile_set".into(),
-				properties_json: Some(serde_json::to_string(&json!({
-					"user_id": user_id.to_string()
-				}))?),
-				..Default::default()
-			},
-		],
-	})
-	.await?;
-
-	Ok(())
-}
diff --git a/packages/services/user/worker/src/workers/updated_party_update.rs b/packages/services/user/worker/src/workers/updated_party_update.rs
deleted file mode 100644
index 6ebcc0a487..0000000000
--- a/packages/services/user/worker/src/workers/updated_party_update.rs
+++ /dev/null
@@ -1,25 +0,0 @@
-use chirp_worker::prelude::*;
-use proto::backend::{self, pkg::*};
-
-#[worker(name = "user-updated-party-update")]
-async fn worker(ctx: &OperationContext<party::msg::update::Message>) -> GlobalResult<()> {
-	let party_id = unwrap_ref!(ctx.party_id);
-
-	let member_list = op!([ctx] party_member_list {
-		party_ids: vec![*party_id],
-	})
-	.await?;
-	let party = unwrap!(member_list.parties.first());
-
-	for user_id in &party.user_ids {
-		msg!([ctx] user::msg::updated(user_id) {
-			user_id: Some(*user_id),
-			update: Some(backend::user::update::Update {
-				kind: Some(backend::user::update::update::Kind::PartyUpdate(backend::user::update::PartyUpdate {})),
-			}),
-		})
-		.await?;
-	}
-
-	Ok(())
-}
diff --git a/packages/services/user/worker/src/workers/updated_user_update.rs b/packages/services/user/worker/src/workers/updated_user_update.rs
deleted file mode 100644
index db7d6bec4e..0000000000
--- a/packages/services/user/worker/src/workers/updated_user_update.rs
+++ /dev/null
@@ -1,18 +0,0 @@
-use chirp_worker::prelude::*;
-use proto::backend::{self, pkg::*};
-
-#[worker(name = "user-updated-user-update")]
-async fn worker(ctx: &OperationContext<user::msg::update::Message>) -> GlobalResult<()> {
-	let user_id = unwrap_ref!(ctx.user_id);
-
-	msg!([ctx] user::msg::updated(user_id) {
-		user_id: ctx.user_id,
-		update: Some(backend::user::update::Update {
-			kind: Some(backend::user::update::update::Kind::Update(backend::user::update::UserUpdate {
-			})),
-		}),
-	})
-	.await?;
-
-	Ok(())
-}
diff --git a/packages/services/user/worker/tests/admin_set.rs b/packages/services/user/worker/tests/admin_set.rs
deleted file mode 100644
index 9700bf089d..0000000000
--- a/packages/services/user/worker/tests/admin_set.rs
+++ /dev/null
@@ -1,33 +0,0 @@
-use chirp_worker::prelude::*;
-use proto::backend::pkg::*;
-
-#[worker_test]
-async fn admin_set(ctx: TestCtx) {
-	let user_res = op!([ctx] faker_user { }).await.unwrap();
-	let user_id = user_res.user_id.unwrap();
-
-	// Turn user into admin
-	msg!([ctx] user::msg::admin_set(user_id) -> user::msg::update {
-		user_id: Some(user_id),
-	})
-	.await
-	.unwrap();
-
-	let (exists,) = sql_fetch_one!(
-		[ctx, (bool,)]
-		"
-		SELECT EXISTS (
-			SELECT 1
-			FROM db_user.users
-			WHERE
-				user_id = $1 AND
-				is_admin = true
-		)
-		",
-		user_id.as_uuid(),
-	)
-	.await
-	.unwrap();
-
-	assert!(exists, "user not made into an admin");
-}
diff --git a/packages/services/user/worker/tests/create.rs b/packages/services/user/worker/tests/create.rs
deleted file mode 100644
index 4fbcdf9777..0000000000
--- a/packages/services/user/worker/tests/create.rs
+++ /dev/null
@@ -1,127 +0,0 @@
-use chirp_worker::prelude::*;
-use proto::backend::pkg::*;
-
-#[worker_test]
-async fn create(ctx: TestCtx) {
-	let user_id = Uuid::new_v4();
-	tracing::info!(%user_id);
-	msg!([ctx] user::msg::create(user_id) -> user::msg::create_complete {
-		user_id: Some(user_id.into()),
-		namespace_id: None,
-		display_name: None,
-	})
-	.await
-	.unwrap();
-
-	let (exists,): (bool,) =
-		sqlx::query_as("SELECT EXISTS (SELECT 1 FROM db_user.users WHERE user_id = $1)")
-			.bind(user_id)
-			.fetch_one(&ctx.crdb().await.unwrap())
-			.await
-			.unwrap();
-	assert!(exists, "user not created");
-}
-
-// // MARK: Stress tests:
-// #[worker_test]
-// async fn stress(ctx: TestCtx) {
-// 	let mut idx = 0;
-// 	let mut interval = tokio::time::interval(std::time::Duration::from_millis(50));
-// 	for _ in 0..100_000 {
-// 		interval.tick().await;
-
-// 		tracing::warn!(?idx);
-// 		idx += 1;
-
-// 		let user_id = Uuid::new_v4();
-// 		tracing::info!(%user_id);
-// 		msg!([ctx] user::msg::create(user_id) -> user::msg::create_complete {
-// 			user_id: Some(user_id.into()),
-// 			namespace_id: None,
-// 		})
-// 		.await
-// 		.unwrap();
-
-// 		let (exists,): (bool,) =
-// 			sqlx::query_as("SELECT EXISTS (SELECT 1 FROM db_user.users WHERE user_id = $1)")
-// 				.bind(&user_id)
-// 				.fetch_one(&ctx.crdb().await.unwrap())
-// 				.await
-// 				.unwrap();
-// 		assert!(exists, "user not created");
-// 	}
-// }
-
-// #[worker_test]
-// async fn stress_slow(ctx: TestCtx) {
-// 	let mut idx = 0;
-// 	loop {
-// 		tokio::time::sleep(std::time::Duration::from_secs(1)).await;
-
-// 		tracing::warn!(?idx);
-// 		idx += 1;
-
-// 		let user_id = Uuid::new_v4();
-// 		tracing::info!(%user_id);
-// 		msg!([ctx] user::msg::create(user_id) -> user::msg::create_complete {
-// 			user_id: Some(user_id.into()),
-// 			namespace_id: None,
-// 		})
-// 		.await
-// 		.unwrap();
-
-// 		let (exists,): (bool,) =
-// 			sqlx::query_as("SELECT EXISTS (SELECT 1 FROM db_user.users WHERE user_id = $1)")
-// 				.bind(&user_id)
-// 				.fetch_one(&ctx.crdb().await.unwrap())
-// 				.await
-// 				.unwrap();
-// 		assert!(exists, "user not created");
-// 	}
-// }
-
-// #[worker_test]
-// async fn stress_msg_reply(ctx: TestCtx) {
-// 	use std::sync::{
-// 		atomic::{AtomicI64, Ordering},
-// 		Arc,
-// 	};
-// 	use tokio::{
-// 		task::JoinSet,
-// 		time::{Duration, Instant},
-// 	};
-
-// 	let mut interval = tokio::time::interval(std::time::Duration::from_millis(50));
-// 	let in_progress_counter = Arc::new(AtomicI64::new(0));
-// 	let mut join_set = JoinSet::new();
-// 	for idx in 0..10_000 {
-// 		// interval.tick().await;
-
-// 		let in_progress_counter = in_progress_counter.clone();
-
-// 		let in_progress = in_progress_counter.fetch_add(1, Ordering::Relaxed);
-// 		tracing::info!(?idx, ?in_progress, "start idx");
-
-// 		let start = Instant::now();
-// 		let client = ctx.chirp().clone();
-// 		join_set.spawn(async move {
-// 			let user_id = Uuid::new_v4();
-// 			tracing::info!(%user_id);
-// 			msg!([client] user::msg::create(user_id) -> user::msg::create_complete {
-// 				user_id: Some(user_id.into()),
-// 				namespace_id: None,
-// 			})
-// 			.await
-// 			.unwrap();
-
-// 			let in_progress = in_progress_counter.fetch_add(-1, Ordering::Relaxed);
-// 			tracing::info!(?idx, ?in_progress, dt = %(Instant::now() - start).as_secs_f32(), "finish idx");
-// 		});
-// 	}
-
-// 	while let Some(res) = join_set.join_next().await {
-// 		res.unwrap();
-// 	}
-
-// 	tracing::info!("complete");
-// }
diff --git a/packages/services/user/worker/tests/delete.rs b/packages/services/user/worker/tests/delete.rs
deleted file mode 100644
index d3e5b692fb..0000000000
--- a/packages/services/user/worker/tests/delete.rs
+++ /dev/null
@@ -1,125 +0,0 @@
-use chirp_worker::prelude::*;
-use proto::backend::{self, pkg::*};
-
-// TODO: Verify user identity is deleted
-#[worker_test]
-async fn delete(ctx: TestCtx) {
-	let user_id = Uuid::new_v4();
-	tracing::info!(%user_id);
-
-	msg!([ctx] user::msg::create(user_id) -> user::msg::create_complete {
-		user_id: Some(user_id.into()),
-		namespace_id: None,
-		display_name: None,
-	})
-	.await
-	.unwrap();
-
-	// File upload
-	{
-		op!([ctx] upload_prepare {
-			bucket: "bucket-build".into(),
-			files: vec![
-				backend::upload::PrepareFile {
-					path: "upload.txt".into(),
-					mime: Some("text/plain".into()),
-					content_length: 123,
-					..Default::default()
-				},
-			],
-			user_id: Some(user_id.into()),
-		})
-		.await
-		.unwrap();
-	}
-
-	// Teams
-	let team_id1 = Uuid::new_v4();
-	let team_id2 = Uuid::new_v4();
-	{
-		// Owner
-		msg!([ctx] team::msg::create(team_id1) -> team::msg::create_complete {
-			team_id: Some(team_id1.into()),
-			display_name: util::faker::display_name(),
-			owner_user_id: Some(user_id.into())
-		})
-		.await
-		.unwrap();
-
-		// Not owner
-		msg!([ctx] team::msg::create(team_id2) -> team::msg::create_complete {
-			team_id: Some(team_id2.into()),
-			display_name: util::faker::display_name(),
-			owner_user_id: Some(Uuid::new_v4().into())
-		})
-		.await
-		.unwrap();
-		msg!([ctx] team::msg::member_create(team_id2, user_id) -> team::msg::member_create_complete {
-			team_id: Some(team_id2.into()),
-			user_id: Some(user_id.into()),
-			invitation: None,
-		})
-		.await
-		.unwrap();
-	}
-
-	msg!([ctx] user::msg::delete(user_id) -> user::msg::delete_complete {
-		user_id: Some(user_id.into()),
-	})
-	.await
-	.unwrap();
-
-	// Verify uploads
-	{
-		let uploads_res = op!([ctx] upload_list_for_user {
-			user_ids: vec![user_id.into()],
-			anchor: None,
-			limit: 1,
-		})
-		.await
-		.unwrap();
-		let user = uploads_res.users.first().unwrap();
-		let uploads_res = op!([ctx] upload_get {
-			upload_ids: user.upload_ids.clone(),
-		})
-		.await
-		.unwrap();
-
-		for upload in &uploads_res.uploads {
-			assert!(upload.deleted_ts.is_some(), "upload not deleted");
-		}
-	}
-
-	// Verify teams
-	{
-		let team_members_res = op!([ctx] team_member_list {
-			team_ids: vec![team_id1.into(), team_id2.into()],
-		})
-		.await
-		.unwrap();
-
-		let team1 = team_members_res
-			.teams
-			.iter()
-			.find(|team| team.team_id.unwrap().as_uuid() == team_id1)
-			.unwrap();
-		assert_eq!(1, team1.members.len());
-		let team2 = team_members_res
-			.teams
-			.iter()
-			.find(|team| team.team_id.unwrap().as_uuid() == team_id2)
-			.unwrap();
-		assert_eq!(1, team2.members.len());
-	}
-
-	// Verify user record
-	{
-		let (delete_complete_ts,): (Option<i64>,) =
-			sqlx::query_as("SELECT delete_complete_ts FROM db_user.users WHERE user_id = $1")
-				.bind(user_id)
-				.fetch_one(&ctx.crdb().await.unwrap())
-				.await
-				.unwrap();
-		assert!(delete_complete_ts.is_some(), "user not deleted");
-	}
-}
diff --git a/packages/services/user/worker/tests/event_party_member_update.rs b/packages/services/user/worker/tests/event_party_member_update.rs
deleted file mode 100644
index 4b73a5bf7b..0000000000
--- a/packages/services/user/worker/tests/event_party_member_update.rs
+++ /dev/null
@@ -1,6 +0,0 @@
-use chirp_worker::prelude::*;
-
-#[worker_test]
-async fn basic(_ctx: TestCtx) {
-	// TODO:
-}
diff --git a/packages/services/user/worker/tests/event_party_update.rs b/packages/services/user/worker/tests/event_party_update.rs
deleted file mode 100644
index 4b73a5bf7b..0000000000
--- a/packages/services/user/worker/tests/event_party_update.rs
+++ /dev/null
@@ -1,6 +0,0 @@
-use chirp_worker::prelude::*;
-
-#[worker_test]
-async fn basic(_ctx: TestCtx) {
-	// TODO:
-}
diff --git a/packages/services/user/worker/tests/event_team_member_remove.rs b/packages/services/user/worker/tests/event_team_member_remove.rs
deleted file mode 100644
index 4b73a5bf7b..0000000000
--- a/packages/services/user/worker/tests/event_team_member_remove.rs
+++ /dev/null
@@ -1,6 +0,0 @@
-use chirp_worker::prelude::*;
-
-#[worker_test]
-async fn basic(_ctx: TestCtx) {
-	// TODO:
-}
diff --git a/packages/services/user/worker/tests/event_user_mm_lobby_join.rs b/packages/services/user/worker/tests/event_user_mm_lobby_join.rs
deleted file mode 100644
index 4b73a5bf7b..0000000000
--- a/packages/services/user/worker/tests/event_user_mm_lobby_join.rs
+++ /dev/null
@@ -1,6 +0,0 @@
-use chirp_worker::prelude::*;
-
-#[worker_test]
-async fn basic(_ctx: TestCtx) {
-	// TODO:
-}
diff --git a/packages/services/user/worker/tests/event_user_presence_update.rs b/packages/services/user/worker/tests/event_user_presence_update.rs
deleted file mode 100644
index 4b73a5bf7b..0000000000
--- a/packages/services/user/worker/tests/event_user_presence_update.rs
+++ /dev/null
@@ -1,6 +0,0 @@
-use chirp_worker::prelude::*;
-
-#[worker_test]
-async fn basic(_ctx: TestCtx) {
-	// TODO:
-}
diff --git a/packages/services/user/worker/tests/event_user_update.rs b/packages/services/user/worker/tests/event_user_update.rs
deleted file mode 100644
index 4b73a5bf7b..0000000000
--- a/packages/services/user/worker/tests/event_user_update.rs
+++ /dev/null
@@ -1,6 +0,0 @@
-use chirp_worker::prelude::*;
-
-#[worker_test]
-async fn basic(_ctx: TestCtx) {
-	// TODO:
-}
diff --git a/packages/services/user/worker/tests/profile_set.rs b/packages/services/user/worker/tests/profile_set.rs
deleted file mode 100644
index dd05eb066f..0000000000
--- a/packages/services/user/worker/tests/profile_set.rs
+++ /dev/null
@@ -1,33 +0,0 @@
-use chirp_worker::prelude::*;
-use proto::backend::pkg::*;
-
-#[worker_test]
-async fn empty(ctx: TestCtx) {
-	let user_res = op!([ctx] faker_user { }).await.unwrap();
-	let user_id = user_res.user_id.unwrap();
-
-	let display_name = util::faker::display_name();
-	let account_number = 1234;
-	let bio = "bio".to_owned();
-
-	msg!([ctx] user::msg::profile_set(user_id) -> user::msg::update {
-		user_id: Some(user_id),
-		display_name: Some(display_name.clone()),
-		account_number: Some(account_number),
-		bio: Some(bio.clone()),
-	})
-	.await
-	.expect("set user profile");
-
-	let (sql_display_name, sql_account_number, sql_bio): (String, i64, String) = sqlx::query_as(
-		"SELECT display_name, account_number, bio FROM db_user.users WHERE user_id = $1",
-	)
-	.bind(*user_id)
-	.fetch_one(&ctx.crdb().await.unwrap())
-	.await
-	.unwrap();
-
-	assert_eq!(display_name, sql_display_name);
-	assert_eq!(account_number as i64, sql_account_number);
-	assert_eq!(bio, sql_bio);
-}
diff --git a/packages/services/user/worker/tests/search_update.rs b/packages/services/user/worker/tests/search_update.rs
deleted file mode 100644
index 4b73a5bf7b..0000000000
--- a/packages/services/user/worker/tests/search_update.rs
+++ /dev/null
@@ -1,6 +0,0 @@
-use chirp_worker::prelude::*;
-
-#[worker_test]
-async fn basic(_ctx: TestCtx) {
-	// TODO:
-}
diff --git a/packages/services/user/worker/tests/search_update_user_create_complete.rs b/packages/services/user/worker/tests/search_update_user_create_complete.rs
deleted file mode 100644
index 4b73a5bf7b..0000000000
--- a/packages/services/user/worker/tests/search_update_user_create_complete.rs
+++ /dev/null
@@ -1,6 +0,0 @@
-use chirp_worker::prelude::*;
-
-#[worker_test]
-async fn basic(_ctx: TestCtx) {
-	// TODO:
-}
diff --git a/packages/services/user/worker/tests/search_update_user_follow_create.rs b/packages/services/user/worker/tests/search_update_user_follow_create.rs
deleted file mode 100644
index 4b73a5bf7b..0000000000
--- a/packages/services/user/worker/tests/search_update_user_follow_create.rs
+++ /dev/null
@@ -1,6 +0,0 @@
-use chirp_worker::prelude::*;
-
-#[worker_test]
-async fn basic(_ctx: TestCtx) {
-	// TODO:
-}
diff --git a/packages/services/user/worker/tests/search_update_user_update.rs b/packages/services/user/worker/tests/search_update_user_update.rs
deleted file mode 100644
index 4b73a5bf7b..0000000000
--- a/packages/services/user/worker/tests/search_update_user_update.rs
+++ /dev/null
@@ -1,6 +0,0 @@
-use chirp_worker::prelude::*;
-
-#[worker_test]
-async fn basic(_ctx: TestCtx) {
-	// TODO:
-}
diff --git a/packages/services/user/worker/tests/updated_party_update.rs b/packages/services/user/worker/tests/updated_party_update.rs
deleted file mode 100644
index 4b73a5bf7b..0000000000
--- a/packages/services/user/worker/tests/updated_party_update.rs
+++ /dev/null
@@ -1,6 +0,0 @@
-use chirp_worker::prelude::*;
-
-#[worker_test]
-async fn basic(_ctx: TestCtx) {
-	// TODO:
-}
diff --git a/packages/services/user/worker/tests/updated_user_follow_create.rs b/packages/services/user/worker/tests/updated_user_follow_create.rs
deleted file mode 100644
index 4b73a5bf7b..0000000000
--- a/packages/services/user/worker/tests/updated_user_follow_create.rs
+++ /dev/null
@@ -1,6 +0,0 @@
-use chirp_worker::prelude::*;
-
-#[worker_test]
-async fn basic(_ctx: TestCtx) {
-	// TODO:
-}
diff --git a/packages/services/user/worker/tests/updated_user_follow_delete.rs b/packages/services/user/worker/tests/updated_user_follow_delete.rs
deleted file mode 100644
index 4b73a5bf7b..0000000000
--- a/packages/services/user/worker/tests/updated_user_follow_delete.rs
+++ /dev/null
@@ -1,6 +0,0 @@
-use chirp_worker::prelude::*;
-
-#[worker_test]
-async fn basic(_ctx: TestCtx) {
-	// TODO:
-}
diff --git a/packages/services/user/worker/tests/updated_user_presence_update.rs b/packages/services/user/worker/tests/updated_user_presence_update.rs
deleted file mode 100644
index 4b73a5bf7b..0000000000
--- a/packages/services/user/worker/tests/updated_user_presence_update.rs
+++ /dev/null
@@ -1,6 +0,0 @@
-use chirp_worker::prelude::*;
-
-#[worker_test]
-async fn basic(_ctx: TestCtx) {
-	// TODO:
-}
diff --git a/packages/services/user/worker/tests/updated_user_update.rs b/packages/services/user/worker/tests/updated_user_update.rs
deleted file mode 100644
index 4b73a5bf7b..0000000000
--- a/packages/services/user/worker/tests/updated_user_update.rs
+++ /dev/null
@@ -1,6 +0,0 @@
-use chirp_worker::prelude::*;
-
-#[worker_test]
-async fn basic(_ctx: TestCtx) {
-	// TODO:
-}