PureShare is a Next.js App Router application for temporary file sharing and file requests. It supports browser-to-S3 uploads, expiring share links, optional password protection, owner analytics, QR/social sharing, and an authenticated dashboard for managing shares and requests.
- Create share links for uploaded files
- Upload files directly from the browser to S3 with presigned URLs
- Protect shares with optional passwords
- Expire links automatically based on configured time windows
- Preview images and video before download
- Download individual files or all files as a ZIP
- Create file request links so other people can upload to you
- View owner analytics and dashboard activity for authenticated shares
PureShare uses practical access controls, not client-side end-to-end encryption.
- TLS protects browser and API traffic
- S3 objects are accessed through time-limited signed URLs
- Shares can require a password before access
- Dashboard and owner APIs are protected with Clerk authentication
- Rate limiting is available when Upstash Redis is configured
- Environment validation fails fast for required runtime secrets
These defaults come from config/constants.ts and can be overridden with environment variables.
- Image uploads:
100MBper file - Video uploads:
500MBper file - Files per share:
50 - Standard expiration options:
24,48,72,168hours - Video expiration options:
24,48,72,168hours
- Framework: Next.js 16 App Router
- Language: TypeScript
- Auth: Clerk
- Database: Supabase Postgres
- Storage: AWS S3
- Validation: Zod
- UI: Tailwind CSS v4, Radix UI, shadcn-style components
- Email: Resend
- Rate limiting: Upstash Redis
- Client calls
POST /api/upload/create - Client registers each file through
POST /api/upload/files - Browser uploads file bytes directly to S3 using the returned presigned URL
- Client finalizes the upload through
PATCH /api/upload/files - Recipients access the share through
/share/[id]
- Authenticated user creates a request through
POST /api/request/create - Recipient opens
/request/[id] - Client registers upload metadata through
POST /api/request/[id]/upload - Browser uploads directly to S3
- Client finalizes the upload through
PATCH /api/request/[id]/upload
- Individual downloads use
GET /api/share/[id]/download/[fileId] - ZIP downloads use
GET /api/share/[id]/download-all - Owner analytics are exposed through
GET /api/shares/[id]/analytics
app/
(dashboard)/ Authenticated dashboard pages
(marketing)/ Public marketing, pricing, help, legal pages
api/ Route handlers for upload, share, request, user, analytics
request/[id]/ Public file request upload page
share/[id]/ Public share view and download page
upload/ Share creation page
components/
dashboard/ Dashboard UI
marketing/ Marketing sections
share/ Share actions and modals
shared/ Shared app components
ui/ UI primitives and motion components
lib/
db/ Supabase clients and user resolution
downloads/ Client download helpers
email/ Notification templates and sending
middleware/ Rate limiting and security helpers
security/ Password and share-link helpers
storage/ S3 client and presigned URL utilities
validations/ Zod schemas
supabase/migrations/ SQL migrations and RPC helpers
config/constants.ts Runtime defaults and limits
- Node.js 20+
- npm
- Supabase project
- AWS S3 bucket
- Clerk application
Optional but recommended:
- Upstash Redis for rate limiting
- Resend for notification emails
Copy .env.example to .env.local and fill in the required values.
Required runtime variables:
NEXT_PUBLIC_APP_URLNEXT_PUBLIC_SUPABASE_URLNEXT_PUBLIC_SUPABASE_ANON_KEYSUPABASE_SERVICE_ROLE_KEYAWS_REGIONAWS_ACCESS_KEY_IDAWS_SECRET_ACCESS_KEYAWS_S3_BUCKET_NAMENEXT_PUBLIC_CLERK_PUBLISHABLE_KEYCLERK_SECRET_KEY
Optional runtime variables:
UPSTASH_REDIS_REST_URLUPSTASH_REDIS_REST_TOKENRESEND_API_KEYFROM_EMAILALLOWED_ORIGINSHEALTH_CHECK_TOKEN
npm installcp .env.example .env.localApply the SQL files in supabase/migrations/ using your normal Supabase workflow.
Important recent migrations:
supabase/migrations/20260313_phase1_upload_finalization.sqlsupabase/migrations/20260313_phase3_aggregates.sql
If you use the Supabase CLI, this is typically done with:
supabase db pushnpm run devOpen http://localhost:3000.
npm run dev
npm run lint
npm run build
npm run startPages:
/- landing page/upload- create a share/share/[id]- view/download a share/request/[id]- upload to a file request/dashboard- owner dashboard/dashboard/shares- owner shares/dashboard/requests- owner file requests/dashboard/settings- account/settings page
API:
POST /api/upload/createPOST /api/upload/filesPATCH /api/upload/filesPOST /api/request/createPOST /api/request/[id]/uploadPATCH /api/request/[id]/uploadPOST /api/share/[id]/verifyGET /api/share/[id]/filesGET /api/share/[id]/download/[fileId]GET /api/share/[id]/download-allGET /api/user/sharesGET /api/user/requestsGET /api/user/statsGET /api/shares/[id]/analytics
- The health endpoint is
GET /api/health - In production, health access requires either a valid Clerk session or
HEALTH_CHECK_TOKEN - Upload finalization is tracked in the database; failed uploads are marked separately from completed uploads
- ZIP generation is streamed server-side and validated before browser-triggered download
Current local validation status:
npm run lintpassesnpm run buildpasses
There is currently no automated test script in package.json, so integration and end-to-end coverage are still a recommended next step.
- Older project notes may still reference JWT auth, client-side encryption, 5GB or 10GB upload limits, or download caps
- The current source of truth is the codebase, especially
config/constants.ts,lib/utils/env-validation.ts, and the route handlers inapp/api/