diff --git a/backend/server.py b/backend/server.py
index 56fddd0..3d04070 100644
--- a/backend/server.py
+++ b/backend/server.py
@@ -3601,6 +3601,38 @@ class CRMHandler(BaseHTTPRequestHandler):
}
except Exception:
out['source_counts'] = None
+ # Storage usage — DB file(s), email attachments, backups, and disk headroom,
+ # so growth can be watched over time. Best-effort; never fails the status call.
+ try:
+ import shutil
+
+ def _fsize(p):
+ try:
+ return os.path.getsize(p)
+ except OSError:
+ return 0
+
+ def _dirsize(d):
+ total = 0
+ for root, _dirs, files in os.walk(d):
+ for f in files:
+ try:
+ total += os.path.getsize(os.path.join(root, f))
+ except OSError:
+ pass
+ return total
+
+ du = shutil.disk_usage(DATA_DIR)
+ out['storage'] = {
+ 'database_bytes': sum(_fsize(DB_PATH + s) for s in ("", "-wal", "-shm")),
+ 'attachments_bytes': _dirsize(os.path.join(DATA_DIR, "email_attachments")),
+ 'backups_bytes': _dirsize(os.path.join(DATA_DIR, "backups")),
+ 'disk_total_bytes': du.total,
+ 'disk_used_bytes': du.used,
+ 'disk_free_bytes': du.free,
+ }
+ except Exception:
+ out['storage'] = None
conn.close()
self.send_json({"data": out})
diff --git a/frontend/index.html b/frontend/index.html
index 841d095..4e0f0d7 100644
--- a/frontend/index.html
+++ b/frontend/index.html
@@ -10258,6 +10258,15 @@
if (error) return
Index Actions
diff --git a/start9/0.4/startos/utils.ts b/start9/0.4/startos/utils.ts
index 27506ac..c0c2e79 100644
--- a/start9/0.4/startos/utils.ts
+++ b/start9/0.4/startos/utils.ts
@@ -27,8 +27,9 @@ export const PACKAGE_TITLE = 'Ten31 Database'
// * 0.1.0:59 (Email Capture admin panel + matched email into the grounding corpus)
// * 0.1.0:60 (Email Capture: single-mailbox enroll field for testing)
// * 0.1.0:61 (Email Capture: live backfill progress + auto-refresh)
-// * Current: 0.1.0:62 (fix backfill crash on no-Reply-To emails; Sync now retries errored mailboxes)
-export const PACKAGE_VERSION = '0.1.0:62'
+// * 0.1.0:62 (fix backfill crash on no-Reply-To emails; Sync now retries errored mailboxes)
+// * Current: 0.1.0:63 (System Status: storage usage — DB, attachments, backups, disk free)
+export const PACKAGE_VERSION = '0.1.0:63'
export const DATA_MOUNT_PATH = '/data'
export const WEB_PORT = 8080
diff --git a/start9/0.4/startos/versions/index.ts b/start9/0.4/startos/versions/index.ts
index 5da9d9d..8401642 100644
--- a/start9/0.4/startos/versions/index.ts
+++ b/start9/0.4/startos/versions/index.ts
@@ -23,8 +23,9 @@ import { v_0_1_0_59 } from './v0.1.0.59'
import { v_0_1_0_60 } from './v0.1.0.60'
import { v_0_1_0_61 } from './v0.1.0.61'
import { v_0_1_0_62 } from './v0.1.0.62'
+import { v_0_1_0_63 } from './v0.1.0.63'
export const versionGraph = VersionGraph.of({
- current: v_0_1_0_62,
- other: [v_0_1_0_39, v_0_1_0_40, v_0_1_0_41, v_0_1_0_42, v_0_1_0_43, v_0_1_0_44, v_0_1_0_45, v_0_1_0_46, v_0_1_0_47, v_0_1_0_48, v_0_1_0_49, v_0_1_0_50, v_0_1_0_51, v_0_1_0_52, v_0_1_0_53, v_0_1_0_54, v_0_1_0_55, v_0_1_0_56, v_0_1_0_57, v_0_1_0_58, v_0_1_0_59, v_0_1_0_60, v_0_1_0_61],
+ current: v_0_1_0_63,
+ other: [v_0_1_0_39, v_0_1_0_40, v_0_1_0_41, v_0_1_0_42, v_0_1_0_43, v_0_1_0_44, v_0_1_0_45, v_0_1_0_46, v_0_1_0_47, v_0_1_0_48, v_0_1_0_49, v_0_1_0_50, v_0_1_0_51, v_0_1_0_52, v_0_1_0_53, v_0_1_0_54, v_0_1_0_55, v_0_1_0_56, v_0_1_0_57, v_0_1_0_58, v_0_1_0_59, v_0_1_0_60, v_0_1_0_61, v_0_1_0_62],
})
diff --git a/start9/0.4/startos/versions/v0.1.0.63.ts b/start9/0.4/startos/versions/v0.1.0.63.ts
new file mode 100644
index 0000000..5ed1b63
--- /dev/null
+++ b/start9/0.4/startos/versions/v0.1.0.63.ts
@@ -0,0 +1,15 @@
+import { VersionInfo } from '@start9labs/start-sdk'
+
+// System Status now shows a Storage section: database file size, email attachments,
+// backups, and disk free/total — so growth can be watched over time. Read-only,
+// best-effort (never fails the status call). No schema migration.
+export const v_0_1_0_63 = VersionInfo.of({
+ version: '0.1.0:63',
+ releaseNotes: {
+ en_US: [
+ 'System Status now shows storage usage: how much space the database, email attachments,',
+ 'and backups are using, plus free disk on the server, so you can watch it grow over time.',
+ ].join(' '),
+ },
+ migrations: { up: async () => {}, down: async () => {} },
+})