Skip to content

Latest commit

 

History

53 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

/dev/null

License: AGPL-3.0 PHP Nextcloud Vue.js Python

Nextcloud app for external disk auto-ingest: detect, mount, scan, deduplicate, classify.

"Where your data goes to live."

— Named after /dev/null, the Unix black hole where data goes to die. This app does the opposite.

Note

DevNull v0.5.0 is published on the Nextcloud App Store.

What is this?

DevNull transforms your Nextcloud server into a central ingest point for external drives. Plug in a disk, click mount, and your server detects, mounts, scans, deduplicates, and classifies — all from the web interface. No terminal required.

Built for the person with 10+ external drives in a drawer, full of photos and documents that deserve an organized life.

Status

Component Status Notes
Disk detection (lsblk) 🟢 Working Recursive, filters system partitions
Web UI (Vue.js) 🟢 Working Disk cards, mount/eject/process buttons, badges
Mount via udisks2 🟢 Working www-data with polkit, handles AlreadyMounted
Eject (unmount) 🟢 Working Removes NC external storage by saved ID
Storage registration 🟢 Working PHP API (GlobalStoragesService), no subprocess
File scan (auto) 🟢 Working \OC\Files\Utils\Scanner (NC 34 compatible)
Ingest pipeline 🟢 Working Scan (sync) + Dedup/Classify (background jobs)
Permissions 🟢 Working Admin mounts; users see shared storage
Error handling 🟢 Working Consistent {success, error, code} + HTTP status
Notifications 🟢 Working NC notification panel (mount, ingest, hotplug)
Auto-classify 🟢 Working Triggers Recognize after scan (configurable)
Dashboard widget 🟢 Working IAPIWidgetV2 on NC home screen
Admin settings 🟢 Working Automation rules in NC admin panel
Daemon (hotplug) 🟢 Working Python + pyudev, SSE, webhook bridge
DB schema 🟢 Working 3 tables (disks, operations, mounts)
App Store 🟢 Published apps.nextcloud.com/apps/devnull

Features

  • Detect USB/external drives connected to the server
  • List disks in Nextcloud UI (name, size, filesystem, model, serial)
  • One-click mount via udisks2 (no root required)
  • One-click eject with --force
  • Auto-register as Nextcloud external storage on mount
  • Auto file scan after mount (content visible immediately)
  • Auto-remove external storage on eject (clean lifecycle)
  • Ingest pipeline: scan → deduplicate → classify (AI)
  • Background job scheduling for heavy operations (dedup, classify)
  • Auto-classify via Recognize after scan (configurable)
  • Nextcloud notifications (mount complete, ingest complete, disk detected)
  • Dashboard widget (mounted disks + recent ops on NC home)
  • Admin settings page (automation rules, daemon config)
  • Python daemon with hotplug detection (pyudev + polling fallback)
  • SSE real-time events endpoint
  • Webhook bridge (daemon → NC app)
  • Auto-mount on plug (configurable)
  • Deploy script (scripts/deploy.sh)
  • Automated test suite (scripts/test.sh)
  • Filter system partitions (/, /boot, swap)
  • .devnull marker file on mounted disks
  • PHPStan level 5 compliance
  • Structured error responses with error codes
  • Nextcloud App Store publication

Architecture

DevNull/
├── app/                           # Nextcloud PHP app
│   ├── appinfo/                   # info.xml, routes.php
│   ├── lib/
│   │   ├── AppInfo/               # Bootstrap + DI (IBootstrap)
│   │   ├── Capability/            # Interfaces (DiskDetector, MountStrategy, StorageRegistrar)
│   │   ├── Command/               # SecureCommandRunner (whitelisted exec)
│   │   ├── Controller/            # OCS API (Disk, Mount, Ingest, Status, Operation, Daemon, Settings)
│   │   ├── Dashboard/             # NC Dashboard widget (IAPIWidgetV2)
│   │   ├── Detection/             # LsblkDetector, DetectorFactory
│   │   ├── Event/                 # DiskMounted, DiskUnmounted, IngestCompleted
│   │   ├── Ingest/                # Pipeline + Steps (Scan, Deduplicate, Classify)
│   │   ├── Listener/              # TriggerScanOnMount, LogOnUnmount, NotifyOnIngestComplete
│   │   ├── Migration/             # DB schema (disks, operations, mounts)
│   │   ├── Mount/                 # UdisksMountStrategy, SudoMountStrategy, NullMountStrategy
│   │   ├── Notification/          # Notifier + NotificationService
│   │   ├── Bridge/                # HttpDaemonClient, NullDaemonClient
│   │   ├── Settings/              # AdminSection, AdminSettings
│   │   └── Storage/               # NextcloudStorageRegistrar (PHP API + auto-classify)
│   ├── src/                       # Vue.js frontend
│   │   ├── components/            # DiskCard, DiskList, OperationLog (dashboard)
│   │   └── App.vue
│   ├── templates/                 # Admin settings page
│   └── js/                        # Built frontend bundle
├── daemon/                        # Python daemon (optional enhancer)
│   ├── devnull_daemon/
│   │   ├── api/                   # FastAPI REST + SSE
│   │   ├── detection/             # UdevMonitor + polling fallback
│   │   ├── mount/                 # Strategy pattern (udisks, sudo)
│   │   ├── notifications/         # Webhook notifier → NC app
│   │   ├── events.py              # EventBus (async pub/sub)
│   │   └── models/                # Pydantic models
│   └── systemd/                   # Service unit
├── scripts/
│   ├── deploy.sh                  # One-command deploy
│   └── test.sh                    # Automated test suite
└── docs/                          # Audit reports, continuation prompts

Tech Stack

  • Backend: PHP 8.2+ / Nextcloud App Framework 28–35
  • Frontend: Vue.js 3.5 / @nextcloud/vue 9 / Vite 6
  • Daemon: Python 3.11+ / FastAPI / pyudev / httpx
  • Mount: udisks2 (userspace, polkit) or sudo mount (fallback)
  • Detection: lsblk --json (PHP) / pyudev real-time (daemon)
  • Storage: files_external GlobalStoragesService (PHP API)
  • Scan: \OC\Files\Utils\Scanner (NC 34+, IUser + SetupManager)
  • Jobs: IJobList for dedup/classify/Recognize scheduling
  • Notifications: OCP\Notification\IManager
  • Dashboard: IAPIWidgetV2 + IReloadableWidget

Quick Deploy

# On the server
cd /opt/devnull && git pull && sudo bash scripts/deploy.sh

# With daemon (hotplug detection)
cd /opt/devnull && git pull && sudo bash scripts/deploy.sh --with-daemon

# Run tests
export DEVNULL_TEST_PASS='your-nc-password'
bash /opt/devnull/scripts/test.sh

API Endpoints

Method Path Auth Description
GET /api/v1/disks User List detected disks
POST /api/v1/mount Admin Mount a device
POST /api/v1/unmount Admin Eject a device
POST /api/v1/ingest Admin Start ingest pipeline
GET /api/v1/ingest/steps User List available steps
GET /api/v1/status User Current mount/operation status
GET /api/v1/logs User Operation history
GET /api/v1/settings Admin Get automation settings
PUT /api/v1/settings Admin Update automation settings
POST /api/v1/daemon/event Token Daemon webhook receiver
GET /api/v1/daemon/config Token Daemon self-configuration

Daemon API (port 9876)

Method Path Auth Description
GET /api/v1/health Health check
GET /api/v1/disks Token List available disks
POST /api/v1/mount Token Mount a device
POST /api/v1/unmount Token Unmount a device
GET /api/v1/events SSE real-time stream
GET /api/v1/events/history Token Recent event history

Contributing

Contributions welcome. Areas where help is needed:

  1. Testing — PHPUnit tests for controllers and services
  2. New mount strategies — Docker volumes, NFS, CIFS
  3. Device support — testing with different USB enclosures
  4. Platform support — Ubuntu, Fedora, Arch variations
  5. Frontend — Vue.js admin settings component

License

AGPL-3.0

About

/dev/null — Where your data goes to live. Nextcloud app for external disk auto-ingest: detect, mount, scan, deduplicate, classify. Published on the App Store.

Topics

Resources

Contributing

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages