Skip to content

01 / LUDER / FILE STORAGE ENGINE

Every file, verified before it is stored.

CHUNKED UPLOAD · RESUME-SAFE · TIKA DETECT · CLAMAV SCAN · AES-CBC · STREAMING

LUDER is a file storage engine built in Java and Spring Boot. It receives files in pieces, tracks every piece, assembles them, proves what each file really is, scans it, encrypts it at rest, and streams it back decrypted on demand.

  • CHUNKED UPLOAD
  • RESUME-SAFE
  • TIKA DETECT
  • CLAMAV SCAN
  • AES-CBC
  • STREAMING READ
LUDER logo — official brand mark
fig 01 · the file engineready

100

MAX CHUNKS · declared per upload session

3
DEFENSE LAYERS · detect · scan · encrypt
AES-CBC
AT REST · fresh 16-byte IV per file
4H
SWEEPER · orphan sessions swept
production case study · fig 01

02 / The pipeline

Five guarantees, before a byte is stored.

From chunk merge to encrypted final store — every file passes the same chain, in the same order, on the way in.

  1. 01

    ASSEMBLE

    FileChannel.transferTo merges chunks in index order

  2. 02

    VERIFY

    Tika detects the real content type · whitelist of nine MIME types

  3. 03

    SCAN

    ClamAV clamscan — exit 0 admits, exit 1 deletes

  4. 04

    ENCRYPT

    AES/CBC/PKCS5Padding with a fresh IV · plaintext deleted

  5. 05

    STORE

    metadata → Postgres · ciphertext → final store

endpoint reference
  1. POST

    /api/uploads/start

    declare fileName · totalChunks · contentType → session + Redis init

  2. POST

    /api/uploads/{uploadId}/chunk/{index}

    multipart chunk → validated, written to the temp store

  3. GET

    /api/uploads/{uploadId}/status

    receivedChunks / totalChunks · served from the Redis cache

  4. POST

    /api/uploads/{uploadId}/complete

    gate received == total → assemble · verify · scan · encrypt

  5. GET

    /api/files

    paged file metadata · one-hour Redis cache

  6. GET

    /api/files/download/{fileName}

    stream + decrypt AES-CBC · attachment response

03 / System map

The engine, opened up.

Twelve nodes across the storage boundary. Select a node to trace how it connects to the rest of the engine.

SYSTEM MAPselect a node to trace its connections

04 / Security

Three walls between upload and store.

No uploaded byte is stored the way it arrived. LUDER proves, scans, and encrypts every file before it lands in the final store.

WALL 01

DETECT

Apache Tika

The content type is detected from the assembled bytes — not from whatever the client claimed — then matched against an allowlist of nine MIME types. Anything outside is rejected and deleted.

9 allowed MIME types

WALL 02

SCAN

ClamAV clamscan

Every assembled file is scanned by ClamAV before it is stored. Exit code 0 admits the file; exit code 1 deletes it as a threat; any other exit aborts the session.

exit 0 clean · exit 1 infected

WALL 03

ENCRYPT

AES/CBC/PKCS5Padding

Files are encrypted at rest with a fresh 16-byte IV written ahead of the ciphertext, and a key persisted out-of-band as a Base64 file. The plaintext is deleted after encryption.

AES-CBC · 16-byte IV · 8KB stream

MIME allowlist

09 types

  • image/jpeg
  • image/png
  • image/gif
  • video/mp4
  • video/webm
  • video/quicktime
  • application/pdf
  • application/json
  • text/plain

05 / Storage

Two stores, tracked to the piece.

Chunks stage in a per-session temp directory; only an assembled, verified, encrypted file reaches the final store.

STAGING

Two stores, one intent

Chunks land in a per-session temp directory; only a fully assembled, verified, encrypted file reaches the final store. A session never writes final files incrementally.

RESUME

Redis tracks every piece

Received chunk indices live in a Redis set with a two-hour TTL, and progress in a matching hash. An interrupted upload can resume from exactly where it stopped.

SWEEP

Orphans do not linger

A scheduled task runs every four hours, cancels sessions idle over 110 minutes with no live Redis progress, and sweeps their temp directories.

RETRIEVAL

Streamed back, not loaded

Downloads open a streaming read that decrypts AES-CBC in 8KB buffers as the response streams — the full file is never held in memory.

disk layout · ./uploads

STAGING
./uploads/temp/{uploadId}/{index}
FINAL
./uploads/fin/{uploadId}_{fileName}.enc
  • · every 4h · cancels sessions idle over 110 minutes · sweeps temp dirs
  • · streaming decrypt · 8KB buffer · attachment response

06 / Verification

Proven against the edge cases.

A test suite that chases the failure modes of a chunked file engine.

verification suite64 runs · 64 passed
  1. SPLITchunk acceptancebounds 0 ≤ index < totalChunks · non-empty · no duplicate index16/16
  2. RESUMEinterrupted uploadmissed chunks re-sent · status reflects the received set · no double writes16/16
  3. TEMP-IOstaging I/Ochunks land per session · assembly reads in index order12/12
  4. ASSEMBLYchunk mergetransferTo merges in order · temp dir swept after completion6/6
  5. COMPLETE GATEsession completionreceived == total required · incomplete sessions rejected · state flips to COMPLETED8/8
  6. THREATmalware rejectionclamscan exit 1 → file deleted · session aborted · nothing stored6/6

07 / Foundations

Built as an engine, not a demo.

The decisions underneath a chunked storage pipeline.

CHUNKING

Resumable chunked upload

Files arrive as 1–100 client-declared chunks, each validated against the session before it is written to the temp store.

STATE

Session state in Redis

Progress and received indices live in Redis with a two-hour TTL — the engine knows exactly what is missing at any moment.

DEFENSE

Verify, scan, encrypt

Every file is detected by Tika, scanned by ClamAV, and encrypted with AES-CBC before it is committed to storage.

RETRIEVAL

Streamed, decrypted reads

Downloads decrypt in 8KB streaming buffers with the original MIME type restored and a Content-Disposition attachment.

08 / Technology

Everything the engine runs on.

The stack the storage pipeline actually runs on.

Stack
  1. JAVA
  2. SPRING BOOT
  3. POSTGRESQL
  4. REDIS
  5. TIKA
  6. CLAMAV
  7. APACHE MAVEN
  8. JPA · HIBERNATE
Layering

CLIENTAPISERVICEREDIS · POSTGRES · DISK

Year
2025
Role
Backend Engineer

09 / Proof & open source

The engine, in the open.

The repository is the storage engine itself — controllers, services, the chunk pipeline, and the gates that guard it.