Remove File Storage and CDN

File storage keeps uploaded files in Supabase storage behind a CDN. Only user avatars and workspace logos use it. This guide removes the whole stack (model, CDN service, cleanup task, upload API and UI), so avatars and logos fall back to initials. It follows the shared removal loop.

Entry points

  • Server: src/server/domain/file/, src/server/services/use-cdn-service.ts, src/server/test/mocks/cdn-service.mock.ts, src/server/tasks/file-cdn-cleanup.ts. Specs sit next to the files and go with them.
  • API: src/server/api/users/[id]/avatar/, src/server/api/workspaces/[id]/logo/.
  • Shared types: src/shared/types/domain/File.ts, src/shared/types/FileUpload.ts.
  • App: src/app/plugins/cdn.ts, src/app/composables/flows/use-image-upload.ts (with spec), src/app/components/design-system/forms-and-actions/VueImageUpload/ (with spec and stories).
  • Prisma: prisma/schema/file.prisma (model File).
  • Env variables and runtime config: NUXT_SUPABASE_URL, NUXT_SUPABASE_SERVICE_ROLE_KEY, NUXT_SUPABASE_STORAGE_BUCKET, NUXT_PUBLIC_CDN_URL (runtime config supabaseUrl, supabaseServiceRoleKey, supabaseStorageBucket, public.cdnUrl).
  • Dependency: the Supabase JavaScript client (uninstall command under "Env and install" below).
  • The i18n keys input.avatar.label, input.logo.label and ProfileSettings.CropImage (used only by the avatar and logo upload fields and VueImageUpload).

Not found by the compiler

  • Prisma: delete the avatarFile/avatarFileId relation in prisma/schema/user.prisma and logoFile/logoFileId in prisma/schema/workspace.prisma, then create a new migration with npm run db:migrate and never edit the existing init migration. The migration drops the File table, both columns and all file records, so back up first and confirm it. Uploaded files stay in the Supabase bucket: delete the bucket yourself. The generated client and src/public/swagger/openapi.json are regenerated by the scripts.
  • Services: in src/server/domain/user/use-user-service.ts, remove updateUserAvatar, removeUserAvatar, the useFileService import and the avatar and deleteFile handling in deleteUser. In src/server/domain/workspace/use-workspace-service.ts, remove the logo equivalents, logoFile/logoFileId in the returned views and the deleteFile handling in deleteWorkspace. The compiler reports leftovers; the specs of both services and src/server/test/setup.ts use the CDN mock and need the matching removals. Remove the avatar test in src/server/api/users/[id]/index.delete.spec.ts.
  • Shared types: remove avatarFile from src/shared/types/domain/User.ts, logoFile/logoFileId from src/shared/types/domain/Workspace.ts, logoUri from src/shared/types/domain/WorkspaceSwitcherItem.ts and localLogoFile and deleteLogo from src/shared/types/ui/forms/WorkspaceFormModel.ts.
  • Stores and actions: remove updateUserAvatar/deleteUserAvatar from src/app/store/user.ts and src/app/composables/actions/use-user-actions.ts. Remove updateWorkspaceLogo/deleteWorkspaceLogo and the logoFile/logoFileId copies from src/app/store/workspace.ts and src/app/composables/actions/use-workspace-actions.ts. The specs src/app/store/user.spec.ts, src/app/store/workspace.spec.ts, src/app/composables/actions/use-user-actions.spec.ts and src/app/composables/actions/use-workspace-actions.spec.ts lose the matching tests.
  • Avatar upload UI: remove the avatar block, useImageUpload and VueImageUpload from src/app/pages/settings/index.vue. Remove the logo field, localLogoFile, deleteLogo and logoFileId from src/app/components/domain/workspace/WorkspaceForm/WorkspaceForm.vue and its stories, and the logo calls in src/app/layouts/app.vue and src/app/pages/workspaces/[workspaceId]/settings.vue. Their specs lose the matching tests.
  • Image display: remove the $cdn(...) image sources and the logoUri mapping in src/app/layouts/app.vue, src/app/pages/workspace-invitations/[id]/index.vue, src/app/components/domain/workspace/WorkspaceSwitcher/WorkspaceSwitcher.vue, src/app/components/domain/workspace-member/WorkspaceMemberTable/WorkspaceMemberTable.vue and src/app/components/domain/workspace-invitation/WorkspaceInvitationTable/WorkspaceInvitationTable.vue. VueAvatar shows initials without src. Remove the $cdn stubs in src/app/test/setup.ts and .storybook/preview.mjs, and the avatar fields in the stories and fixtures of these components.
  • Cleanup task: remove file-cdn-cleanup from scheduledTasks in nuxt.config.ts and from the group and the comment in src/server/plugins/run-startup-tasks.ts.
  • Demo reset: if the demo still exists, remove the file.updateMany call, markedFilesAsDeleted and the comment line about files in src/server/demo/reset-demo-data.ts. Adjust its spec and src/server/demo/run-demo-lifecycle.spec.ts.
  • nuxt.config.ts: remove the cdn constant, the cdn-cache workbox runtime caching entry, and supabaseUrl, supabaseServiceRoleKey, supabaseStorageBucket and public.cdnUrl from runtimeConfig. In src/app/app.vue, remove the dns-prefetch and preconnect links for config.public.cdnUrl.
  • Env and install: delete the four variables from .env-example, .env and the env list in content/docs/01.getting-started/02.installation.md, and from your hosting configuration. Then run npm uninstall @supabase/supabase-js. Supabase may also host your database: keep the account if it does.
  • Privacy and legal (your responsibility; Vuesion provides no legal advice): src/app/pages/privacy-policy/index.vue names Supabase as "Database and file storage" (pages.security.privacy-policy.p6.list.3), has the section "File Uploads" (pages.security.privacy-policy.p5.*) and lists "Profile picture" and "Files you upload" (pages.security.privacy-policy.p1.list.3, p1.list.7). The delete-account dialogs say "uploaded content" (AccountSettings.DangerZone.confirmDialog.description, WorkspaceSettings.DangerZone.confirmDialog.description). Adjust or remove as fits your product.
  • Marketing wording (only if you keep marketing; see the marketing guide): FoundationSection.identity.avatarUpload, FoundationSection.platform.fileUploads, FoundationSection.platform.imageCropper. The cropper stays as a design-system component, so adjust the last one only if you also remove the cropper.
  • i18n: the extractor never removes keys. Delete unused keys by hand from en-US.json and de-DE.json in i18n/locales.
  • Docs: in content/docs/03.development/04.configuration.md, remove "Storage configuration" from the secrets list, the "Supabase storage requires" bullet and the file-cdn-cleanup mention in the demo reset paragraph. In content/docs/03.development/05.database.md, remove the paragraphs "The main exception is the file domain." and "Files are deleted asynchronously ... disappear.". Only pages that still exist need changes.
  • Agent skills: in .agents/skills/vuesion-backend/SKILL.md, remove "CDN" from the Integrations row of the artifact table ((CDN, billing provider)) and replace the example file src/server/services/use-cdn-service.ts with a surviving file of the same kind, such as src/server/services/use-email-service.ts.
  • Keep VueImageCropper, VueFileInput, VueAvatar and cropperjs: they are generic design-system parts.

Coding-agent prompt

Read this guide and the shared removal loop. Delete every entry point of this guide, handle every item under "Not found by the compiler", and run the loop until lint, test and build pass.