A production-ready REST API for file storage where metadata lives in a relational database and binary content is stored on disk.
This project is built for teams that need a simple, extensible file platform with tenant isolation, configurable storage layouts, usage tracking, and built-in controls for API-key access, quotas, and rate limits.
File Management System helps external integrators and platform teams:
- ingest and retrieve files through a clean HTTP API
- isolate tenants at both filesystem and database query level
- choose storage path strategies without changing API contracts
- enforce tenant-level quotas and upload limits
- expose usage events for billing and analytics
- run locally with H2 or move to PostgreSQL for larger environments
Client Apps
|
v
Spring Boot API (port 8081)
- UploadFileController
- DownloadFileController
- ApiKeyController
|
+--> Database (H2/PostgreSQL): metadata, API keys, usage events
|
+--> Filesystem: binary content under {file.db.location}/{tenant}/...
Core design choices:
- strategy pattern for storage layout (
StorageStrategyService+FileStorageStrategyFactory) - strategy pattern for file ID generation (
FileIdStrategyService+FileIdServiceFactory) - centralized configuration through
AppConfig(avoid scattered@Value) - global exception mapping via
GlobalExceptionHandlerfor predictable API errors
- multipart upload and raw byte-array upload variants
- download by file ID, with optional tenant check
- file metadata persisted in DB, content on disk
- tenant-aware folder structure under
file.db.location - tenant-scoped repository queries for storage and retrieval
- optional tenant allow-list enforcement (
tenant.verification)
storage.strategy supports:
FILEFILE_PER_DATEFILE_PER_YEAR_DATEFILE_PER_YEAR_MONTHFILE_PER_YEAR_MONTH_DAYFILE_PER_YEAR_MONTH_DATE
- optional API key enforcement (
api.key.verification=true) - per-tenant storage quota (
tenant.storage.quota.bytes) - rolling 24-hour upload rate limit (
tenant.upload.limit.per.day) - usage event tracking for upload/download activity (
UsageEvent)
- Java 21
- Spring Boot 4.0.5
- Spring Web + Spring Data JPA
- H2 (default local DB) and PostgreSQL driver
- springdoc OpenAPI UI
- Log4j2
- Maven
- Java 21+
- Maven 3.9+
mvn clean packagejava -jar target/file-management-system-1.0.7.jar- API docs (springdoc):
http://localhost:8081/swagger-ui/index.html - API docs (compat redirect in many setups):
http://localhost:8081/swagger-ui.html - H2 console:
http://localhost:8081/h2-console/
From src/main/resources/application.properties:
server.port=8081spring.datasource.url=jdbc:h2:file:./data/db-v2;AUTO_SERVER=TRUEspring.datasource.username=saspring.datasource.password=passwordfile.db.location=C:/filessssss/file-dbstorage.strategy=FILEfile.id.type=(empty means UUID default)api.key.verification=falsetenant.storage.quota.bytes=1073741824tenant.upload.limit.per.day=10000
| Method | Endpoint | Description |
|---|---|---|
POST |
/uploadNewFile/{tenant} |
Upload new file with generated ID |
POST |
/uploadByTenantAndFileId/{tenant}/{fileId} |
Upload with client-provided ID |
POST |
/uploadNewFile/{fileId}/{tenant} |
Upload with explicit file ID and tenant |
POST |
/uploadMultipartFile/{fileId}/{tenant} |
Multipart upload variant |
POST |
/upload/{fileId}/{tenant} |
Raw byte-array upload |
POST |
/upload/{fileId}/{directory}/{tenant} |
Raw upload with custom directory segment |
| Method | Endpoint | Description |
|---|---|---|
GET |
/download/{fileId} |
Download by file ID |
GET |
/download/{fileId}/{tenant} |
Download with tenant validation |
| Method | Endpoint | Description |
|---|---|---|
POST |
/admin/apikey/{tenant} |
Generate API key |
GET |
/admin/apikey/{tenant} |
List active API keys |
DELETE |
/admin/apikey/{tenant} |
Revoke all tenant keys |
curl -X POST http://localhost:8081/uploadNewFile/tenant1 -F "file=@document.pdf"
curl -X GET http://localhost:8081/download/my-id --output downloaded.pdf
curl -X POST http://localhost:8081/admin/apikey/tenant1
curl -X GET http://localhost:8081/download/my-id -H "X-API-Key: fms-..." --output downloaded.pdfThe project uses Log4j2 with src/main/resources/log4j2-spring.xml.
- console logging enabled
- rolling file appender enabled
- base log folder property:
APP_LOG_ROOT(default in config:/root/app/logs) - active levels in
application.properties:logging.level.root=infologging.level.org.springframework.web=infologging.level.org.hibernate=error
mvn testRun one test class:
mvn test -Dtest=FileStorageStrategyFactoryTestRun with external configuration:
java -jar target/file-management-system-1.0.7.jar --spring.config.location=/path/to/application.propertiesFor production-like deployments, typically:
- use PostgreSQL
- set a valid writable
file.db.location - configure a writable log path in
log4j2-spring.xml - keep
api.key.verification, quotas, and limits enabled as required by your pricing model
Please read CONTRIBUTING.md.
See CHANGELOG.md for release history.
MIT License - see LICENSE.
- GitHub Sponsors: https://github.com/sponsors/sdrahnea
- PayPal: https://www.paypal.me/sdrahnea