⚡ Technical Specification · v1.0 · 2026

E-UBI Device Blueprint

A complete hardware and software specification for constructing a physical E-UBI community terminal — from bare components to a fully networked, solar-powered node running TheEtherNet.

🍓 Raspberry Pi 4/5 ⚡ Node.js 20 LTS 🗄️ PostgreSQL 16 🔄 PM2 Process Manager ☁️ Cloudflare Tunnel 📡 Socket.io Real-Time

Physical Components

Every E-UBI terminal is built around a Raspberry Pi single-board computer paired with a touchscreen display, solid-state storage, and a solar-aware power supply. The design is intentionally modular — swap components as the project scales.

🍓
Processing Unit
Raspberry Pi 5 (8 GB)
Quad-core Cortex-A76 @ 2.4 GHz · BCM2712 · PCIe 2.0 for NVMe SSD. Pi 4 (4 GB) is the minimum for running Postgres + Node concurrently.
🖥️
Display
7″ Official RPi Touchscreen
800 × 480 px IPS · 10-point capacitive touch · DSI connector · 70 mA at 5 V. Ideal for kiosk-mode deployments.
💾
Primary Storage
128 GB microSD (U3/A2)
Samsung Pro Endurance or equivalent. High write-endurance is critical for Postgres WAL. Upgrade to NVMe SSD via PCIe hat for production nodes.
🔌
Power Supply
27W USB-C (Pi 5 official)
5.1 V / 5 A. For solar deployments use a 12 V→5 V buck converter (Waveshare Solar Power Manager D) with a 50 W panel + 10 Ah LiFePO₄.
📡
Connectivity
Wi-Fi 802.11ac + Gigabit Ethernet
Built-in on Pi 4/5. For remote deployments add a 4G LTE USB dongle (Huawei E3372) configured via ModemManager.
🎛️
Optional Peripherals
NFC + Audio + Speaker
PN532 NFC module (I²C) for tap-to-login. I²S DAC or 3.5 mm jack for music playback via TheEtherNet profile player.

🔌 Device Power & Signal Path

🔌 AC PSU or Solar Input
27 W USB-C supply or regulated DC source
⚙️ 5.1 V Power Rail
buck converter / USB-C PD trigger / fuse
🍓 Raspberry Pi 5
main compute + GPIO + storage bus
🖥️ DSI Touchscreen
display + touch controller
💾 microSD / NVMe
boot media + database endurance
🌐 Ethernet / Wi-Fi / LTE
uplink to router or field gateway
☀️ Optional Solar Chain
PV → MPPT → LiFePO₄ → 5 V buck
🔋
Typical Load Budget
~10–18 W operating
A Pi 5 commonly sits around 3–5 W at light load and rises materially during package installs, builds, or sustained proxy + database activity. The official 7″ display can add roughly 3–5 W depending on brightness, while LTE modems and USB accessories introduce transient peaks. Design the 5 V rail with margin rather than sizing to the average draw alone.
🌡️
Thermal Envelope
Active cooling recommended
The Pi 5 will reduce clocks if the SoC approaches its thermal limit. For kiosks expected to run databases, WebSocket traffic, and build tasks, use the official active cooler or an equivalent heatsink/fan assembly, preserve intake and exhaust paths, and plan periodic dust cleaning in public deployments.
💽
Storage Strategy
microSD for boot, NVMe preferred for writes
A good endurance microSD card is acceptable for prototyping and recovery images, but PostgreSQL WAL traffic and log churn benefit from SSD-class media. For long-lived nodes, keep a known-good boot image and move the database to NVMe or a high-quality USB SSD where possible.
🧰
Field Serviceability
Fast swap > glued assembly
Leave access to the USB-C input, storage device, display ribbon, and at least one maintenance USB port. Label internal connectors, keep a spare SD recovery image, and record hostname, LAN IP, tunnel name, and power-chain wiring inside the enclosure for future servicing.

📋 Bill of Materials

Component Model / Part Est. Cost (USD) Required?
Single-board ComputerRaspberry Pi 5 — 8 GB RAM$80Required
MicroSD CardSamsung Pro Endurance 128 GB$18Required
Touchscreen DisplayOfficial RPi 7″ Touch Display$80Required
Display Case / StandSmartiPi Touch Pro 2$30Required
Power SupplyRaspberry Pi 27W USB-C PSU$12Required
Active CoolerOfficial RPi 5 Active Cooler$5Required
NVMe SSD (Pi 5)WD_BLACK SN770M 256 GB$45Optional
PCIe NVMe HatPimoroni NVMe Base for RPi 5$15Optional
Solar Power ManagerWaveshare Solar Power Manager D$22Optional
Solar Panel50 W 18 V Monocrystalline$40Optional
LiFePO₄ Battery12 V 10 Ah LiFePO₄$35Optional
NFC ModulePN532 I²C Breakout$8Optional
4G LTE DongleHuawei E3372h-325$30Optional
Core kit total~$225
Full solar kit total~$430

Portal Gateway Device

A Portal Gateway Device is a doorway-scale light-and-sound installation that uses controlled audio, visible-light modulation, and proximity sensing to make crossing a threshold feel intentional. Here, portal means a designed sensory effect and shared ritual — not a verified claim of spacetime distortion, healing, or altered consciousness.

🌈 Light Layer
diffused LED rails in the jambs or header
🔊 Resonance Layer
low-SPL tones, harmonics, and doorway sweep tuning
🌐 Network Layer
motion events, local state, and TheEtherNet presence

🧱 Hardware Specification — Reference Build

