Drive
Back to DevelopmentPersonal Storage-as-a-Service — files and folders, team drives, sharing, trash, public links, and pluggable Local / Tigris backends with a full REST API.
Repository
DrivePersonal Storage-as-a-Service — files and folders, team drives, sharing, trash, public links, and pluggable Local / Tigris backends with a full REST API.
Overview
Drive (ZNL-DRIVE) is a SvelteKit file workspace that feels like a familiar cloud drive while staying under your control. Metadata — hierarchy, labels, pin/star, trash, shares, and storage provider — lives in Postgres via Drizzle. Bytes live on either the server filesystem (Local) or Tigris S3-compatible object storage. The same product exposes a browser UI, cookie sessions, and developer API keys for automation.
Problem it solves
Most “drive” demos hard-code one bucket and skip team spaces, trash retention, or a public API. Drive treats storage as a product surface: switch providers without rewriting the UI, share with signed-in users or anonymous link tokens, and operate teams with their own storage target. Deployments run on Docker or Fly.io with Neon Postgres.
Home library
Home is the primary library. Breadcrumbs track folder depth; row actions cover rename, color labels, pin, star, download, share, public link, and move to trash. The NEW menu creates folders, uploads files, and can create a team. There is no global top-bar search — navigation is intentional through Home, Shared, Teams, Recent, Trash, and Dashboard.
Storage providers
A navbar selector chooses the active target for new uploads and folders. Existing rows keep the provider they were written with. Team drives lock to the team’s configured provider so members do not accidentally split a shared space across backends.
- Local — server filesystem under a mounted data directory (ideal for LAN / single-node Docker)
- Tigris — S3-compatible object storage via the Tigris SDK
- Architecture leaves room for other S3-compatible backends (R2, MinIO, B2, etc.)
Upload & download
Small files upload as binary application/octet-stream; larger files use chunked upload sessions (≈8 MiB chunks) assembled on disk before finalize. MIME is inferred from filenames when the browser sends an empty type. Downloads stream a single file or a ZIP for folders. Upload/create actions are disabled in Shared and Trash with clear UI copy.
Sharing & collaboration
- User share — grant another account access; Shared view is read-oriented (browse/download, no upload into someone else’s tree)
- Team drives — shared spaces under Teams; create from NEW, invite members, list membership via /api/teams
- Public links — revocable random tokens; human share page at /{token} plus direct /api/public/files/{token} for raw bytes or folder ZIP; images preview inline, other types download
- Docs under /onboarding/docs never collide with share tokens (fixed path prefix)
Trash & retention
Items leave Home when trashed and appear in the Trash sidebar view for restore or permanent delete. A cron endpoint (Bearer CRON_SECRET) purges expired trash on a schedule so operators can enforce retention policy without manual cleanup.
Auth & developer mode
Better Auth powers email/password plus optional GitHub and Google OAuth. Drive JSON/binary APIs accept a session cookie or a developer API key (Authorization / X-API-Key). Key CRUD and developer-mode toggles require a cookie session so keys cannot manage themselves. Settings expose profile, storage preferences, and logout.
REST surface (highlights)
- GET/POST /api/drive/files & folders — list, create, patch pin/star/name/color/trash
- POST /api/drive/upload (+ /chunk) — binary and chunked uploads
- GET …/download, …/public-link; POST/DELETE public-link and share
- GET /api/drive/shared, /trash, /stats
- GET/POST /api/teams — membership and team creation
- GET /api/public/share/{token} and /api/public/files/{token} — anonymous access
- Developer mode + API key CRUD under /api/developer/*
Architecture
Requests enter SvelteKit routes, resolve auth (cookie or API key), then hit small server handlers that query Postgres for metadata and open Local or Tigris blobs for bytes. Public link tokens are a separate table so anonymous traffic never needs a session. Onboarding docs are mdsvex routes with a drawer sidebar — prerender-safe because they do not read private data.
Stack & ops
- SvelteKit 2 + Svelte 5, Tailwind CSS 4, daisyUI 5 (prefixed d- classes)
- Postgres (Neon) + Drizzle ORM; Better Auth sessions
- Deno 2 task runner for install/dev/db scripts; Node for Vite build and production runtime
- Docker volume for Local data; BODY_SIZE_LIMIT per chunk; ORIGIN-sensitive CSRF/cookie Secure behavior
- Paraglide i18n; Playwright + unit tests; GPLv3
Design decisions
- Metadata in SQL, blobs in pluggable storage — so listing, trash, and shares stay fast regardless of backend
- Chunked uploads with on-disk assembly — large media without loading whole files into memory
- API keys as first-class auth — scripts and agents can use the same drive APIs as the UI
- Team storage affinity — one shared space maps to one provider, avoiding split-brain folders