NizenVault is a lightweight, self-hosted image manager for S3-compatible storage. Upload, organize, and serve images with workspaces, metadata editing, and a modern UI β powered by PHP, SQLite, and Docker.
- π Workspace Management β Organize images into workspaces (e.g., per article, per project).
- βοΈ S3-Compatible Storage β Works with AWS S3, DigitalOcean Spaces, Cloudflare R2, Wasabi, etc.
- πΌοΈ Gallery View β Browse images with skeleton loaders, lazy loading, and smooth View Transitions.
- π·οΈ Metadata Editing β Update alt text, captions, and sort order per image.
- βοΈ Background Worker β Handles heavy operations (rename/delete workspace with many assets) asynchronously.
- π‘οΈ Security β CSRF protection, brute-force rate limiting, secure session management.
- π¨ Dynamic Island β Real-time floating status pill for background job activity.
- π Dark/Light Mode β Fully responsive with theme toggle.
Request β Nginx β public/index.php (Front Controller)
β
Router.php
β
DI Container.php
β β
Controllers Services
β β
SQLite DB S3 Storage
Stack: PHP 8.4 (FPM) Β· SQLite Β· Nginx Β· Docker (3 services: app, web, worker)
# 1. Clone the repository
git clone https://github.com/mbahnizen/nizenvault.git
cd nizenvault
# 2. Configure environment
cp .env.example .env
# Edit .env β set ADMIN_PASSWORD and S3 credentials
# 3. Start the stack
docker compose up -d
# 4. Open in browser
# http://localhost:8000After cloning and configuring .env, the docker-compose.override.yml automatically mounts ./public and ./src into the container for live-reload β no rebuild needed for PHP/JS/CSS changes.
All API endpoints require authentication (session cookie) unless noted. Mutating endpoints also require the X-CSRF-TOKEN header.
| Method | Endpoint | Auth | Description |
|---|---|---|---|
POST |
/api/login |
β | Login with admin password |
GET |
/api/health |
β | System health check |
curl -X POST http://localhost:8000/api/login \
-H "Content-Type: application/json" \
-d '{"password":"your_admin_password"}'| Method | Endpoint | Description |
|---|---|---|
GET |
/api/list_assets?workspace_id=1 |
List assets in workspace (paginated) |
POST |
/api/upload |
Upload image to workspace |
POST |
/api/delete |
Soft-delete an asset |
POST |
/api/rename_asset |
Rename an asset (copies S3 object) |
POST |
/api/update_asset |
Update metadata (alt, caption, sort) |
POST |
/api/cleanup_deleted |
Purge soft-deleted assets older than N days |
curl -X POST http://localhost:8000/api/upload \
-H "X-CSRF-TOKEN: {token}" \
-b "PHPSESSID={session}" \
-F "file=@/path/to/image.jpg" \
-F "workspace_id=1" \
-F "filename=my-photo"curl http://localhost:8000/api/list_assets?workspace_id=1&page=1&limit=50 \
-b "PHPSESSID={session}"| Method | Endpoint | Description |
|---|---|---|
GET |
/api/workspaces |
List all workspaces |
POST |
/api/workspaces |
Create a new workspace |
POST |
/api/rename_workspace |
Rename workspace (may queue background job) |
POST |
/api/delete_workspace |
Delete workspace and its assets |
| Method | Endpoint | Description |
|---|---|---|
GET |
/api/workspace_jobs |
List all jobs |
GET |
/api/workspace_jobs_active |
List running/queued jobs |
GET |
/api/workspace_job_status?id=1 |
Get job status by ID |
POST |
/api/workspace_job_cancel |
Cancel a queued job |
POST |
/api/workspace_job_retry |
Retry a failed job |
POST |
/api/workspace_job_force_reset |
Force-reset a stale running job |
| Variable | Description | Default |
|---|---|---|
| App | ||
APP_ENV |
Environment mode | production |
APP_DEBUG |
Enable debug output | false |
LOG_CHANNEL |
Log target: stderr or file |
file |
| S3 Storage | ||
S3_ENDPOINT |
S3 API endpoint URL | Required |
S3_BUCKET |
Bucket name | Required |
S3_ACCESS_KEY |
Access key ID | Required |
S3_SECRET_KEY |
Secret access key | Required |
S3_REGION |
S3 region | id-jkt-1 |
S3_ACL |
Object ACL | public-read |
PUBLIC_URL_BASE |
Public base URL for assets | Required |
| Auth & Session | ||
ADMIN_PASSWORD |
Admin login password | Required |
SESSION_LIFETIME_SECONDS |
Session cookie lifetime | 43200 (12h) |
SESSION_IDLE_TIMEOUT_SECONDS |
Idle timeout before auto-logout | 7200 (2h) |
| Worker | ||
WORKSPACE_SYNC_THRESHOLD |
Max assets before queuing background job | 20 |
WORKSPACE_JOB_STALE_MINUTES |
Minutes before a running job is stale | 15 |
WORKER_SLEEP_SECONDS |
Worker polling interval | 2 |
nizenvault/
βββ public/ # Web root (only directory exposed by Nginx)
β βββ index.php # Front controller + SPA HTML
β βββ app.js # Client-side logic
β βββ app.css # Styles
βββ src/ # PHP source (PSR-4: App\)
β βββ Controller/ # Route handlers
β βββ Router.php # URL routing
β βββ Container.php # Dependency injection
β βββ Database.php # SQLite connection + schema
β βββ StorageService.php # S3 operations
β βββ bootstrap.php # App initialization
βββ scripts/ # CLI scripts
β βββ workspace_worker.php # Background job processor
βββ docker/ # Docker support files
β βββ nginx/default.conf
β βββ entrypoint.sh
βββ docker-compose.yml # Production stack
βββ docker-compose.override.yml # Dev overrides
βββ Dockerfile
βββ .env.example
Contributions are welcome! Please see CONTRIBUTING.md for guidelines.
MIT License β see LICENSE for details.