🧠
Control Stack
Pi 5 + Pico 2
Base compute remains the Raspberry Pi 5. Add a Raspberry Pi Pico 2 if you want deterministic sensor timing, relay / DMX expansion, or LED offload from the Linux host.
🔊
Audio Path
I²S DAC → Class-D amp → exciters
Use a HiFiBerry DAC+ ADC Pro into a TPA3116D2-based stereo amplifier driving two Dayton DAEX32EP-4 exciters mounted to birch or aluminum doorway panels.
🌈
Visual Path
WS2815 12 V LED rails
Two 1 m BTF-LIGHTING WS2815 strips inside diffused jamb channels provide the visible threshold effect. Drive data through a 74AHCT125 level shifter.
📏
Sensors
PIR + ultrasonic range
Use an HC-SR501 PIR for motion and an HC-SR04P ultrasonic sensor for proximity. The HC-SR04P is preferred because it operates from 3.3 V logic more cleanly than the original HC-SR04.
📡
Signal Generation
Software synthesis + optional DDS
The reference implementation generates tones in software on the Pi. For bench calibration or analog experiments, add two AD9833 DDS boards as optional low-voltage signal generators.
🔋
Power Chain
12 V main rail + 5 V buck
Use a Mean Well LRS-150-12 for the LED / amplifier rail and a Pololu D36V50F5 or equivalent 5 V / 5 A buck converter for the Raspberry Pi.
Component Model / Part Est. Cost (USD) Required?
Primary controllerRaspberry Pi 5 — 8 GB RAM$80Required
Real-time coprocessorRaspberry Pi Pico 2$7Recommended
Audio interfaceHiFiBerry DAC+ ADC Pro (I²S)$55Required
Stereo amplifierTPA3116D2 2 × 50 W board$18Required
Doorway transducers2 × Dayton Audio DAEX32EP-4 exciters$42Required
Threshold transducerDayton Audio BST-1 tactile transducer$58Optional
LED railsBTF-LIGHTING WS2815 12 V, 60 LED/m, 2 m total$34Required
LED logic shifting74AHCT125 level shifter breakout$4Required
Motion sensorHC-SR501 PIR module$3Required
Proximity sensorHC-SR04P ultrasonic module$4Required
Power supplyMean Well LRS-150-12$28Required
5 V regulatorPololu D36V50F5 5 V / 5 A buck converter$22Required
Calibration DDS2 × AD9833 signal generator modules$12Optional
Frame hardware20 × 20 mm aluminum U-channel + polycarbonate diffuser + rubber grommets$35Required

🪶 Safer / Minimal Variant

Best for workshops, temporary installs, and first builds: keep all AC-to-DC conversion outside the doorway, skip the open-frame 12 V supply, omit the tactile threshold transducer, and use a lower-SPL audio path. This variant is cheaper, easier to mount, and simpler to service.

🔌
Power
External adapters only
Use the official Pi 5 USB-C PSU plus a separate UL-listed 5 V LED supply or power bank. Keep mains adapters outside the frame so only low-voltage wiring enters the doorway.
🔊
Audio
USB audio + small powered speaker
Swap the HiFiBerry / exciter stack for a USB audio dongle feeding a compact powered soundbar or monitor speaker. Use 120 Hz + 240 Hz instead of deep 40 Hz if the speaker cannot reproduce bass cleanly.
🌈
Lighting
1 m APA102 / SK9822 strip
A single diffused LED strip on the header or one strip per jamb is enough for a readable threshold effect. APA102 / SK9822 keeps wiring simple and produces clean, high-refresh animation.
👣
Sensing
PIR only
Use only the HC-SR501 for motion-triggered approach states. Skip ultrasonic ranging until the mechanical layout is stable; this removes one sensor, one mounting constraint, and one tuning variable.

Minimal build notes: keep continuous sound under 70 dBA at 1 m, use softer pulse envelopes, and avoid any visible low-frequency strobing. The same software model still works: disable ultrasonic logic, reduce LED_COUNT, and keep TheEtherNet posting optional.

This trims the add-on bill to roughly $70–$120 beyond the base Pi, depending on the speaker and LED choice, while preserving the core threshold effect.

🎚️ Frequency & Resonance Details

Layer Exact Setting Purpose Evidence / Note
Low-frequency bed40 Hz sine at conservative SPLProvides a stable low-frequency anchor felt in the frame and heard in the room.40 Hz is widely used in auditory steady-state response research (for example Galambos et al., 1981), but that does not prove mystical or therapeutic effects.
Harmonic scaffold160 Hz + 320 Hz sines, phase-lockedMakes the 40 Hz structure audible on smaller exciters and helps define the timbre.Pure engineering choice: harmonics improve audibility and reduce the need to overdrive the lowest band.
Beat pair216 Hz left / 222 Hz rightCreates a 6 Hz acoustic beating pattern in the doorway air column.This is an aesthetic interference effect, not a clinical entrainment claim.
Envelope statesIdle 0.08 Hz, approach 0.6 Hz, crossing 1.2 HzControls how the audio and light pulse as a person approaches and passes through.These rates were chosen for perceptibility and comfort, not because the numbers are uniquely “sacred.”
Visible-light paletteBlue ~470 nm, green ~525 nm, red ~625 nmThe installation’s intentional electromagnetic emission is visible light from RGB LEDs.Those wavelengths are ordinary LED channels; there is no claim that they open portals or modify biology.
LED drive safetyKeep carrier / PWM above 3 kHz when possibleAvoid visible flicker and reduce photosensitive risk.Aligned with the direction of IEEE 1789-2015 LED modulation guidance. Do not add 3–70 Hz full-depth strobing in occupied doorways.
Doorway mode scan80–240 Hz swept sine during commissioningFind the cleanest mechanical / acoustic band for a given frame and room.Door and room resonances follow ordinary acoustics; a useful first estimate is f = c / (2D) for an axial dimension D.

Reference notes: treat this frequency plan as a reproducible signal recipe, not evidence of extraordinary effects. The strongest footing here is 40 Hz auditory steady-state response literature, standard room-acoustics practice, and IEEE 1789-2015 flicker guidance.

Rule of thumb: a 0.9 m doorway width gives an axial estimate near 190 Hz, while a 2.1 m opening height gives one near 82 Hz — which is why the commissioning sweep covers 80–240 Hz.

💻 Software Implementation

The reference controller below runs directly on the Raspberry Pi. It covers frequency generation, sensor integration, visual synchronization, and TheEtherNet integration using surfaces already present in this repository: POST /ethernet-api/auth/login, POST /ethernet-api/auth/guest, POST /ethernet-api/posts, and Socket.IO on /ethernet-socket.io.

Dependencies — Raspberry Pi OS
sudo apt update sudo apt install -y python3-pip python3-dev portaudio19-dev python3 -m pip install --upgrade pip python3 -m pip install numpy sounddevice gpiozero rpi_ws281x requests python-socketio
portal-gateway/portal_gateway.py — reference controller
import colorsys import math import os import time import numpy as np import requests import socketio import sounddevice as sd from gpiozero import DistanceSensor, MotionSensor from rpi_ws281x import Color, PixelStrip SAMPLE_RATE = 48000 LED_COUNT = 120 BASE_URL = os.getenv('THEETHERNET_BASE_URL', 'http://127.0.0.1:3000') USERNAME = os.getenv('THEETHERNET_USERNAME', '') PASSWORD = os.getenv('THEETHERNET_PASSWORD', '') pir = MotionSensor(17) distance_sensor = DistanceSensor(echo=24, trigger=23, max_distance=2.0) strip = PixelStrip(LED_COUNT, 18, 800000, 10, False, 160, 0) strip.begin() session = requests.Session() online_users = set() state = {'phase': 0, 'level': 0.0, 'distance_m': 2.0, 'last_cross': 0.0} access_token = None sio = socketio.Client(reconnection=True, logger=False, engineio_logger=False) @sio.on('user:online') def on_user_online(data): username = (data or {}).get('username') if username: online_users.add(username) @sio.on('user:offline') def on_user_offline(data): username = (data or {}).get('username') if username: online_users.discard(username) def ethernet_auth(): global access_token if USERNAME and PASSWORD: response = session.post(f'{BASE_URL}/ethernet-api/auth/login', json={'username': USERNAME, 'password': PASSWORD}, timeout=5) else: response = session.post(f'{BASE_URL}/ethernet-api/auth/guest', json={}, timeout=5) response.raise_for_status() access_token = response.json()['accessToken'] sio.connect(BASE_URL, socketio_path='ethernet-socket.io', auth={'token': access_token}, transports=['websocket']) def post_crossing_event(distance_m): if not access_token: return payload = {'content': f'Portal threshold crossed at {time.strftime("%Y-%m-%d %H:%M:%S")} · distance={distance_m:.2f}m'} session.post(f'{BASE_URL}/ethernet-api/posts', json=payload, headers={'Authorization': f'Bearer {access_token}'}, timeout=5) def update_state(): measured_m = distance_sensor.distance * 2.0 state['distance_m'] = max(0.05, min(2.0, measured_m)) proximity = max(0.0, min(1.0, 1.0 - (state['distance_m'] / 1.5))) target = (0.18 + 0.82 * proximity) if pir.motion_detected else (0.08 * proximity) state['level'] += (target - state['level']) * 0.18 now = time.monotonic() if pir.motion_detected and measured_m < 0.75 and (now - state['last_cross']) > 15.0: state['last_cross'] = now post_crossing_event(measured_m) def update_leds(): net_bias = min(len(online_users), 12) * 0.02 hue = max(0.02, 0.58 - net_bias) pulse = 0.5 + 0.5 * math.sin(time.monotonic() * (0.8 + 4.0 * state['level'])) value = min(1.0, 0.10 + 0.55 * state['level'] + 0.25 * pulse) r_f, g_f, b_f = colorsys.hsv_to_rgb(hue, 0.85, value) for i in range(LED_COUNT): edge = abs((i / max(1, LED_COUNT - 1)) * 2.0 - 1.0) scale = 1.0 - 0.35 * edge strip.setPixelColor(i, Color(int(r_f * 255 * scale), int(g_f * 255 * scale), int(b_f * 255 * scale))) strip.show() def audio_callback(outdata, frames, time_info, status): idx = state['phase'] + np.arange(frames) t = idx / SAMPLE_RATE shimmer_hz = 160.0 + 24.0 * math.sin(time.monotonic() * 0.11) base = 0.55 * np.sin(2 * np.pi * 40.0 * t) harm_1 = 0.20 * np.sin(2 * np.pi * 160.0 * t) harm_2 = 0.12 * np.sin(2 * np.pi * 320.0 * t) beat_l = 0.08 * np.sin(2 * np.pi * 216.0 * t) beat_r = 0.08 * np.sin(2 * np.pi * 222.0 * t) shimmer = 0.10 * np.sin(2 * np.pi * shimmer_hz * t) env_rate = 0.08 + (0.52 * state['level']) + min(len(online_users), 12) * 0.015 envelope = 0.30 + 0.70 * (0.5 + 0.5 * np.sin(2 * np.pi * env_rate * t)) gain = 0.05 + 0.25 * state['level'] left = gain * envelope * (base + harm_1 + harm_2 + beat_l + shimmer) right = gain * envelope * (base + harm_1 + harm_2 + beat_r + shimmer) outdata[:] = np.column_stack((left, right)) state['phase'] += frames def clear_leds(): for i in range(LED_COUNT): strip.setPixelColor(i, Color(0, 0, 0)) strip.show() if __name__ == '__main__': try: ethernet_auth() except Exception as exc: print(f'TheEtherNet unavailable at startup: {exc}') try: with sd.OutputStream(channels=2, callback=audio_callback, samplerate=SAMPLE_RATE, blocksize=1024): while True: update_state() update_leds() time.sleep(0.05) except KeyboardInterrupt: pass finally: clear_leds() if sio.connected: sio.disconnect()

🛠️ Assembly Instructions

Doorway wiring diagram — low-voltage reference layout
[120 / 230 VAC mains in approved enclosure] ↓ [Mean Well LRS-150-12 12 V rail] ├── fuse ──> [TPA3116D2 amplifier] ──> [Left / right exciters] ├── fuse ──> [WS2815 LED rails] └── fuse ──> [5 V buck converter] ──> [Raspberry Pi 5 USB-C] [Raspberry Pi GPIO18] ──> [74AHCT125 level shifter] ──> [WS2815 DIN] [Raspberry Pi I²S] ──> [HiFiBerry DAC+ ADC Pro] ──> [TPA3116D2 line in] [GPIO17] ──> [HC-SR501 OUT] [GPIO23 / GPIO24] ──> [HC-SR04P trig / echo] [USB or UART] ──> [Optional Pico 2 co-controller] [Ethernet / Wi-Fi] ──> [Express :3000] ──> [/ethernet-api + /ethernet-socket.io]
1
Survey and mark the doorway
Measure clear width, height, swing, and emergency-egress constraints before installing anything. Keep portal hardware outside the walking envelope: mount LED channels on the jamb faces, place exciters on hidden side panels or a header plate, and never let hardware protrude into the path of travel.
2
Mount structural panels and transducers
Fasten 6 mm birch or aluminum resonance plates behind each jamb finish panel. Bond one Dayton DAEX32EP-4 exciter per side using the manufacturer adhesive pad or VHB tape on a cleaned surface. If you add the optional BST-1, mount it to a threshold plinth or adjacent subfloor panel — not directly to a fire-rated door leaf.
3
Install LED rails and diffusers
Fit the WS2815 strips inside aluminum U-channel with a polycarbonate diffuser so the light reads as a soft line rather than exposed points. Run the strips vertically up both sides of the frame, keep service loops at the top, and add strain relief where cables transition into the control cavity.
4
Wire sensors and logic safely
Mount the HC-SR501 above head height, angled slightly downward across the approach path. Mount the HC-SR04P or equivalent range sensor in the header so it reads the doorway centerline. Route all low-voltage conductors separately from mains, fuse each 12 V branch, and terminate grounds at a single distribution point to reduce hum.
5
Deploy, calibrate, and tune the resonant band
Start with moderate amplifier gain and run a slow sweep from 80–240 Hz. Listen for rattles, buzzing trim, or harsh frame resonances; then reduce or notch the offending range and keep the cleanest band. Aim for 70–75 dBA continuous at 1 m with brief peaks under 85 dBA. Set the ultrasonic trigger so approach ramps begin around 1.2 m and crossing events fire near 0.75 m.
export THEETHERNET_BASE_URL=http://127.0.0.1:3000 export THEETHERNET_USERNAME=portal_gateway export THEETHERNET_PASSWORD=replace_me # leave blank to use guest mode python3 portal_gateway.py
6
Perform final safety and transparency checks
Verify that the install does not obstruct door operation, fire hardware, or accessibility clearances. Confirm there is no visible low-frequency strobing, no exposed mains terminals, and no component temperature above its rating after one hour of operation. Post a short placard stating that the work is an interactive audio / light installation using sensors, sound, and networked software — and that any “portal” language is artistic framing, not a proven physical phenomenon.

🔎 Transparency Note

Experimentally grounded: motion detection, distance sensing, synchronized audio / light control, doorway resonance mapping, and TheEtherNet-based presence logging are ordinary, reproducible engineering tasks. The main behaviors here can be checked with a microphone, SPL meter, and direct observation.

Suggestive but not established: 40 Hz stimulation is a real topic in auditory neuroscience, and rhythmic sound / light can influence attention and atmosphere. That does not establish teleportation, dimensional access, consciousness transfer, medical benefit, or any other extraordinary mechanism.

Claim being made: this build creates a compelling threshold effect through coordinated sound, light, and sensing. Claim not being made: that it opens literal portals or produces verified biological outcomes beyond those of an ordinary sensory installation.

Software Architecture

The E-UBI terminal runs a single Express.js process that serves the static SPA build, proxies TheEtherNet API/WebSocket traffic, and exposes the community JSON API — all managed by PM2 and tunnelled to the internet via Cloudflare.

🗺️ Request Flow

