Noema is a zero-runtime-dependency, self-hosted personal workspace built with Node.js, the built-in SQLite module, plain HTML, CSS and JavaScript. It brings tasks, notes, documents, links, files, project galleries, calendar events, MCP tools and OpenAPI routes into one private interface.
Current public line: 0.3.x — encrypted-at-rest storage, one-password browser login, revocable server-side sessions, static-only Service Worker caching, encrypted disaster-recovery backups and a hardened Docker deployment.
All screenshots below are generated automatically from a clean checkout with neutral demo data. The screenshot job refuses to run when data/ contains user data.
| Notes | Documents |
|---|---|
![]() |
![]() |
| Links | Inspiration |
|---|---|
![]() |
![]() |
More neutral screenshots are kept in docs/screenshots/, including Building Sites, AI Projects, Stats, Backup, Help, Login and the 404 page.
- Yesterday / today / tomorrow task board with priority, time, subtasks, archive, drag-and-drop ordering and stable recurring tasks.
- Notes, documents, Links, AI Projects, Building Sites, Inspiration, Stats and a private Files library.
- Private-data encryption at rest: record payloads and managed private binary content remain encrypted in persistent storage.
- Files metadata is encrypted in SQLite; new Files uploads are encrypted incrementally into authenticated 1 MB chunks below
NOEMA_DATA_DIR/files, with a 120 MB per-file limit and HTTP Range downloads. - Legacy Files/base64 records remain readable for compatibility while browser uploads can use the bounded-memory raw streaming routes.
- Document uploads, Building Site/Inspiration media and previously generated Links thumbnails are stored encrypted below
NOEMA_DATA_DIR. - Source-linked tasks from Notes, Documents, Links, Files, galleries and AI Projects.
- One responsive navigation system, active-page highlighting, light/dark mode, font scaling and persistent WIDTH control.
- Google Calendar read-only integration with encrypted refresh-token storage and session-bound OAuth state.
- MCP and OpenAPI endpoints for authenticated machine clients.
- Opaque, revocable browser sessions with idle/absolute expiration.
- Trusted-proxy handling, production security headers and bounded login/API rate limiting.
- Expiring, revocable and scope-limited gallery-share links.
- Password-encrypted
.noemadisaster-recovery archives protected by a separate backup password. - Static-only Service Worker caching: private/API/gallery/file/backup responses are network-only and never intentionally persisted in browser Cache Storage.
- Docker build tests, encrypted-storage regression tests, recurrence/DST coverage, security checks and a strict production startup smoke test.
Noema follows one persistent-storage rule:
Everything the user enters, uploads, or Noema generates from private user data is encrypted at rest.
A random 256-bit installation data key encrypts application data with AES-256-GCM. UI_PASSWORD is the single password entered in the browser: it authenticates the UI and protects the random installation key stored in wrapped form in NOEMA_DATA_DIR/master.key. The password itself is not the AES data key.
Browser authentication is owned by src/security-gateway.js. Noema does not use HTTP Basic Auth and does not send WWW-Authenticate challenges. Successful login creates an opaque random session token; only a hash and encrypted session metadata are stored.
This is server-side encryption at rest, not end-to-end encryption. An authorized running Noema process can decrypt data to serve it. The model protects persistent/offline storage exposure, not a fully compromised running host.
See SECURITY.md, PRIVACY.md and ARCHITECTURE.md.
- Node.js 22.16+ for direct execution, or Docker.
- Persistent storage for
NOEMA_DATA_DIR. - HTTPS for an Internet-facing production deployment.
zipandunzipfor full backup/restore outside the provided container.
No runtime npm dependencies are required by Noema itself.
Serving existing encrypted thumbnails remains supported. Automatic browser-based thumbnail generation is intentionally disabled in the main Noema container because launching a general-purpose browser against user-controlled URLs requires stronger DNS/network isolation than the application process can safely provide. A future isolated renderer can restore generation without weakening the main container.
cp .env.example .env
# Set UI_PASSWORD for the normal browser-login path.
# For an isolated local test only, you may instead set:
# ALLOW_INSECURE_NO_AUTH=true
npm run check
npm startOpen http://localhost:3000.
Production fails closed unless authentication and HTTPS-related settings are valid. At minimum:
NODE_ENV=production
PUBLIC_BASE_URL=https://noema.example.com
NOEMA_CORS_ORIGIN=https://noema.example.com
UI_PASSWORD=replace-with-a-strong-master-password
NOEMA_API_TOKEN=replace-with-a-long-random-machine-token
NOEMA_BACKUP_PASSWORD=replace-with-a-separate-long-backup-passwordFor a new production installation, UI_PASSWORD must be strong and NOEMA_API_TOKEN must be a separate long secret. ALLOW_INSECURE_NO_AUTH=true is development-only.
Existing installations that still use a legacy ENCRYPTION_KEY should keep it only during the controlled migration. Remove it after a successful restart/login/data validation cycle.
See DEPLOYMENT.md for reverse-proxy, Docker, upgrades and backups.
docker build -t noema .
docker run --rm -p 3000:3000 \
-v noema-data:/app/data \
--env-file .env \
noemaThe supplied image uses Node 24 Alpine, runs the complete project checks under isolated test configuration, performs a strict production startup/health smoke test and removes npm/corepack/yarn from the final runtime image.
Primary metadata lives in NOEMA_DATA_DIR/noema.sqlite; private record payloads are encrypted before insertion. Managed binary data lives in encrypted directories such as:
files/
uploads/
buildingsites/
inspirations/
link-thumbnails/
Large managed media uses independently authenticated chunks so authorized byte ranges can be reconstructed without storing plaintext copies in a public directory. The reader remains compatible with the earlier NOEMA-ASSET-V1 chunk envelope while new writes use the compact raw AES-GCM chunk layout.
Create a full encrypted archive:
npm run backup -- ./noema-backup.noemaRestore while Noema is stopped:
npm run restore -- ./noema-backup.noema /path/to/restored-dataA full .noema archive includes the complete persistent data set, including SQLite, master.key, encrypted binary media and compatibility state, then adds a second encryption layer using NOEMA_BACKUP_PASSWORD.
Portable JSON export is different: it is readable metadata intended for inspection/migration and does not include the complete binary data set.
| Route | Purpose |
|---|---|
/ |
Task board and calendar |
/notes |
Notes |
/documents |
Documents and checklists |
/links |
Visual bookmarks |
/files |
Private file library |
/ai-projects |
AI project catalog |
/buildingsite |
Project/site galleries |
/inspiration |
Reference galleries |
/stats |
Optional analytics dashboard |
/backup |
Metadata/full-backup controls |
/help |
In-app help |
/openapi.json |
OpenAPI description |
/mcp |
MCP Streamable HTTP endpoint |
/healthz |
Unauthenticated health check |
npm run check validates the application itself. Public repository screenshots are generated separately with Playwright by .github/workflows/screenshots.yml.
The screenshot generator:
- refuses to run if
data/contains anything; - starts a temporary Noema instance with test-only credentials;
- creates neutral demo Notes/Documents/Links/galleries;
- captures the public UI at desktop size;
- tears down the test data directory;
- commits only
docs/screenshots/*.pngback to the documentation branch.
This keeps README imagery reproducible without exposing a real installation.
- PRODUCT.md — product scope and behavior
- ARCHITECTURE.md — request layers, storage and runtime architecture
- CUSTOMIZATION.md — UI/module customization
- DEPLOYMENT.md — Docker, reverse proxies, upgrades and backups
- SQLITE_MIGRATION.md — storage format and migration
- PRIVACY.md — data flows and browser/storage privacy
- SECURITY.md — security model and vulnerability reporting
- CONTRIBUTING.md — development workflow
- SUPPORT.md — troubleshooting
- CHANGELOG.md — release history
- E2EE_ROADMAP.md — optional future client-side E2EE direction
MIT. See LICENSE.





