AFTERNOON INSIGHT
Your week was calm — no notable spikes in energy or budget. The weekend looks sunny, a good moment to tackle the garden reminders.
The nerve centre of the LOWI platform
This page will become a deeper look at Nidus: architecture, decisions and code. Content is coming soon.
In production · personal use
the choices first, then the screens
client / api / data / edge / ai
Drawn arrows only show connections confirmed in the existing copy.
Next.js · Vercel
Web dashboard: overview and control of the whole platform in the browser.
Expo / React Native · iOS
Mobile app for on the go, talks exclusively to nidus-api.
Fastify 5 / TypeScript · Railway · Frankfurt
Central business logic; the only component with write access to Supabase.
PostgreSQL · Frankfurt
Central storage with row-level security and auth.
FastAPI / Python · Railway
ML inference as a separate service alongside storage.
Community Edition · Cloud
Batch ML training and data pipelines.
Raspberry Pi · Thuisnetwerk
PM2 cron jobs for energy, location and sync.
LLM · Anthropic API
Reasoning and generation for Jarvis.
Decisions
No published formula exists for VLamax based on power or speed alone — confirmed by two independent literature reviews. Rather than continuing to chase a more precise approach, I used a pragmatic proxy (peak 3-second power × a constant, ~21% error margin) and explicitly labelled it 'indicative' in the interface. Sometimes the right technical decision isn't solving the problem, but admitting the available data won't support more precision — and communicating that honestly to the user.
The first version of the VO2max model reverse-engineered a constant from five test results, with an error margin over 20%. Switching to a published, speed-based formula (Ji et al., 2021) and calibrating only the individual constant brought that down to 4.71%. Lesson: a validated formula shape with one calibrated parameter beats a fully self-derived model.
Training blocks needed to be draggable at second-level precision, with power and heart-rate curves underneath. The existing chart library (Recharts) is used elsewhere in the app but isn't built for precise pointer interaction. Rather than forcing that library, I built a focused custom SVG component with its own pointer events — less reusable, but robust for exactly this problem.
When someone drags a training-block boundary, power and heart-rate averages need local recalculation without re-calling the ML model — which means the full curve has to stay available. Instead of a separate table with thousands of rows per session, I stored it as a JSONB column on the session table itself: the data logically belongs to that one session and is never queried on its own.
For this portfolio's AI assistant I had to choose: store conversation history server-side like the assistant in Nidus itself does, or keep it client-side and resend it with every question. For a short, anonymous portfolio visit, the benefit of server-side storage doesn't outweigh the cost: a new database table, a retention policy, and extra privacy surface for unknown visitors. Same technology, a deliberately different architecture for a different context.
Coming soon
Coming soon.