{"id":46638204,"url":"https://github.com/tetherto/miningos-app-node","last_synced_at":"2026-03-08T02:13:07.331Z","repository":{"id":335332458,"uuid":"1129676249","full_name":"tetherto/miningos-app-node","owner":"tetherto","description":null,"archived":false,"fork":false,"pushed_at":"2026-03-05T10:23:24.000Z","size":210,"stargazers_count":1,"open_issues_count":2,"forks_count":8,"subscribers_count":1,"default_branch":"main","last_synced_at":"2026-03-05T12:54:58.573Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/tetherto.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-01-07T12:28:41.000Z","updated_at":"2026-02-03T07:21:33.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/tetherto/miningos-app-node","commit_stats":null,"previous_names":["tetherto/miningos-app-node"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/tetherto/miningos-app-node","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tetherto%2Fminingos-app-node","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tetherto%2Fminingos-app-node/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tetherto%2Fminingos-app-node/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tetherto%2Fminingos-app-node/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/tetherto","download_url":"https://codeload.github.com/tetherto/miningos-app-node/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tetherto%2Fminingos-app-node/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":30242406,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-03-08T00:58:18.660Z","status":"online","status_checked_at":"2026-03-08T02:00:06.215Z","response_time":56,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2026-03-08T02:13:06.819Z","updated_at":"2026-03-08T02:13:07.316Z","avatar_url":"https://github.com/tetherto.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# miningos-app-node\n\n## Table of Contents\n\n1. [Overview](#overview)\n2. [Architecture](#architecture)\n3. [Quick Start](#quick-start)\n4. [Configuration](#configuration)\n5. [API Reference](#api-reference)\n\n---\n\n## Overview\n\n### Purpose\n\n`miningos-app-node` serves as the **HTTP API gateway** for MiningOS. \n\n### Key Features\n\n- **HTTP API Gateway** - RESTful fastify APIs\n- **OAuth2 Authentication** (Google) with token-based authorization\n- **Role-Based Access Control (RBAC)** - Multiple user roles with granular permissions\n- **Multi-Cluster RPC** - Communicates with multiple orchestrator clusters via DHT-based RPC\n- **Request Caching** - Configurable LRU caching (10s, 15s, 30s, 15m TTLs)\n- **Request Deduplication** - Prevents duplicate concurrent requests\n- **Audit Logging** - Comprehensive logging of user management and security events\n- **Schema Validation** - JSON Schema validation for all endpoints (Fastify)\n\n---\n\n## Architecture\n\n### Technology Stack\n\n| Component | Technology | Purpose |\n|-----------|-----------|---------|\n| **Runtime** | Node.js ≥20 | JavaScript execution environment |\n| **Base Framework** | tether-wrk-base | P2P networking and storage foundation |\n| **Web Framework** | Fastify | High-performance HTTP server |\n| **P2P Network** | Hyperswarm | DHT-based peer-to-peer networking |\n| **P2P Storage** | Hyperbee | Distributed append-only B-tree |\n| **Authentication** | svc-facs-auth + OAuth2 | Token-based auth with Google OAuth |\n| **Local DB** | SQLite (bfx-facs-db-sqlite) | User management and session storage |\n| **Caching** | LRU (bfx-facs-lru) | In-memory request caching |\n| **Logging** | Pino (svc-facs-logging) | Structured JSON logging with transport |\n| **Testing** | Brittle | Modern TAP test runner |\n\n### Data Flow\n\n1. **Client Request** → HTTP API (Fastify)\n2. **Authentication** → Token validation (cached, 1-minute TTL)\n3. **Authorization** → Permission check (role + capability)\n4. **Cache Check** → LRU cache lookup (if applicable)\n5. **Request Deduplication** → Queue identical concurrent requests\n6. **RPC Aggregation** → Parallel DHT-based RPC requests to ORK clusters (max 2 concurrent)\n7. **Response Aggregation** → Merge results from multiple ORKs\n8. **Cache Update** → Store result in LRU cache\n9. **Audit Log** → Log sensitive operations (if enabled)\n10. **Response** → JSON response to client\n\n---\n\n## Quick Start\n### Prerequisites\n\n- Node.js ≥20.0\n- npm\n- Git\n\n### Installation\n\n```bash\n# Clone the repository\ngit clone https://github.com/tetherto/miningos-app-node.git\ncd miningos-app-node\n\n# Install dependencies\nnpm install\n\n# Setup configuration files\n./setup-config.sh\n\n# (Optional) Include test configuration\n./setup-config.sh --test\n```\n\n### Basic Configuration\n\n#### 1. Common Configuration\n\nEdit `config/common.json`:\n\n```json\n{\n  \"dir_log\": \"logs\",\n  \"debug\": 0,\n  \"site\": \"production-site-01\",\n  \"ttl\": 300,\n  \"staticRootPath\": \"/path/to/mos-app-ui/build/\",\n  \"orks\": {\n    \"cluster-1\": {\n      \"rpcPublicKey\": \"YOUR_ORK_RPC_PUBLIC_KEY_HERE\"\n    },\n    \"cluster-2\": {\n      \"rpcPublicKey\": \"YOUR_ORK_RPC_PUBLIC_KEY_HERE\"\n    }\n  },\n  \"cacheTiming\": {\n    \"/auth/list-things\": \"30s\",\n    \"/auth/tail-log\": \"15s\",\n    \"/auth/global/data\": \"15m\",\n    \"/auth/actions\": \"10s\"\n  },\n  \"featureConfig\": {}\n}\n```\n\n**Configuration Notes:**\n- **`dir_log`**: Directory for log files (required)\n- **`ttl`**: Token time-to-live in seconds (default: 300 = 5 minutes)\n- **`staticRootPath`**: Path to the UI build directory (required if serving frontend)\n- **`cacheTiming`**: Per-endpoint cache TTL values (available: \"10s\", \"15s\", \"30s\", \"15m\")\n- **`featureConfig`**: Feature flags (see `config/common.json.example` for all available options)\n\n#### 2. OAuth2 Configuration\n\nEdit `config/facs/httpd-oauth2.config.json`:\n\n```json\n{\n  \"h0\": {\n    \"method\": \"google\",\n    \"credentials\": {\n      \"client\": {\n        \"id\": \"YOUR_GOOGLE_CLIENT_ID\",\n        \"secret\": \"YOUR_GOOGLE_CLIENT_SECRET\"\n      }\n    },\n    \"users\": [\n      { \"email\": \"admin@yourcompany.com\", \"write\": true },\n      { \"email\": \"operator@yourcompany.com\", \"write\": true },\n      { \"email\": \"viewer@yourcompany.com\", \"write\": false }\n    ]\n  }\n}\n```\n\n#### 3. Authentication \u0026 Roles Configuration\n\nSet superAdmin email in `config/facs/auth.config.json` (see full example in Configuration section)\n\n### Running the Service\n\n```bash\n# Development mode\nnode worker.js --wtype wrk-node-http --env development --port 3000\n\n# Production mode\nnode worker.js --wtype wrk-node-http --env production --port 3000\n\n# With debug logging\nDEBUG=\"*\" node worker.js --wtype wrk-node-http --env development --port 3000\n```\n\n---\n\n## Configuration\n\n**Note:** Configuration files are created by running `./setup-config.sh`, which copies `.example` files to actual config files.\n\n### Configuration Details\n\n#### `config/common.json`\n\n```json\n{\n  \"debug\": 0,\n  \"site\": \"production-site-01\",\n  \"staticRootPath\": \"/home/user/dev/mos-app-ui/build/\",\n  \"ttl\": 300,\n  \"dir_log\": \"logs\",\n  \"orks\": {\n    \"cluster-1\": { \"rpcPublicKey\": \"abc123...\" },\n    \"cluster-2\": { \"rpcPublicKey\": \"def456...\" }\n  },\n  \"cacheTiming\": {\n    \"/auth/list-things\": \"15s\",\n    \"/auth/tail-log\": \"15s\",\n    \"/auth/actions/batch\": \"30s\",\n    \"/auth/actions/:type\": \"30s\",\n    \"/auth/actions/:type/:id\": \"30s\",\n    \"/auth/global/data\": \"30s\"\n  },\n  \"featureConfig\": {\n    \"comments\": true,\n    \"inventory\": false,\n    \"lvCabinetWidgets\": true,\n    \"poolStats\": true,\n    \"powerAvailable\": true,\n    \"reporting\": true,\n    \"settings\": true,\n    \"isOneMinItvEnabled\": false,\n    \"powerModeTimeline\": false,\n    \"totalSystemConsumptionChart\": false,\n    \"exportHistKpiDashboard\": false,\n    \"showMinerConsumptionDashboard\": false,\n    \"totalSystemConsumptionHeader\": false,\n    \"energyProvision\": true\n  }\n}\n```\n\n**Fields:**\n- `debug`: Debug level (0 = info, 1+ = debug)\n- `site`: Site identifier for this node\n- `staticRootPath`: Path to static UI files served by HTTP server\n- `ttl`: Authentication token TTL in seconds (default: 300)\n- `dir_log`: Log directory path\n- `orks`: Map of ORK cluster names to RPC public keys\n- `cacheTiming`: Cache TTL per endpoint (available TTLs: 10s, 15s, 30s, 15m)\n- `featureConfig`: Static feature flags for enabling/disabling UI features\n\n**Cache Timing Notes:**\n- Use endpoint paths as keys (e.g., `/auth/list-things`)\n- Supported TTL values: `10s`, `15s`, `30s`, `15m`\n- Unspecified endpoints default to `30s`\n\n#### `config/facs/auth.config.json`\n\n```json\n{\n  \"a0\": {\n    \"superAdmin\": \"superadmin@company.com\",\n    \"ttl\": 86400,\n    \"saltRounds\": 10,\n    \"superAdminPerms\": [\n      \"miner:rw\",\n      \"container:rw\",\n      \"minerpool:rw\",\n      \"powermeter:rw\",\n      \"temp:rw\",\n      \"electricity:rw\",\n      \"features:rw\",\n      \"revenue:rw\",\n      \"users:rw\",\n      \"actions:rw\",\n      \"production:rw\",\n      \"alerts:rw\",\n      \"cabinets:rw\",\n      \"comments:rw\",\n      \"explorer:rw\",\n      \"inventory:rw\",\n      \"reporting:rw\",\n      \"settings:rw\",\n      \"ticket:rw\",\n      \"power_spot_forecast:rw\"\n    ],\n    \"roles\": {\n      \"admin\": [\n        \"miner:rw\",\n        \"container:rw\",\n        \"minerpool:rw\",\n        \"powermeter:rw\",\n        \"temp:rw\",\n        \"electricity:rw\",\n        \"features:rw\",\n        \"revenue:rw\",\n        \"users:rw\",\n        \"actions:rw\",\n        \"production:rw\",\n        \"alerts:rw\",\n        \"cabinets:rw\",\n        \"comments:rw\",\n        \"explorer:rw\",\n        \"inventory:rw\",\n        \"reporting:rw\",\n        \"settings:rw\",\n        \"ticket:rw\",\n        \"power_spot_forecast:rw\"\n      ],\n      \"reporting_tool_manager\": [\n        \"revenue:rw\",\n        \"production:rw\",\n        \"reporting:rw\",\n        \"settings:r\",\n        \"power_spot_forecast:r\"\n      ],\n      \"site_manager\": [\n        \"miner:rw\",\n        \"container:rw\",\n        \"minerpool:rw\",\n        \"powermeter:rw\",\n        \"temp:rw\",\n        \"electricity:rw\",\n        \"actions:rw\",\n        \"alerts:rw\",\n        \"cabinets:rw\",\n        \"comments:rw\",\n        \"explorer:rw\",\n        \"inventory:rw\",\n        \"reporting:rw\",\n        \"settings:rw\",\n        \"ticket:rw\"\n      ],\n      \"site_operator\": [\n        \"miner:rw\",\n        \"container:rw\",\n        \"minerpool:rw\",\n        \"powermeter:rw\",\n        \"temp:rw\",\n        \"actions:rw\",\n        \"electricity:rw\",\n        \"explorer:rw\",\n        \"inventory:rw\",\n        \"reporting:rw\",\n        \"cabinets:rw\",\n        \"comments:rw\",\n        \"settings:rw\",\n        \"ticket:rw\",\n        \"alerts:rw\"\n      ],\n      \"field_operator\": [\n        \"miner:r\",\n        \"container:r\",\n        \"minerpool:r\",\n        \"powermeter:r\",\n        \"temp:r\",\n        \"electricity:r\",\n        \"explorer:r\",\n        \"inventory:r\",\n        \"reporting:r\",\n        \"cabinets:r\",\n        \"comments:rw\",\n        \"settings:r\",\n        \"ticket:r\",\n        \"alerts:r\"\n      ],\n      \"repair_technician\": [\n        \"miner:r\",\n        \"container:r\",\n        \"minerpool:r\",\n        \"powermeter:r\",\n        \"temp:r\",\n        \"actions:rw\",\n        \"electricity:r\",\n        \"explorer:r\",\n        \"inventory:rw\",\n        \"cabinets:r\",\n        \"comments:rw\",\n        \"settings:r\",\n        \"ticket:r\",\n        \"alerts:r\"\n      ],\n      \"read_only_user\": [\n        \"miner:r\",\n        \"container:r\",\n        \"minerpool:r\",\n        \"powermeter:r\",\n        \"temp:r\",\n        \"electricity:r\",\n        \"explorer:r\",\n        \"inventory:r\",\n        \"reporting:r\",\n        \"cabinets:r\",\n        \"comments:r\",\n        \"settings:r\",\n        \"ticket:r\",\n        \"alerts:r\"\n      ],\n      \"dev\": [\n        \"miner:r\",\n        \"container:r\",\n        \"minerpool:r\",\n        \"powermeter:r\",\n        \"temp:r\",\n        \"electricity:r\",\n        \"explorer:rw\",\n        \"inventory:rw\",\n        \"reporting:rw\",\n        \"cabinets:rw\",\n        \"comments:rw\",\n        \"settings:rw\",\n        \"ticket:rw\",\n        \"alerts:rw\"\n      ]\n    },\n    \"roleManagement\": {\n      \"admin\": [\n        \"site_manager\",\n        \"site_operator\",\n        \"reporting_tool_manager\",\n        \"field_operator\",\n        \"repair_technician\",\n        \"read_only_user\",\n        \"dev\"\n      ]\n    }\n  }\n}\n```\n\n**Fields:**\n- `superAdmin`: Email of the super administrator (cannot be modified/deleted)\n- `ttl`: Token time-to-live in seconds (default: 86400 = 24 hours)\n- `saltRounds`: BCrypt salt rounds for password hashing\n- `superAdminPerms`: Permissions granted to super administrator\n- `roles`: Role definitions with their associated permissions\n- `roleManagement`: Defines which roles can manage other roles\n\n**Permission Format:**\n- Permissions use format `resource:access` where access can be:\n  - `r` = read-only\n  - `rw` = read and write\n- Example: `\"miner:rw\"` grants read and write access to miner resources\n\n**Available Roles:**\n- `admin` - Full administrative access, can manage all other roles\n- `reporting_tool_manager` - Access to revenue, production, and reporting features\n- `site_manager` - Full site operations without user/feature management\n- `site_operator` - Day-to-day mining operations\n- `field_operator` - Read-only access with comment/ticket creation\n- `repair_technician` - Read access with action/inventory/comment management\n- `read_only_user` - Read-only access to all resources\n- `dev` - Developer access with elevated explorer/inventory/settings permissions\n\n**Role Management Rules:**\n- `superAdmin`: Designated user with all permissions, cannot be modified/deleted via API\n- `admin`: Can manage all roles listed in `roleManagement.admin` array\n- Other roles: Cannot manage users (not present in `roleManagement` object)\n\n#### `config/facs/httpd-oauth2.config.json`\n\n```json\n{\n  \"h0\": {\n    \"method\": \"google\",\n    \"credentials\": {\n      \"client\": {\n        \"id\": \"\u003cCLIENT_ID\u003e\",\n        \"secret\": \"\u003cCLIENT_SECRET\u003e\"\n      }\n    },\n    \"startRedirectPath\": \"/oauth/google\",\n    \"callbackUri\": \"http://localhost:3000/oauth/google/callback\",\n    \"callbackUriUI\": \"http://localhost:3030\"\n  }\n}\n```\n\n**Fields:**\n- `method`: OAuth provider (currently only `\"google\"` supported)\n- `credentials.client.id`: Google OAuth2 client ID\n- `credentials.client.secret`: Google OAuth2 client secret\n- `startRedirectPath`: Initiation path for OAuth flow\n- `callbackUri`: OAuth callback URL (must match Google Console configuration)\n- `callbackUriUI`: Frontend redirect URL after authentication\n\n**Capability Codes:**\n- `m` = miner\n- `c` = container\n- `mp` = minerpool\n- `p` = powermeter\n- `t` = temperature\n- `e` = electricity\n- `f` = features\n- `r` = revenue\n\n**OAuth Flow:**\n1. User visits `/oauth/google` on the app-node\n2. Redirected to Google authentication\n3. After auth, Google redirects to `callbackUri`\n4. App-node issues token and redirects to `callbackUriUI`\n\n---\n\n## API Reference\n[API](./docs/API.md)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftetherto%2Fminingos-app-node","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftetherto%2Fminingos-app-node","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftetherto%2Fminingos-app-node/lists"}