🌐 Browser / Mobile
eubi-manifesto.com
☁️ Cloudflare Tunnel
cloudflared service
⚡ Express.js (port 3000)
eubi-server · PM2
GET /
→ dist/index.html (SPA)
GET /admin
→ public/admin.html
/api/*
→ JSON REST API
/ethernet-api/*
→ proxy → port 4000
/ethernet-socket.io
→ WS proxy → port 4000
GET /ethernet
→ TheEtherNet SPA
🕸️ TheEtherNet (port 4000)
ethernet-server · PM2
🗄️ PostgreSQL 16
Prisma ORM · port 5432
📡 Socket.io
Real-time chat / events
Runtime
Node.js 20 LTS
Long-Term Support until April 2026. Install via NodeSource binary repo to stay current on ARM64.
🛣️
Web Framework
Express 5
Reverse-proxy middleware must be registered before body-parser to prevent POST body consumption before forwarding.
🗄️
Database
PostgreSQL 16
The ethereal role requires CREATEDB permission for Prisma shadow database operations during migrations.
🔷
ORM
Prisma 5
Schema at TheEtherNet/server/prisma/schema.prisma. Run migrate deploy (not dev) in production.
📡
Real-Time
Socket.io 4
Used for live DMs, typing indicators, and feed activity. WebSocket upgrade is proxied through the main Express server on /ethernet-socket.io.
🔄
Process Manager
PM2 5
Three managed processes: eubi-server, ethernet-server, and cf-tunnel. Auto-restarts on crash. Saves process list across reboots.

🧩 Local Service Topology

☁️ cloudflared
outbound-only tunnel process
⚡ Express.js :3000
static site + reverse proxy + JSON endpoints
🕸️ TheEtherNet :4000
auth, feed, DM, Socket.io events
🔷 Prisma Client
typed DB access inside Node
🗄️ PostgreSQL :5432
local-only database on the node
🔄 PM2 Supervisor
restart policy + boot persistence
📜 Logs & Metrics
pm2 logs, journalctl, disk / temp checks
🧱
Edge Boundary
Keep port 4000 private
The public internet should terminate at Express and Cloudflare, not at the raw TheEtherNet service. Running PostgreSQL and the application server on loopback-only interfaces reduces the attack surface and keeps the reverse-proxy contract explicit.
💾
Durability
Backups are part of the build
A working node still needs export and restore discipline. Plan regular pg_dump backups, keep at least one offline copy, and test restore procedures before field deployment so the terminal can be rebuilt from storage failure rather than only from source code.
📈
Observability
Watch thermals + disk + tunnel state
On single-board systems, software faults often present as storage exhaustion, undervoltage, or thermal throttling rather than obvious application crashes. Pair PM2 status checks with temperature, memory, and filesystem monitoring so failures are detected before users see a dead kiosk.
🛠️
Update Strategy
Small reversible releases
Treat every node like an appliance. Deploy pinned code revisions, restart under PM2, verify HTTP and tunnel health, and keep a previous known-good image available. The simpler the rollback path, the less risk a remote update poses to a public device.

🔷 Database Schema (Prisma)

TheEtherNet/server/prisma/schema.prisma — key models
// Connection — set in .env as DATABASE_URL datasource db { provider = "postgresql" url = env("DATABASE_URL") } model User { id String @id @default(cuid()) username String @unique email String? @unique // optional since auth refactor passwordHash String? isGuest Boolean @default(false) createdAt DateTime @default(now()) profile Profile? posts Post[] songs Song[] sentMessages Message[] @relation("SentMessages") receivedMessages Message[] @relation("ReceivedMessages") friends FriendRequest[] @relation("FriendRequests") } model Message { id String @id @default(cuid()) content String createdAt DateTime @default(now()) sender User @relation("SentMessages", fields: [senderId], references: [id]) senderId String recipient User @relation("ReceivedMessages", fields: [recipientId], references: [id]) recipientId String }

Build & Initialise

Follow these steps in order — from flashing the OS to bringing up both PM2 processes and verifying the live tunnel. Each step includes the exact shell commands needed on a fresh Raspberry Pi OS Lite (64-bit) image.

🧰 Bench Wiring Sequence

Physical assembly order — test on the bench before closing the enclosure
# Mechanical / electrical assembly flow [5 V PSU or solar-fed buck converter] ↓ [Pi 5 USB-C power input] → [Active cooler] → [microSD or NVMe boot/storage] ↓ [DSI ribbon to 7" display] + [USB or GPIO touch interface if required by panel variant] ↓ [Ethernet or Wi-Fi provisioning] → [optional LTE modem / NFC module / speakers] ↓ [Bench test: boot, network, thermals, storage, tunnel] ↓ [Final cable dressing, strain relief, enclosure close-out, field labeling]
1
Flash Raspberry Pi OS Lite (64-bit)
Use the official Raspberry Pi Imager. Choose Raspberry Pi OS Lite (64-bit), enable SSH, set hostname, Wi-Fi credentials, and your user in the "Advanced options" before writing.
# On your desktop — download imager $ snap install rpi-imager # Ubuntu/Debian # or: https://www.raspberrypi.com/software/ # After first boot — update all packages $ sudo apt update && sudo apt upgrade -y $ sudo apt install -y git curl build-essential
2
Install Node.js 20 LTS via NodeSource
Do not use the default apt repo — it ships an outdated Node version. Use the official NodeSource script instead.
$ curl -fsSL https://deb.nodesource.com/setup_20.x | sudo -E bash - $ sudo apt install -y nodejs $ node -v # expect: v20.x.x $ npm -v # expect: 10.x.x # Install PM2 globally $ sudo npm install -g pm2 $ pm2 startup systemd -u $USER --hp $HOME $ sudo env PATH=$PATH:/usr/bin pm2 startup systemd -u $USER --hp $HOME
3
Install PostgreSQL 16 & create the database
PostgreSQL 16 is available via the official PGDG apt repository. The ethereal role needs CREATEDB for Prisma shadow-database support during migrations.
# Add PGDG repo $ sudo sh -c 'echo "deb https://apt.postgresql.org/pub/repos/apt $(lsb_release -cs)-pgdg main" > /etc/apt/sources.list.d/pgdg.list' $ wget --quiet -O - https://www.postgresql.org/media/keys/ACCC4CF8.asc | sudo apt-key add - $ sudo apt update && sudo apt install -y postgresql-16 # Create role + database $ sudo -u postgres psql -c "CREATE ROLE ethereal WITH LOGIN PASSWORD 'ethereal_pass' CREATEDB;" $ sudo -u postgres psql -c "CREATE DATABASE theethernet OWNER ethereal;" # Verify connection $ psql -U ethereal -d theethernet -c "\dt"
4
Clone the repository & install dependencies
Clone into your home directory. Install dependencies for both the main site and TheEtherNet server and client separately.
$ git clone https://github.com/EveOfSin/ccb-ubi.git ~/ccb-ubi $ cd ~/ccb-ubi # Main E-UBI site $ cd eubi-site && npm install # TheEtherNet back-end $ cd ../TheEtherNet/server && npm install # TheEtherNet front-end $ cd ../client && npm install && npm run build
5
Configure environment variables
Create a .env file in TheEtherNet/server/. Never commit this file — it is already in .gitignore.
# TheEtherNet/server/.env DATABASE_URL="postgresql://ethereal:ethereal_pass@localhost:5432/theethernet" JWT_SECRET="replace-with-a-strong-random-secret-min-32-chars" JWT_REFRESH_SECRET="replace-with-another-strong-secret" PORT=4000 NODE_ENV="production"
6
Run Prisma migrations & seed admin account
Use migrate deploy (not migrate dev) in production — it applies existing migrations without creating new ones or touching the shadow database.
$ cd ~/ccb-ubi/TheEtherNet/server # Apply all pending migrations to theethernet DB $ npx prisma migrate deploy # Generate the Prisma client (if not already built) $ npx prisma generate # Optional: open Prisma Studio to inspect data $ npx prisma studio --port 5555
7
Launch both servers with PM2
The ecosystem.config.js in eubi-site/ defines all three processes. After starting, save the list so PM2 resurrects them on reboot.
$ cd ~/ccb-ubi/eubi-site # Start / restart all processes defined in ecosystem.config.js $ pm2 start ecosystem.config.js # Persist the process list across reboots $ pm2 save # Verify all three processes are online $ pm2 list # Stream live logs from both servers $ pm2 logs --lines 50
8
Validate thermals, storage headroom, and undervoltage state
Before sealing the kiosk, check that the Pi is not reporting throttling, the filesystem has adequate free space, and the services remain healthy under sustained operation. These checks catch weak power supplies, failing storage, and airflow problems early.
$ vcgencmd measure_temp $ vcgencmd get_throttled $ free -h $ df -h $ sudo dmesg | grep -i -E 'voltage|throttl' $ pm2 monit
9
Harden the node for unattended service
A public kiosk benefits from automatic package security updates, SSD trim support, correct time sync, and persistent SSH access for recovery. Perform these steps once the node is stable and before the hardware is moved into its final location.
$ sudo systemctl enable ssh $ sudo timedatectl set-ntp true $ sudo systemctl enable fstrim.timer $ sudo apt install -y unattended-upgrades $ sudo dpkg-reconfigure --priority=low unattended-upgrades

Cloudflare Tunnel

Cloudflare Tunnel (cloudflared) exposes the local Express server on port 3000 to the public internet under your domain — no port-forwarding or static IP required. The tunnel itself is managed as a PM2 process.

🌐 Network & Exposure Path

🍓 Pi Node
Express + TheEtherNet + PostgreSQL
🏠 Local Router / AP
Ethernet preferred, Wi-Fi acceptable
☁️ Cloudflare Edge
public DNS, TLS termination, tunnel broker
🌍 Visitors
browser, mobile, admin workstation
🔧 Local Maintenance Path
SSH / LAN access still works if WAN fails
📶 Optional LTE Uplink
useful for remote or temporary sites
🔒 Outbound-Only Egress
no inbound port-forward rule required
📡 Monitoring
tunnel reconnects, DNS, packet loss, RSSI

From a reachable node to an operable community system

Cloudflare Tunnel gets one terminal or one node reachable. The node spec explains the single-site infrastructure around it. The federation guide shows how multiple local nodes mirror documentation, share recovery capacity, and sync selected data without flattening every site into one opaque central service. The operations runbook adds the day-two layer: backup cadence, restore drills, incident handling, and steward handoff. The service matrix then defines what should remain local, what may federate, and who is allowed to change those boundaries. The identity and trust guide closes the loop by documenting who actually holds authority, custody, peer trust, and recovery power inside that system. The operator handbook names the steward roles and escalation ladder, while the service runbooks turn those governance boundaries into repeatable identity, mirror, relay, and backup procedures.

Open Node Spec Open Federation Guide Open Operations Runbook Open Service Matrix Open Identity & Trust Guide Open Operator Handbook Open Service Runbooks
1
Install cloudflared on the Pi
Download the ARM64 binary directly from the Cloudflare release page.
$ curl -L https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-linux-arm64 -o cloudflared $ sudo mv cloudflared /usr/local/bin/ $ sudo chmod +x /usr/local/bin/cloudflared $ cloudflared --version
2
Authenticate & create a named tunnel
Log in to your Cloudflare account, then create a named tunnel and route it to your domain.
# Opens browser — log in and select your zone (eubi-manifesto.com) $ cloudflared tunnel login # Create the tunnel (generates a UUID-named credentials file) $ cloudflared tunnel create eubi-node-1 # Route DNS — replaces any existing A/CNAME record $ cloudflared tunnel route dns eubi-node-1 eubi-manifesto.com
3
Write the tunnel config file
Create ~/.cloudflared/config.yml. The tunnel forwards all traffic to localhost:3000 where Express is listening.
# ~/.cloudflared/config.yml tunnel: eubi-node-1 credentials-file: /home/pi/.cloudflared/<TUNNEL-UUID>.json ingress: - hostname: eubi-manifesto.com service: http://localhost:3000 - service: http_status:404
4
Add the tunnel to PM2 via ecosystem.config.js
Managing cloudflared as a PM2 process means it auto-restarts on crash and is included in pm2 save.
// eubi-site/ecosystem.config.js — cf-tunnel entry { name: 'cf-tunnel', script: '/usr/local/bin/cloudflared', args: 'tunnel run eubi-node-1', autorestart: true, watch: false, env: { HOME: '/home/pi' } }
5
Verify tunnel health, local reachability, and DNS propagation
Check the local HTTP path first, then confirm that the PM2-managed tunnel is stable and that the public hostname resolves correctly. If the WAN path is down, LAN administration should still remain available for maintenance.
$ ss -ltnp | grep 3000 $ curl -I http://127.0.0.1:3000 $ pm2 logs cf-tunnel --lines 30 $ cloudflared tunnel info eubi-node-1 # From another device or network, verify the public edge path $ curl -I https://eubi-manifesto.com
🔌
Primary Uplink
Ethernet where available
A wired link is usually the most predictable option for kiosks installed in fixed locations. It avoids Wi-Fi congestion, improves latency consistency for WebSocket traffic, and makes power/throughput troubleshooting easier during field maintenance.
📶
Wireless Tradeoff
Wi-Fi / LTE are deployment tools
Wi-Fi shortens setup time but inherits the health of the local access point. LTE can rescue remote sites, though throughput, NAT behavior, monthly data cost, and signal variability should be budgeted before it becomes the assumed primary path.
🛡️
Firewall Posture
Outbound rules still matter
Tunnelled access avoids opening inbound ports, but a locked-down network still has to permit DNS, HTTPS, and whichever Cloudflare tunnel transport the deployment uses. In strict environments, document those egress requirements before the node is shipped.

Physical Design

The enclosure should be weather-resistant (for outdoor deployments), tamper-evident, and aesthetically aligned with the E-UBI brand — dark finish with gold accent lettering. Below are the recommended configurations for indoor kiosk vs. outdoor node.

🏢
Indoor Kiosk
SmartiPi Touch Pro 2
Designed specifically for the official 7″ RPi display. Includes a tilting stand, Pi 4/5 mount, and cable management. Available in black. Laser-engrave the E-UBI logo on the face plate.
🌧️
Outdoor Node
IP65 ABS Junction Box
200×150×75 mm NEMA 4X rated box. Mount display behind a polycarbonate window cutout. Use waterproof cable glands for power + Ethernet. Spray paint matte black with gold stencil.
🌞
Solar Mounting
Adjustable Tilt Bracket
Mount the 50 W panel at ~30–35° tilt facing true south (northern hemisphere) for maximum annual yield. Use an M8 stainless steel bracket rated for 60 mph wind load.
🎨
Branding
Gold on Matte Black
Vinyl cut or laser-engraved E-UBI yin-yang logo + "Community UBI Terminal" text. Font: Inter 700. Gold: #FFD700. Reserve 40 mm clearance around display bezel.
🔒
Security
Kensington Lock + Tamper Seal
Thread a Kensington cable through the Pi's mounting holes before closing the enclosure. Apply a tamper-evident holographic seal over the enclosure seam.
🌡️
Thermal Management
Active Cooler + Passive Vent
The official Pi 5 active cooler keeps the BCM2712 below 60 °C in ambient temperatures up to 35 °C. Add a 60 mm mesh vent near the top of the enclosure for convection.

🧱 Mechanical Stack-Up

Front-to-back enclosure layering — keep service loops and thermal paths intact
# Representative kiosk stack [Front bezel / vandal-resistant face plate] ↓ [Polycarbonate or tempered protective window] ↓ [7" display panel + touch layer + ribbon routing clearance] ↓ [Pi 5 + active cooler + optional NVMe HAT on stand-offs] ↓ [Fused DC input / buck converter / cable strain relief] ↓ [Low intake vent] → airflow across board and display driver → [high exhaust vent] # Service notes - Keep cable bends gentle, especially for DSI and flat-flex ribbons. - Avoid placing the battery, charger, or DC regulator directly above the SoC heatsink. - Leave enough slack to open the enclosure without unplugging every internal harness.
🪛
Access Clearance
Design for re-openability
Leave tool access for the display mount, Pi stand-offs, and power terminals. A community device should be repairable with common hand tools, not sealed into a state where a failed SD card or fan requires destructive disassembly.
💧
Condensation Control
Weatherproof ≠ airtight forever
Outdoor boxes need gaskets and cable glands, but they also need a plan for humidity. Use breathable vents or desiccant strategies where appropriate, avoid trapping warm electronics against cold walls, and inspect seals after seasonal temperature swings.
🔌
Cable Routing
Separate signal and power paths
Route low-voltage DC input, display ribbons, and network cables so they do not rub against fan blades, sharp edges, or the rear of the touchscreen. Strain relief matters more in public hardware than in bench prototypes because vibration and repeated servicing are normal.
⚠️
Protection
Fuse and isolate the power chain
Any external DC input, battery link, or solar feed should have appropriate overcurrent protection and a service disconnect. If mains equipment is added, follow the enclosure, grounding, and legal requirements for that jurisdiction rather than improvising consumer AC wiring inside the box.

Long-Horizon Renewable Power

Powering one kiosk from a solar panel is a modest engineering task. Powering large numbers of terminals, routers, storage systems, and community facilities over decades is a broader infrastructure problem involving site conditions, storage limits, transmission, maintenance crews, safety systems, forecasting, and regional balancing. The practical goal is not a magical perpetual machine; it is a resilient clean-energy architecture that can be expanded responsibly.

⚡ Scale Ladder

🖥️ Single Terminal
5 V electronics, local storage, one network path
🏘️ Community Microgrid
shared generation, batteries, protected AC/DC buses
🗺️ Regional Mix
solar + wind + hydro + geothermal + storage
🌍 Interconnection
transmission, dispatch, redundancy, black-start planning
🔋
Terminal-Scale System
Panel + controller + battery + 5 V rail
A single E-UBI node can often be supported by a modest solar subsystem if the power budget is kept honest. A representative off-grid design might use a 50–100 W PV module, MPPT charge control, LiFePO₄ storage sized for the required autonomy window, fused DC distribution, and a regulated 5 V output sized for peak kiosk load rather than only average draw.
🏘️
Community Microgrid
Critical loads first, then general loads
At neighborhood scale, the design shifts toward protected AC buses, hybrid inverters, battery energy storage, load prioritisation, and islanding logic. A practical microgrid distinguishes critical services—communications, refrigeration, pumps, lighting, clinic loads, E-UBI nodes—from discretionary demand during low-generation periods.
🌬️
Regional Backbone
Diverse resources reduce correlated failure
Large-scale clean grids work best when they combine technologies with different production profiles: solar for daytime output, wind for seasonal and overnight diversity, hydro for dispatchable balancing where geography allows, geothermal for steady baseload in suitable regions, and storage tuned for different durations rather than one universal battery type.
🛡️
Safety & Operations
Protection is part of generation
Every layer needs disconnects, breakers, grounding, surge protection, battery management, remote alarms, and maintenance planning. Renewable infrastructure still fails in storms, dust, heat, corrosion, and operator error; resilience comes from inspection schedules, spares, training, and sensible operating margins.

🔌 Power path — terminal + local node support chain

Power path for an E-UBI terminal and supporting local node Diagram showing photovoltaic input through disconnects and MPPT into a battery and protected bus feeding the terminal and the local networking node. PV Array 50–100 W kiosk scale DC Disconnect Fuse / breaker / isolation MPPT Controller Charge control + telemetry LiFePO₄ Battery BMS + low-voltage cutoff Autonomy buffer Protected DC / AC Bus Critical loads first Terminal Pi + display Node router + AP protected comms loads
generation and critical-load bus protection / disconnect control and terminal rail storage and network resilience

The key planning move is to keep communications and coordination gear on the protected side of the storage buffer. A terminal is useful; a terminal plus local router, AP, and docs node that all stay alive together is infrastructure.

🔋 Single Terminal Renewable Chain

Representative off-grid topology — one kiosk-class E-UBI node
# Terminal-scale renewable architecture [50–100 W PV module] ↓ [DC disconnect + fuse / breaker] ↓ [MPPT charge controller] ↓ [12 V LiFePO₄ battery + BMS] ↓ [Low-voltage disconnect / service fuse] ↓ [5.1 V buck converter sized with peak-current margin] ↓ [Raspberry Pi 5] → [7" display] → [NVMe / microSD] → [Ethernet / Wi-Fi / LTE uplink] # Typical design concerns - Battery autonomy depends on average load, nighttime duration, and weather, not panel nameplate alone. - Charge controller, cable gauge, and fuse sizing must match the actual current path. - Add local telemetry for battery voltage, cabinet temperature, and persistent undervoltage events.

🏘️ Community Microgrid Blueprint

Neighborhood-scale architecture — islandable but grid-aware
# Community microgrid block diagram [Rooftop / canopy solar] [Small wind where viable] [Micro-hydro / geothermal where geography permits] ↓ ↓ ↓ [String inverters] [AC/DC conversion] [Conditioning] \ | / \ | / [Protected microgrid bus + switchgear] ↓ [Battery energy storage system + BMS + fire isolation] ↓ [Critical loads panel: routers, clinic IT, pumps, lighting, E-UBI nodes] ↓ [Non-critical loads shed first during low-generation periods] ↓ [Utility intertie / islanding relay / backup contingency source] # Operations layer [Forecasting] + [metering] + [demand response] + [maintenance crew dispatch] + [spare parts inventory]

🌍 Interconnected Clean-Energy Network

Regional / interregional architecture — coordinated, redundant, and weather-aware
# Multi-region renewable backbone [Utility solar] [Onshore / offshore wind] [Hydro reservoirs] [Geothermal fields] ↓ ↓ ↓ ↓ [Regional substations + protection relays] ↓ [High-voltage transmission corridors] ↓ [Distribution substations and feeders] ↓ [Cities, microgrids, transit, industry, data, community nodes] # Balancing / resilience layers [4 h batteries] + [pumped hydro] + [thermal storage] + [long-duration storage where economical] [weather forecasting] + [market / dispatch coordination] + [black-start resources] + [mutual aid crews] # Constraint No single site or technology covers every season, every storm, or every load spike; resilience comes from diversity, transmission reach, disciplined maintenance, and the ability to curtail or shift non-critical demand when needed.