Skip to content

Comments

Feature: Non Public Object Storage#499

Open
Neirpyc wants to merge 3 commits intospliit-app:mainfrom
Neirpyc:main
Open

Feature: Non Public Object Storage#499
Neirpyc wants to merge 3 commits intospliit-app:mainfrom
Neirpyc:main

Conversation

@Neirpyc
Copy link

@Neirpyc Neirpyc commented Jan 29, 2026

Context & Use Case

I host this Spliit instance for upcoming group holidays. To keep our data private, the entire instance sits behind an authenticated proxy, ensuring only our friends can access the tool.

The Problem: Currently, S3-uploaded documents (receipts/images) require the bucket to be public for them to render in the browser. This effectively bypasses the proxy's security, potentially exposing personal documents to the open web if a URL is leaked.

The Fix: This PR moves all S3 interactions to the server. The bucket can now be 100% private. Spliit fetches and streams the files server-side, meaning only users already authenticated through the proxy can see them.

Key Improvements

  • Privacy First: Documents are no longer public. They are served via application routes (/api/documents/[id]).
  • Zero-CORS Setup: Since the browser no longer talks directly to S3, we can remove all CORS configurations from the bucket.
  • Secure AI Analysis: Enables server-side generation of temporary authenticated URLs for AI document extraction (tested with Scaleway) without ever making the file public.

What Changed

Backend (The "Proxy" Logic)

  • POST /api/documents: Receives multipart uploads, stores them in S3, and saves metadata (dimensions, filename) to the DB.
  • GET /api/documents/:id: The "secure gateway." It verifies the document exists and streams the data directly from S3 to the authenticated user.

Client & UI

  • Frontend Refactor: Replaced next-s3-upload dependencies with a lightweight, native implementation.
  • getImageData: A new client helper that calculates image dimensions using browser APIs to prevent layout shift without extra libraries.
  • Receipt Flow: The "Create from Receipt" button now triggers a server-side upload + AI extraction, keeping the entire pipeline off the public internet.

Infrastructure

  • src/lib/s3.ts: Centralized S3 client factory that only initializes if env vars are present.
  • Flexible AI Env Vars: Added support for OPENAI_BASE_URL and model overrides, allowing for easy swapping between OpenAI and local/Scaleway providers.

Security Note

By default, the SDK creates objects with private ACLs. This PR ensures that even if someone gets hold of the raw S3 link, the file remains inaccessible without the app's internal credentials.

@Neirpyc
Copy link
Author

Neirpyc commented Jan 29, 2026

Note: addresses #350, #84 and #378

@Neirpyc Neirpyc changed the title Feature: Secure Document Storage for Private Spliit Instances Feature: Non Public Object Storage Jan 29, 2026
@brknkfr
Copy link

brknkfr commented Feb 17, 2026

Fantastic!

I just deployed spliit on our server and I was missing the possibility to use with our LocalAI instance and I thought, that it would be nice to use private S3 buckets as we use Garage as our S3 bucket provider which is a little bit complicated to configure to provide files over the web (different domains for the S3 endpoint and the web endpoint).

Now there is your PR which solves those two problems. The PR works like a charm (together with LocalAI and Garage).

Please include this in the next release, @scastiel.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants