Explainability
Every blocked action should identify the checked resource, observed state, and corrective action.
Technical architecture baseline 2026.08
A source-backed engineering dossier for the supervised application container and its internal YouTube provider sidecar: authenticated request boundaries, explicit domain workflows, native NNTP and YouTube transfer, normalized persistence, failure recovery, filesystem policy, and verified production delivery.
Audited repository scale
Nooklet documentation
Move from product outcomes to daily operation to implementation evidence without losing context.
See what Nooklet does, how the complete media journey feels, and where its boundaries are.
Explore capabilities → 02 · UseInstall, reach a first request, understand season recovery, and resolve common problems.
Follow a task → 03 · EngineerTrace runtime boundaries, workflows, persistence, reliability, security, and release evidence.
Inspect the system ↓ 04 · ContributeTwelve breakdowns walking real files, from a form submission to the row it writes.
Follow a trace →Scope and constraints
Nooklet favors operability for a self-hosted instance over distributed scale. The architecture keeps one deployment unit while maintaining explicit domain boundaries, persisted workflow state, and recoverable failure semantics inside that unit.
Every blocked action should identify the checked resource, observed state, and corrective action.
Request, queue, import, job, and audit state survive process restarts in SQLite.
Secrets, outbound hosts, persisted result ownership, and filesystem roots are policy-bound.
One supervised application container owns the web runtime, worker, download engines, migrations, and health surface; one internal sidecar supplies YouTube proof-of-origin tokens.
| Concern | In scope | Not claimed | Reason |
|---|---|---|---|
| Deployment | One hardened application container | Horizontal multi-replica execution | Process-local locks and runtime singletons intentionally match the self-hosted model. |
| Downloads | Newznab + Nooklet's native Usenet downloader | Torrent protocol support | Automatic acquisition searches enabled Newznab sources only; a protocol guard remains as defense in depth. |
| Persistence | SQLite, validated migrations, operational-record retention, verified online backup | Automatic backup-file retention or off-host restore drills | Operational rows are bounded in-app; backup scheduling and off-host recovery remain operator policies. |
| Assurance | Automated, container, and signed-in browser verification | Formal security audit or WCAG certification | The dossier distinguishes observed evidence from broader assurance claims. |
Runtime and dependency architecture
Next.js handles delivery and authenticated interaction. Named workflows own use cases. Repositories own transactions. Typed adapters own protocols. The worker hosts the Usenet and YouTube runners, while their durable state remains outside process memory. Compose adds one internal YouTube proof-of-origin provider sidecar.
FIG 01 · SYSTEM CONTEXT
Nooklet container · supervised Node 24 processes
FIG 02 · DEPENDENCY DIRECTION
src/app · src/components
authenticate → validate → delegate
src/modules/*/workflows
Drizzle contracts · normalized IDs
typed capability boundaries
Runtime startup
The container supervisor applies the migration journal before
starting distinct web and worker children.
src/instrumentation.ts initializes the web database
client; the worker child owns the 15-second background loop and
native download engine.
HTTP surface
Most mutations use authenticated server actions. Three API route files cover narrow HTTP concerns, including health, rather than exposing a generic CRUD or upstream proxy API.
Domain ownership
The repository contains 147 production workflow files and 98 workflow test files across request, search, scan, import, recommendation, connection, and history domains.
Request, transfer, and import
The request path validates intent and ownership before acquisition, reserves local state before enqueue, compensates partial writes, and carries built-in transfer evidence into one conservative import pipeline.
FIG 03 · SEQUENCE TRACE
Media type, monitored scope, destination, quality, and download intent become a typed request.
Normal requests use five minutes; TV expansion uses two hours, while season recovery has a separate renewable 15-minute per-plan lease.
Only enabled Newznab sources enter automatic acquisition ranking; URLs are encrypted, user-owned, and expire after 24 hours.
A partial unique index rejects another active request for the same user and media target.
The URL origin must match the supplying indexer; fetch is bounded to 60 seconds and 50 MiB, then capacity is atomically reserved.
Segments are parallelized within one claimed release and progress is serialized into SQLite.
Samples are rejected, collisions are checked, and claimed hard-link or streamed copies retain their engine-owned source until persistence succeeds.
Import records preserve the outcome and queue a scan only for affected active destination paths.
FIG 04 · SEASON FULFILLMENT
download_request is one physical attempt. Failed or
intrinsically oversized releases are excluded within the plan; active
capacity contention waits without burning a release; current storage
pressure blocks for repair. Due work survives restart in SQLite, and
infrastructure faults stop fan-out. Source:
season fulfillment workflow.
FIG 05 · ENGINE STATE MODEL
queued | fetching →
paused → queued
queued;
incomplete bytes restart from the stored NZB.
failed with a
persisted reason.
importing state.
fetching, without a separate persisted
intermediate state.
Engine runner source.
Work + completed staging
/app/data/engine-work → /downloads/nooklet-engine/complete
High-concurrency incomplete, assembly, repair, and extraction I/O stays in the work root; finalized output crosses to completed staging with a sequential copy.
statfsPermanent storage
/media/movies
Only accepted primary media and confidently matched companion files are published into this root. Cross-filesystem copies report progress and recover only Nooklet-owned partials after interruption.
FIG 06 · CAPACITY POLICY
0.5 GiB + Σ(active total + remaining)
free - processing reservation
floor(available / 2)
| Failure point | Persisted outcome | Compensation or recovery | Source preservation |
|---|---|---|---|
| Capacity preflight | Request submission fails before engine creation | Exact path, available bytes, required bytes, and reserve are reported | No engine workspace created |
| Downloader accepted; local persistence failed | Reserved request becomes failed | Best-effort queue removal; manual cleanup warning if that also fails | Downloader cleanup attempted |
| Transfer or finalization | Engine row becomes failed with a phase-specific reason | Import maintenance evaluates retry and notification policy | Terminal input is consumed after outcome persistence |
| Retryable import | Import/request remains visible for attention or retry | Alternate-release search stops after three failed releases | Completed output remains until successful import or terminal handling |
| Missing engine queue row | Queue item and request become failed | A visible reason closes the formerly active request | Unknown; no queue-owned source remains |
Persistence and data integrity
Fifty Drizzle tables separate instance configuration, identity and session validity, intent, fulfillment state, Usenet and YouTube transfer state, import evidence, recommendations, history, jobs, notifications, credentials, and audit events. SQLite-specific behavior is embraced deliberately rather than hidden behind portability claims.
CHART 01 · SCHEMA COMPOSITION
sqliteTable definitions in
schema.ts. The categories explain responsibility; they are not storage-size
measurements.
FIG 07 · DOMAIN RELATIONSHIPS
Connection policy
synchronous=NORMALWrite invariants
Migration contract
ensureDatabaseReady applies the Drizzle journal when
its signature changes, then performs narrowly scoped compatibility
repairs and asserts the expected schema.
FIG 08 · MIGRATION TIMELINE
0000 through 0047. Migration
0033 deliberately repairs a known historical state using
idempotent DDL. The repository validator enforces contiguous tags, SQL
artifacts, and monotonic new timestamps.
Migration source.
Concurrency and recovery
The worker runs as a separately supervised process, but job ownership is not inferred from memory. Compare-and-set claims, random run tokens, expiring leases, heartbeats, and token-checked completion make stale work reclaimable.
CHART 02 · WORKER TIMING
FIG 09 · LEASE PROTOCOL
runToken, status, timestamps, and
lockedUntil
FIG 09B · CANCELLATION PROTOCOL
Maintenance lane
Five scheduled lanes
watch-history-syncmedia-library-scanrecommendation-runmissing-content-searchmetadata-refreshFailure isolation
Promise.allSettled, not fail-fast.An optional integration failure does not prevent unrelated job types or built-in import work from making progress. Failure context is persisted and reflected in health.
Security architecture
Nooklet treats browser input, configured service hosts, persisted result URLs, downloaded archives, and filesystem paths as separate trust boundaries. Controls are layered around the actual data flow.
FIG 10 · TRUST BOUNDARIES
Scroll horizontally to compare control coverage on a narrow screen.
| Control | Identity | Stored data | Network | Filesystem | Operations |
|---|---|---|---|---|---|
| Local identity + lockout | Primary | - | Supporting | - | Supporting |
| Temporary-password recovery | Primary | Supporting | - | - | Primary |
| AES-256-GCM secret envelopes | Supporting | Primary | Supporting | - | Supporting |
| SSRF-aware safe fetch | - | Supporting | Primary | - | Supporting |
| Approved-root policy | - | Supporting | - | Primary | Supporting |
| Backup, health, audit | Supporting | Supporting | - | Supporting | Primary |
Primary = directly enforced at that surface. Supporting = contributes defense in depth.
Identity
Passwords use scrypt and timing-safe comparison. Login and bootstrap are throttled. Disabled users and password changes invalidate otherwise live sessions; temporary passwords require replacement. Encrypted JWT cookies also require an active per-login SQLite record and the user's current monotonic authentication generation, so sign-out remains final when an older response arrives late and a pending login cannot survive password or disable/re-enable invalidation. Legacy tokens without every claim fail closed.
Secrets
AES-256-GCM envelopes use HKDF-SHA256-derived keys. A dedicated
SECRET_BOX_KEY is preferred, and previous keys support
lazy read-and-rewrite rotation.
Outbound network
safeFetch permits HTTP(S), rejects URL credentials,
classifies all resolved addresses, pins validated DNS results,
refuses redirects, and enforces duration and body limits.
Filesystem + archives
Media roots fail closed when unconfigured. Filesystem roots, device/network paths, symlinks, escaped files, unsafe archive entries, and unbounded extraction trees are rejected.
Deployment and operations
The production image is multi-stage and runs as a non-root user behind
tini. Compose drops Linux capabilities, enables
no-new-privileges, binds to loopback by default, and makes
persistent/mounted state visible.
FIG 11 · DEPLOYMENT TOPOLOGY
Nooklet application container
USER node · tini -g · port
42021
Observe
/api/health
The public probe returns only database, worker, and engine status.
Database failure or a stale/stopped worker returns 503; authenticated
/health owns timestamps, counts, stages, and private
errors.
Protect
The source and completed copy both pass SQLite quick_check;
the command refuses overwrite and restricts permissions where supported.
Package
Source, tests, environment files, local databases, private keys, and local tooling state are removed; every journaled migration must remain.
Recover
The recovery command resets one selected local administrator, clears lockout state, audits the event, and requires password replacement.
npm ci
npm run check
docker build --tag nooklet:verified .
npm run db:backup
npm run account:recover -- admin@example.com
Simple deployment and backup semantics; no multi-replica safety claim.
Excellent local operability; one local persistent volume and one write coordinator.
One release globally at a time; NNTP segments parallelize inside that release.
Queued intent survives; interrupted transfer bytes restart rather than resume.
Nooklet's built-in engine owns transfer, progress, cancellation, and completion state.
TLS, mounts, backup retention, and off-host recovery stay explicit operator decisions.
Engineering evidence
Counts describe the audited source baseline; they are not code-coverage percentages. Verification evidence is separated by the question each gate answers.
CHART 03 · DOMAIN ENGINEERING DENSITY
src/modules
src tree contains 831
TypeScript/TSX files, including 260 test files.
FIG 12 · RELEASE PROOF LADDER
Is source quality structurally clean?
PassedDo TypeScript contracts compose?
PassedDo workflow, policy, component accessibility, and first-run browser behaviors hold?
238 Vitest/Node files + 1 Playwright specCan the standalone artifact be assembled and sanitized?
PassedDoes the hardened runtime start and report healthy?
PassedCan a user bootstrap, sign in, reach Home, and avoid serious/critical accessibility violations?
Chromium smokeCan key workflows be understood and operated responsively?
Desktop + mobilesrc831 TypeScript/TSX · 571 production · 260 test
src/app; sign-out lives under
src/components/layout.
49432fb20,879 additions · 7,178 deletions.
Scroll horizontally to inspect implementation traceability on a narrow screen.
| Concern | User surface | Owning implementation | Primary evidence |
|---|---|---|---|
| Explainable capacity | Storage + request errors |
get-storage-overviewenqueue-nzb-download
|
Capacity workflow tests + signed-in QA |
| Capability readiness | Home + Setup Center |
readiness evaluator
|
Evaluator tests + browser QA |
| Owned download request | Search + Discover |
queue-indexer-result
|
Phase tests + database uniqueness |
| Resilient season intent | Library + Activity |
season-fulfillmentfulfillment repository
|
State-machine, persistence, fallback, and migration tests |
| Verified cancellation | Activity |
request cancellationseason cancellation
|
Checkpoint, lease, built-in cleanup, and retry-backoff tests |
| Native transfer | Activity |
engine-runnerdownload-nzb
|
Fake NNTP integration tests + queue tests |
| Conservative import | Activity + Library |
file-organizationfile-transferimport-file-policy
|
Policy, collision, durable claim recovery, progress, rollback, and multipart tests |
| Job recovery | Automation + Health |
job-repositoryworker
|
Lease, heartbeat, stale-claim, and deferred-run tests |
| Network trust | Connections + Indexers |
safe-fetch
|
Address-classification, timeout, redirect, and size tests |
| Production delivery | Container runtime |
Dockerfileci.yml
|
Build + hardened health smoke |
Decision record
Defines the modular-monolith shape, normalized data, typed adapter boundaries, and the single supervised application-container constraint.
ADR 0002 · acceptedEstablishes engine-owned queue state and the standalone direction; current-runtime differences are called out in this dossier.
ADR 0003 · acceptedSeparates the user's season outcome from physical attempts, with classified pack retry, episode fallback, and restart-safe recovery.
Product contractConnects observable product behavior to its owning workflows instead of a specific screen implementation.
Engineering conclusion
Nooklet keeps operational topology compact while making boundaries, persistence, recovery, trust, and failure semantics explicit. The result is a self-hosted system that can explain what it is doing and leave enough evidence to diagnose what happened.