Compare commits
No commits in common. "6db1f353920e2c5c588cdf334b8b628a79173528" and "b56544faf92d7182898d862884d724d77e83462f" have entirely different histories.
6db1f35392
...
b56544faf9
6 changed files with 13 additions and 306 deletions
|
|
@ -1,47 +0,0 @@
|
||||||
# Token Efficiency Tips for KingDezigns / Fund Tracker Work with Claude
|
|
||||||
Last Updated: 2026-08-17
|
|
||||||
|
|
||||||
**Read this file first, before starting other work in this project.** It captures patterns observed across a long Fund Tracker build/deploy conversation that burned more tokens than necessary — mostly from long back-and-forth deployment troubleshooting. None of this changes what Claude can do, only how efficiently a conversation gets there.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## The single biggest lever: keep deployment troubleshooting out of long feature-build chats
|
|
||||||
|
|
||||||
The most token-expensive pattern in this project was doing one-command-at-a-time SSH deployment walkthroughs inside the same conversation as large feature builds. Every message in a conversation resends the *entire* prior conversation as context — so a 40-step deployment dialogue tacked onto a long build conversation costs far more than the same 40 steps would in a short, dedicated conversation.
|
|
||||||
|
|
||||||
**Better pattern:**
|
|
||||||
- Do feature/architecture work in one conversation.
|
|
||||||
- Start a **fresh conversation** for deployment of that specific change, referencing the relevant doc (e.g. `server_fundtracker.md`'s "Deployment pattern" section) instead of re-deriving the steps from scratch.
|
|
||||||
- If a deployment goes smoothly, a single message with the full sequence of commands (not one-at-a-time) is far cheaper than a guided back-and-forth — reserve the slow, one-step-at-a-time approach for genuine troubleshooting where you actually need to see each result before deciding the next step.
|
|
||||||
|
|
||||||
## Reference the docs instead of re-explaining context
|
|
||||||
|
|
||||||
This project's `.md` files (especially `server_fundtracker.md`) already capture the architecture, scoring methodology, deployment pattern, and known-issue history in detail. In a new conversation:
|
|
||||||
- Say what you want changed and point at the relevant doc section, rather than re-describing the whole system.
|
|
||||||
- If Claude's project knowledge already includes these files, it does not need them re-pasted into the chat — only reference them by name.
|
|
||||||
|
|
||||||
## Batch related changes into one request
|
|
||||||
|
|
||||||
Several rounds in this project asked for one small thing, got it built and deployed, then immediately asked for the next small thing — each round paying the fixed overhead of a fresh deployment walkthrough. Where changes are known in advance and not interdependent on seeing one work before starting the next, list them together in one request so they can be built and deployed together in a single pass.
|
|
||||||
|
|
||||||
## For routine, repeated deployment steps, prefer a real script over chat guidance
|
|
||||||
|
|
||||||
The deploy pattern for this project (SCP to a scratch directory → `sudo cp` into the OMV-managed project directory → rebuild or restart depending on what changed) is now stable and documented. A short deploy script run directly on KingDezigns001/NAS16 will do this identically every time without needing a guided chat conversation at all. Ask Claude to write that script once; use it going forward instead of a fresh guided walkthrough per deploy.
|
|
||||||
|
|
||||||
## When reporting an error, paste full context in one message
|
|
||||||
|
|
||||||
Partial command output followed by a follow-up asking for more context costs an extra round trip every time. Pasting the full command **and** its full output together the first time (even if it looks noisy) usually resolves faster than an incremental back-and-forth.
|
|
||||||
|
|
||||||
## Consider Claude Code for hands-on iterative work
|
|
||||||
|
|
||||||
Chat-based one-command-at-a-time debugging (as done throughout this project's deployment rounds) is a reasonable approach for a guided walkthrough, but is comparatively token-heavy since the growing chat history resends every turn. For hands-on iterative work where a guided explanation isn't needed — e.g., "get this deployed and fix whatever comes up" — an agentic coding tool with direct terminal/file access can iterate without accumulating a long resent chat history the same way.
|
|
||||||
|
|
||||||
## Don't ask Claude to re-verify things already proven
|
|
||||||
|
|
||||||
Once a piece of logic has been tested and confirmed working (e.g. the rebound-score algorithm, the auth/session flow), later requests can reference "the already-tested X" rather than asking for it to be re-explained or re-derived. Re-verification is worth doing after a *code change* to that logic, not as routine repetition.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Applying this going forward
|
|
||||||
|
|
||||||
The immediate next step for this project (as of 2026-08-17) is a specific, bounded list of ten items — user account self-service, admin-delete protection, timezone display, sidebar consistency, cookie/HTTPS confirmation, FQDN links, public signup with an admin toggle, and three open security/policy questions. That full list, with context, was handed off at the end of the build conversation specifically so it could be pasted into a **new** conversation rather than continuing an already-long one — apply the batching guidance above and consider tackling the concrete build items (1–7) together in one pass before circling back to the advisory questions (8–10).
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
# KingDezigns Network Documentation Index
|
# KingDezigns Network Documentation Index
|
||||||
Last Updated: 2026-08-17
|
Last Updated: 2026-07-26
|
||||||
|
|
||||||
This index provides a structured overview of all VLANs, servers, and firewall policies in the KingDezigns network.
|
This index provides a structured overview of all VLANs, servers, and firewall policies in the KingDezigns network.
|
||||||
Each section links to its own dedicated Markdown file for clarity and modularity.
|
Each section links to its own dedicated Markdown file for clarity and modularity.
|
||||||
|
|
@ -29,10 +29,9 @@ Each section links to its own dedicated Markdown file for clarity and modularity
|
||||||
## Core Services
|
## Core Services
|
||||||
- [Home Assistant Server](server_homeassistant.md)
|
- [Home Assistant Server](server_homeassistant.md)
|
||||||
- [NAS08 — Pi-hole, Nextcloud (+ ONLYOFFICE/Collabora), Vaultwarden, STOCKPROXY](server_nas08.md)
|
- [NAS08 — Pi-hole, Nextcloud (+ ONLYOFFICE/Collabora), Vaultwarden, STOCKPROXY](server_nas08.md)
|
||||||
- [NAS16 — LAMP Stack, MariaDB, Webmin, Forgejo, Fund Tracker](server_nas16.md)
|
- [NAS16 — LAMP Stack, MariaDB, Webmin, Forgejo](server_nas16.md)
|
||||||
- [PLEX32 — Plex Media Server + Tautulli](server_plex32.md)
|
- [PLEX32 — Plex Media Server + Tautulli](server_plex32.md)
|
||||||
- [Forgejo — Self-Hosted Git Server (hosted on NAS16)](server_forgejo.md)
|
- [Forgejo — Self-Hosted Git Server (hosted on NAS16)](server_forgejo.md)
|
||||||
- [Fund Tracker — Multi-Profile Mutual Fund/Stock Tracking (hosted on NAS16)](server_fundtracker.md)
|
|
||||||
|
|
||||||
## Network Hardware
|
## Network Hardware
|
||||||
- [UCG Gateway Max](server_ucg.md)
|
- [UCG Gateway Max](server_ucg.md)
|
||||||
|
|
@ -55,7 +54,6 @@ Each section links to its own dedicated Markdown file for clarity and modularity
|
||||||
- Firewall Bouncer enforces bans at nftables level
|
- Firewall Bouncer enforces bans at nftables level
|
||||||
- Email alerts on every ban decision
|
- Email alerts on every ban decision
|
||||||
- All LAN VLANs whitelisted — internal IPs can never be banned
|
- All LAN VLANs whitelisted — internal IPs can never be banned
|
||||||
- Applies automatically to every service proxied through NPM, including Forgejo and Fund Tracker — no per-service configuration needed
|
|
||||||
- See [Home Assistant Server](server_homeassistant.md) for full configuration details
|
- See [Home Assistant Server](server_homeassistant.md) for full configuration details
|
||||||
|
|
||||||
## Perimeter Defense (per server)
|
## Perimeter Defense (per server)
|
||||||
|
|
@ -69,9 +67,6 @@ Each section links to its own dedicated Markdown file for clarity and modularity
|
||||||
- All VLANs forced to use Pi-hole via global firewall rule 20001
|
- All VLANs forced to use Pi-hole via global firewall rule 20001
|
||||||
- **Local DNS overrides required** for any internally-hosted service accessed by its public hostname from within the LAN (e.g. `cloud.kingdezigns.com` → `192.168.150.30`), to avoid NAT hairpin failures. See `server_nas08.md` ONLYOFFICE section for a documented example and fix.
|
- **Local DNS overrides required** for any internally-hosted service accessed by its public hostname from within the LAN (e.g. `cloud.kingdezigns.com` → `192.168.150.30`), to avoid NAT hairpin failures. See `server_nas08.md` ONLYOFFICE section for a documented example and fix.
|
||||||
|
|
||||||
## Application-level Auth (per service, where applicable)
|
|
||||||
- **Fund Tracker** — session-cookie auth (httponly, bcrypt-hashed passwords), account lockout after 5 failed attempts, forced password change on new/seeded accounts, versioned legal-document acceptance gating. See `server_fundtracker.md`.
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
# 🌐 Network Architecture Overview
|
# 🌐 Network Architecture Overview
|
||||||
|
|
@ -182,7 +177,6 @@ A menu-driven launcher script provides one-click access to run scripts on PLEX32
|
||||||
No `coolwsd.xml` changes required. Full detail in `server_nas08.md`.
|
No `coolwsd.xml` changes required. Full detail in `server_nas08.md`.
|
||||||
- **Synaplan AI integration** (added 2026-07-18, not yet functional): Nextcloud connector app installed, but the required self-hosted Synaplan backend stack (PHP/MariaDB/Qdrant/optional Ollama) has not been deployed. Treat as a future project, not a bug — see `server_nas08.md` for details before troubleshooting.
|
- **Synaplan AI integration** (added 2026-07-18, not yet functional): Nextcloud connector app installed, but the required self-hosted Synaplan backend stack (PHP/MariaDB/Qdrant/optional Ollama) has not been deployed. Treat as a future project, not a bug — see `server_nas08.md` for details before troubleshooting.
|
||||||
- **Forgejo self-hosted Git server** (added 2026-07-26): Deployed on NAS16 (192.168.150.40) via Docker Compose — chosen over Gitea for non-profit/community governance (Codeberg e.V.). Public web UI at `https://forgejo.kingdezigns.com/` (proxied via NPM on HAS), SSH git access on port 2222 (LAN-only, no external port-forward). Provides version control with in-browser file editing/history for the `07 - Projects` folder on NAS16's share, organized as one Forgejo org per host (`NAS08`, `NAS16`, `PLEX32`) with a `<hostname>-scripts` repo in each. Data (`/opt/forgejo/data`) folded into the existing `nas16-backup.sh` job. A companion `forgejo_autosync.sh` script (not yet scheduled as of this writing) auto-commits/pushes any uncommitted changes on a timer as a safety net alongside normal manual commits. Full setup, config, and troubleshooting history in `server_forgejo.md`.
|
- **Forgejo self-hosted Git server** (added 2026-07-26): Deployed on NAS16 (192.168.150.40) via Docker Compose — chosen over Gitea for non-profit/community governance (Codeberg e.V.). Public web UI at `https://forgejo.kingdezigns.com/` (proxied via NPM on HAS), SSH git access on port 2222 (LAN-only, no external port-forward). Provides version control with in-browser file editing/history for the `07 - Projects` folder on NAS16's share, organized as one Forgejo org per host (`NAS08`, `NAS16`, `PLEX32`) with a `<hostname>-scripts` repo in each. Data (`/opt/forgejo/data`) folded into the existing `nas16-backup.sh` job. A companion `forgejo_autosync.sh` script (not yet scheduled as of this writing) auto-commits/pushes any uncommitted changes on a timer as a safety net alongside normal manual commits. Full setup, config, and troubleshooting history in `server_forgejo.md`.
|
||||||
- **Fund Tracker multi-profile mutual fund/stock tracker** (added 2026-08-17): Deployed on NAS16 (192.168.150.40) via Docker Compose — FastAPI + PostgreSQL, containers `fundtracker_api`/`fundtracker_db`. Public web UI at `https://funds.kingdezigns.com/` (proxied via NPM on HAS, Force SSL). Core design: security data (ticker, price history, group classification) is shared across all profiles and synced once regardless of how many profiles track it; each profile's holdings, cost basis, and watchlist membership are private. Scoring built from quality (risk-adjusted), opportunity (quality + genuine price dip, requires both a return z-score AND a drawdown-from-high to agree), combined (harmonic mean of quality+opportunity), and rebound (peer-relative "usually near the top of its group, currently collapsed" detector, reconstructed retroactively from existing price history) scores. Market data via `yfinance` + `curl_cffi` Chrome-impersonation session — required to avoid Yahoo Finance's bot-detection blocking, and a real fix (not a sandbox artifact). Session-cookie auth (httponly, bcrypt), admin role with anonymized cross-profile Census and versioned legal-document (Terms of Use + Investment Disclaimer) publishing — a version bump immediately requires every profile to re-accept. Daily sync + personalized-per-profile email report runs via an in-process APScheduler inside the container at 06:00 UTC, **not** an OMV Scheduled Job. Full architecture, scoring methodology, deployment pattern (code-only changes = folder swap + restart; dependency changes = rebuild; compose/env changes = `up -d`; structural DB migrations require a `pg_dump` backup first), and known-issue history in `server_fundtracker.md`.
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
@ -201,9 +195,7 @@ Additional files may be added for:
|
||||||
- **Synaplan self-hosted AI stack deployment** (PHP backend, MariaDB, Qdrant, optional Ollama) — scope resource requirements and deployment plan when ready
|
- **Synaplan self-hosted AI stack deployment** (PHP backend, MariaDB, Qdrant, optional Ollama) — scope resource requirements and deployment plan when ready
|
||||||
- **Collabora vs. ONLYOFFICE trial decision** (started 2026-07-21) — once a winner is chosen, update `server_nas08.md` and this index to reflect the final state (remove trial framing, decommission or keep the losing container, update firewall/NPM docs if the losing editor's proxy host is removed)
|
- **Collabora vs. ONLYOFFICE trial decision** (started 2026-07-21) — once a winner is chosen, update `server_nas08.md` and this index to reflect the final state (remove trial framing, decommission or keep the losing container, update firewall/NPM docs if the losing editor's proxy host is removed)
|
||||||
- **STOCKPROXY hardening** — not yet stress-tested at full ~50-ticker scale for Yahoo-side rate limiting; revisit if widespread simultaneous lookup failures are observed
|
- **STOCKPROXY hardening** — not yet stress-tested at full ~50-ticker scale for Yahoo-side rate limiting; revisit if widespread simultaneous lookup failures are observed
|
||||||
- **Fund Tracker — pending feature work** (as of 2026-08-17, not yet built): self-service user account page (email update, relocated change-password), stronger primary-admin delete/demote protection, Eastern-time display throughout (currently UTC), always-visible logout control in the sidebar (currently inconsistent across pages per user report), confirmation of cookie/session behavior over the new HTTPS domain, fully-qualified-domain links everywhere (email + in-app) instead of the internal IP, public self-service signup with an admin on/off toggle and disclaimer acceptance, and open questions on geo-blocking / additional security hardening / anti-infiltration monitoring / PII collection policy. See the dedicated handoff summary provided at the end of the deployment conversation before starting this work.
|
|
||||||
- **Fund Tracker — pre-existing documentation gap fixed 2026-08-17:** the Forgejo proxy host (`192.168.150.40:3000`) was missing from `server_homeassistant.md`'s Current Proxy Hosts table despite Forgejo being deployed and documented since 2026-07-26 — added along with the new Fund Tracker entry.
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
# ✔️ End of Index
|
# ✔️ End of Index
|
||||||
|
|
@ -1,175 +0,0 @@
|
||||||
# Fund Tracker — Multi-Profile Mutual Fund & Stock Tracking Service
|
|
||||||
Device Type: **Docker Container (hosted on NAS16)**
|
|
||||||
Containers: **fundtracker_api**, **fundtracker_db**
|
|
||||||
IP Address: **192.168.150.40** (shares NAS16's host IP)
|
|
||||||
VLAN: **50 — Lab / Servers**
|
|
||||||
|
|
||||||
Last Updated: 2026-08-17
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 🧩 Role & Purpose
|
|
||||||
Fund Tracker is a self-hosted, multi-profile web service for tracking mutual funds and stocks, built to answer one specific question: *which securities are historically strong performers that are currently trading below where they normally sit* — a systematic "buy the proven dip" screen, rather than chasing whatever's up the most right now.
|
|
||||||
|
|
||||||
It is **not** a data source or execution platform — it pulls public price history (Yahoo Finance), computes a set of derived scores, and presents ranked, filterable, exportable views plus a daily email report. All investment decisions remain manual.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 🌐 Public Access
|
|
||||||
- **Domain:** `https://funds.kingdezigns.com/`
|
|
||||||
- **Proxy:** NPM on HAS (192.168.150.30) → `192.168.150.40:8000`
|
|
||||||
- **SSL:** Force SSL enabled, Let's Encrypt via NPM — same pattern as every other public KingDezigns service
|
|
||||||
- **Internal LAN access:** `http://192.168.150.40:8000/dashboard/` (unchanged, still works from VLAN 20)
|
|
||||||
- No CrowdSec/Fail2Ban changes were required — traffic proxied through NPM inherits the same protection (CrowdSec reads NPM's logs regardless of backend) as every other service behind it.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 🖥️ Architecture
|
|
||||||
|
|
||||||
### Stack
|
|
||||||
- **API:** FastAPI (Python 3.12), Docker container `fundtracker_api`
|
|
||||||
- **Database:** PostgreSQL 16 (Alpine), Docker container `fundtracker_db`, bind-mounted at `/opt/fundtracker/pgdata`
|
|
||||||
- **Frontend:** Vanilla HTML/JS/CSS (no build step), served directly by FastAPI's `StaticFiles` mount at `/dashboard/`
|
|
||||||
- **Scheduler:** APScheduler, in-process (not an OMV Scheduled Job) — runs the daily sync + report job inside the `fundtracker_api` container itself
|
|
||||||
- **Market data:** Yahoo Finance via the `yfinance` library, using a `curl_cffi` session with Chrome browser impersonation (see Known Issues below — this is required, not optional)
|
|
||||||
|
|
||||||
### Data model — shared securities, private watchlists
|
|
||||||
The core design decision: **security data is shared across all profiles, personal data is private.**
|
|
||||||
|
|
||||||
| Concept | Table | Shared or private | Contains |
|
|
||||||
|---|---|---|---|
|
|
||||||
| Security | `instruments` | **Shared** — one row per ticker, regardless of how many profiles track it | ticker, name, category, group tag, price history (via `price_points`), benchmark link |
|
|
||||||
| Watchlist entry | `watchlist_entries` | **Private** per profile | is_held, held_since, cost_basis — a profile's personal relationship to a shared security |
|
|
||||||
| Metric snapshot | `metric_snapshots` | Shared (security-level) | Daily-recorded quality/opportunity/combined/rebound scores, used for trend detection |
|
|
||||||
| Settings | `settings` | Private per profile | Currently just each profile's rebalance date |
|
|
||||||
|
|
||||||
**Practical effect:** if two profiles both track GOOGL, its price history is synced exactly once and shared instantly between them — adding a ticker someone else already tracks is immediate, no re-sync wait, no duplicate Yahoo API traffic. Only `is_held`/`cost_basis`/which-tickers-you-track are private; ticker, name, group, and all performance scores are identical for every profile tracking that security.
|
|
||||||
|
|
||||||
### Multi-profile auth
|
|
||||||
- Session-cookie based (httponly, `SameSite=Strict`), **not** JWT-in-localStorage — a cookie can't be read by injected JavaScript, meaningfully reducing XSS token-theft risk for a public-facing app
|
|
||||||
- Passwords hashed with `bcrypt`
|
|
||||||
- 5 failed login attempts locks the account for 15 minutes
|
|
||||||
- Forced password change on any seeded or admin-created account — cannot be skipped
|
|
||||||
- Admin role can create/delete/promote accounts, force password resets, and view the anonymized cross-profile Census (see below) — but is **not** shown other profiles' actual holdings or cost basis by design
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 📊 Scoring Methodology
|
|
||||||
|
|
||||||
All scores are computed from price history only (no fundamentals data). Four are per-security (shared, identical for every profile); one is per-holding (private).
|
|
||||||
|
|
||||||
### Quality score (0–100)
|
|
||||||
Long-run risk-adjusted strength, deliberately blind to short-term noise:
|
|
||||||
- 35% annualized Sharpe ratio
|
|
||||||
- 20% annualized Sortino ratio (downside-only volatility)
|
|
||||||
- 25% CAGR
|
|
||||||
- 20% consistency (% of historical rolling windows, of the selected length, that were positive)
|
|
||||||
|
|
||||||
Requires 30+ price points to compute; below that, returns null rather than a misleading number.
|
|
||||||
|
|
||||||
### Opportunity score (0–100)
|
|
||||||
`0.6 × quality + 0.4 × depressed-ness`. Depressed-ness requires **both** of the following to agree (via `min()`, not an average) — this was a deliberate fix after an early version let a low-volatility fund sitting exactly at its 52-week high still score as a strong "opportunity" purely on quality alone:
|
|
||||||
1. `current_return_zscore` — is the current rolling-window return unusual *for this specific security's own history*
|
|
||||||
2. `drawdown_from_52wk_high_pct` — is it actually below its recent peak, not just statistically unusual
|
|
||||||
|
|
||||||
### Combined score (0–100)
|
|
||||||
Harmonic mean of quality and opportunity (not a plain average) — deliberately punishes imbalance, so a security only scores high here if it's strong on **both** axes, not exceptional on one while mediocre on the other.
|
|
||||||
|
|
||||||
### Rebound score (0–100) — the core "proven leader, currently crashed" signal
|
|
||||||
Answers a different question than opportunity score: *does this security normally rank near the top of its peer group by raw return, and has it recently fallen hard in that ranking?* Reconstructed retroactively from price history already on file (no waiting for new data to accumulate) by:
|
|
||||||
1. Computing every security's rolling-window return, for every date, within its shared group tag (e.g. all `STOCK`-tagged securities)
|
|
||||||
2. Ranking them against each other on every date → a full history of peer-relative percentile rank per security
|
|
||||||
3. Comparing today's percentile to the security's own historical average percentile
|
|
||||||
4. Combining "how strong is it historically" and "how far has it fallen right now" via harmonic mean, same imbalance-punishing logic as combined score
|
|
||||||
|
|
||||||
Requires a peer group of 5+ securities sharing the same group tag to compute at all.
|
|
||||||
|
|
||||||
### Buy / Sell / Hold signal (held positions only)
|
|
||||||
A simple, explainable, threshold-based heuristic — not a black box, and explicitly documented as a screening aid rather than a trade instruction:
|
|
||||||
- **SELL** if quality has fallen below 40, or dropped 15+ points in the trailing 7 days, or the position is deeply below its own normal range with no rebound signal backing it up
|
|
||||||
- **BUY** (add to position) if opportunity ≥ 65 with quality ≥ 60, or rebound score ≥ 65
|
|
||||||
- **HOLD** otherwise
|
|
||||||
|
|
||||||
Trend-based triggers (the 7-day quality delta) only become meaningful once daily snapshots have accumulated for about a week post-deployment — this is a genuine cold-start limitation, not a bug.
|
|
||||||
|
|
||||||
### Quality lookback (adjustable, default 3 years)
|
|
||||||
All of the above can be restricted to a trailing window (6mo/1yr/2yr/3yr/5yr/all) rather than always using full history. This matters: a fund that compounded fast for several early years and has since flattened out will look artificially strong if scored on all-time history — the early years hide what it's actually doing now. Verified with a synthetic test: a fund with 4 strong years then 1 flat year scored 84.6 quality on all-history, 25.9 restricted to the trailing year.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 🔐 Admin Features
|
|
||||||
|
|
||||||
### Census (anonymized cross-profile leaderboard)
|
|
||||||
`Admin → Census` page. Aggregates every tracked security across **all** profiles, showing how many profiles track it and its shared performance scores — deliberately does **not** reveal which specific profile tracks what, consistent with the private-watchlist design above.
|
|
||||||
|
|
||||||
### Legal document versioning
|
|
||||||
Two independently-versioned, admin-editable documents, stored in the database:
|
|
||||||
- **Terms of Use** — gated immediately after login, blocks all dashboard access until accepted
|
|
||||||
- **Investment Disclaimer** — gated specifically before adding any ticker to a watchlist (not a one-time login gate)
|
|
||||||
|
|
||||||
Publishing a new version (`Admin → Accounts → Legal documents`) **immediately** requires every profile to re-accept before continuing — acceptance is tracked per specific version number, so a version bump is itself the "flag everyone to re-agree" mechanism, no separate manual flag needed. An admin can also force one specific account to re-accept without republishing for everyone.
|
|
||||||
|
|
||||||
> **Not a substitute for actual legal review.** The shipped default text is comprehensive boilerplate covering no-liability-for-losses, educational-use-only, no-fiduciary-relationship, and indemnification — drafted carefully, but worth having an attorney glance at given this is a public-facing tool touching real investment decisions.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 🐳 Docker Configuration
|
|
||||||
|
|
||||||
Managed via OMV → Services → Compose, project `fundtracker`, at `/Kingdezignsnas16/fundtracker/`.
|
|
||||||
|
|
||||||
### Key environment variables
|
|
||||||
| Variable | Purpose |
|
|
||||||
|---|---|
|
|
||||||
| `DATABASE_URL` | Postgres connection string |
|
|
||||||
| `SYNC_HOUR_UTC` / `SYNC_MINUTE_UTC` | Daily sync+report time (default 06:00 UTC) |
|
|
||||||
| `SMTP_HOST/PORT/USER/PASSWORD/FROM` | Same Zoho account used by every other KingDezigns notification |
|
|
||||||
| `ADMIN_SEED_USERNAME/PASSWORD/EMAIL` | Bootstrap admin, only used if the `users` table is completely empty |
|
|
||||||
| `SESSION_TTL_DAYS` | Login session length (default 14) |
|
|
||||||
| `COOKIE_SECURE` | **Must be `true`** now that this is exposed externally over HTTPS — `false` is LAN-testing-only and sends credentials in cleartext if left on over plain HTTP |
|
|
||||||
| `PUBLIC_BASE_URL` | Should be `https://funds.kingdezigns.com` — used to build password-reset email links |
|
|
||||||
| `REPORT_WINDOW_DAYS/LOOKBACK_YEARS/TOP_N` | Daily email report defaults |
|
|
||||||
|
|
||||||
### Deployment pattern (established across multiple rounds of iteration)
|
|
||||||
- **Code-only changes** (edits inside `api/app/`): copy the updated `app/` folder into the OMV project directory, then `sudo docker restart fundtracker_api`. A plain restart is sufficient since `app/` is bind-mounted.
|
|
||||||
- **New Python dependencies** (`requirements.txt` changes): a restart is **not** enough — requires `docker compose build --no-cache api` followed by `up -d`, since dependencies are baked into the image at build time.
|
|
||||||
- **Compose YAML / environment variable changes**: requires `up -d` (recreate), not `restart` — a plain restart reuses the old in-memory environment. This distinction caused real deploy failures twice during development (once for the `curl_cffi` fix, once for the `bcrypt` addition) before being nailed down.
|
|
||||||
- Because `/Kingdezignsnas16/fundtracker/` is root-owned (`drwx------`, contains DB credentials), file transfers land in a `rufusking`-writable scratch path first (e.g. `/tmp/ft_upload/`), then get moved into place with `sudo cp -r`.
|
|
||||||
|
|
||||||
### Database migrations
|
|
||||||
Two tiers, by risk:
|
|
||||||
- **Additive** (`ADD COLUMN IF NOT EXISTS`) — safe, runs on every startup, no backup needed.
|
|
||||||
- **Structural** (e.g. the shared-security/private-watchlist split, the per-profile settings conversion) — genuinely restructures data, including column drops. These are idempotent (safe to run repeatedly) but a `pg_dump` backup is taken before deploying any update in this category, restorable via `psql` into a fresh container.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## ⚠️ Known Issues & Fixes Already Shipped
|
|
||||||
|
|
||||||
- **Yahoo Finance blocking (fixed):** `yfinance`'s default HTTP client gets silently blocked by Yahoo's bot detection with increasing frequency — the library misreports this as "no data" rather than "blocked." Fixed by routing all requests through a `curl_cffi` session impersonating a real Chrome browser's TLS fingerprint.
|
|
||||||
- **Bogus-ticker crash (fixed):** a nonexistent ticker could make `yfinance`'s internal metadata lookup throw an unhandled exception (a JSON decode error) instead of just returning empty data, crashing the add-ticker request entirely. Now caught and treated as "0 rows synced," which correctly triggers the verification-failure flow instead.
|
|
||||||
- **Ticker verification with override:** adding a brand-new ticker attempts a real sync as verification. Zero rows returned prompts a warning with an explicit "add anyway" override (rather than a hard block) — specifically to handle legitimate cases like a recent ticker rename Yahoo hasn't caught up to yet (e.g. Siemens Energy's SMNEY → SMERY change).
|
|
||||||
- **Rate-limit-driven data source risk:** noted, not yet acted on — if Yahoo's blocking becomes more aggressive over time, alternative data sources may need evaluation. Deferred as a future consideration.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 💾 Backup
|
|
||||||
- `/opt/fundtracker/pgdata` (bind-mounted Postgres data) can fold into `nas16-backup.sh` the same way Forgejo's data was — not yet formally added as of this writing.
|
|
||||||
- A raw file-copy backup of a *live* Postgres directory can be inconsistent; `pg_dump` is the reliable method (see Deployment pattern above). Given nearly all price data is re-derivable by re-syncing from Yahoo, a stale/imperfect backup mainly costs a re-sync, not real data loss — the one exception is user accounts, watchlist memberships (which securities each profile tracks), cost basis, and legal-acceptance records, which are **not** re-derivable and are the actual reason to keep backups current.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 🧠 Summary for AI Systems
|
|
||||||
- Fund Tracker = **multi-profile mutual fund/stock tracking web app**, Docker Compose on NAS16, VLAN 50.
|
|
||||||
- Public at `https://funds.kingdezigns.com/` via NPM on HAS, Force SSL. Also reachable internally at `http://192.168.150.40:8000/dashboard/`.
|
|
||||||
- Two containers: `fundtracker_api` (FastAPI) and `fundtracker_db` (Postgres 16).
|
|
||||||
- **Shared security data, private watchlists**: ticker/price history/group tag are shared across all profiles; is_held/cost_basis/which-tickers-tracked are private per profile.
|
|
||||||
- Scoring: quality (risk-adjusted, security-level) → opportunity (quality + genuine dip, requires both z-score AND drawdown to agree) → combined (harmonic mean of quality+opportunity) → rebound (peer-relative "usually top of its group, currently collapsed" detector, reconstructed retroactively from existing price history).
|
|
||||||
- Buy/Sell/Hold signals apply only to positions flagged `is_held` — simple threshold heuristic, documented as a screening aid, not a trade instruction.
|
|
||||||
- Auth: httponly session cookies, bcrypt, 5-attempt lockout, forced password change on seeded accounts.
|
|
||||||
- Admin: account management, anonymized cross-profile Census, versioned legal document publishing (version bump = automatic re-acceptance requirement for everyone).
|
|
||||||
- Market data via `yfinance` + `curl_cffi` (Chrome impersonation) — required workaround for Yahoo's bot detection, not optional.
|
|
||||||
- Deployment: code-only changes = folder swap + `docker restart`; dependency changes = rebuild; compose/env changes = `up -d`. Structural DB migrations require a `pg_dump` backup first.
|
|
||||||
- `COOKIE_SECURE=true` and `PUBLIC_BASE_URL=https://funds.kingdezigns.com` must both be set now that this is publicly exposed — leaving `COOKIE_SECURE=false` on a public HTTPS deployment would send credentials in cleartext.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
# ✔️ End of File
|
|
||||||
|
|
@ -4,7 +4,7 @@ Hostname: **homeassistant**
|
||||||
IP Address: **192.168.150.30**
|
IP Address: **192.168.150.30**
|
||||||
VLAN: **50 — Lab / Servers**
|
VLAN: **50 — Lab / Servers**
|
||||||
|
|
||||||
Last Updated: 2026-08-17
|
Last Updated: 2026-07-21
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
@ -66,8 +66,6 @@ This placement ensures:
|
||||||
| 192.168.150.40:8080 | NAS16 service |
|
| 192.168.150.40:8080 | NAS16 service |
|
||||||
| 192.168.150.40:10000 | Webmin |
|
| 192.168.150.40:10000 | Webmin |
|
||||||
| 192.168.150.40:3670 | NAS16 service |
|
| 192.168.150.40:3670 | NAS16 service |
|
||||||
| 192.168.150.40:3000 | Forgejo — self-hosted Git server (`forgejo.kingdezigns.com`, Force SSL, see `server_forgejo.md`) |
|
|
||||||
| 192.168.150.40:8000 | Fund Tracker — multi-profile mutual fund/stock tracking web app (`funds.kingdezigns.com`, Force SSL, see `server_fundtracker.md` and `server_nas16.md`) |
|
|
||||||
| 192.168.150.35:8080 | NAS08 service |
|
| 192.168.150.35:8080 | NAS08 service |
|
||||||
| 192.168.150.35:8081 | NAS08 service |
|
| 192.168.150.35:8081 | NAS08 service |
|
||||||
| 192.168.150.35:8082 | NAS08 service |
|
| 192.168.150.35:8082 | NAS08 service |
|
||||||
|
|
@ -110,7 +108,6 @@ Internet → UCG Max → NPM (192.168.150.30:80/443)
|
||||||
- Banned IPs are blocked before traffic ever reaches NPM or backend services
|
- Banned IPs are blocked before traffic ever reaches NPM or backend services
|
||||||
- **Email notifications are handled externally by NAS16** — not by CrowdSec's native notification system
|
- **Email notifications are handled externally by NAS16** — not by CrowdSec's native notification system
|
||||||
- Native CrowdSec email notifications are **disabled** in profiles.yaml
|
- Native CrowdSec email notifications are **disabled** in profiles.yaml
|
||||||
- **Applies uniformly to every service proxied through NPM**, including Fund Tracker and Forgejo — no per-service CrowdSec configuration is required; anything routed through NPM inherits this protection automatically.
|
|
||||||
|
|
||||||
#### Active Collections
|
#### Active Collections
|
||||||
| Collection | Protects Against |
|
| Collection | Protects Against |
|
||||||
|
|
@ -281,15 +278,14 @@ These are essential for:
|
||||||
- Native CrowdSec email notifications are disabled — all alerting handled by NAS16 scripts.
|
- Native CrowdSec email notifications are disabled — all alerting handled by NAS16 scripts.
|
||||||
- The LAN whitelist postoverflow ensures no internal IP can ever be banned — critical for remote VPN recovery.
|
- The LAN whitelist postoverflow ensures no internal IP can ever be banned — critical for remote VPN recovery.
|
||||||
- CrowdSec Watchdog is enabled — it will auto-restart after system reboots.
|
- CrowdSec Watchdog is enabled — it will auto-restart after system reboots.
|
||||||
- **New public services only need a proxy host entry here** — CrowdSec/Fail2Ban protection applies automatically to anything proxied through NPM, no per-service security configuration needed.
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 🧠 Summary for AI Systems
|
## 🧠 Summary for AI Systems
|
||||||
- HAS = **automation hub + network reverse proxy + intrusion prevention** located in VLAN 50.
|
- HAS = **automation hub + network reverse proxy + intrusion prevention** located in VLAN 50.
|
||||||
- Runs Home Assistant core, Nginx Proxy Manager (port 81), CrowdSec Agent + LAPI (port 8080), and CrowdSec Firewall Bouncer.
|
- Runs Home Assistant core, Nginx Proxy Manager (port 81), CrowdSec Agent + LAPI (port 8080), and CrowdSec Firewall Bouncer.
|
||||||
- NPM is the single external ingress point for all internal web services, including Forgejo and Fund Tracker.
|
- NPM is the single external ingress point for all internal web services.
|
||||||
- CrowdSec is the single intrusion prevention layer — blocks at nftables before NPM, applies uniformly to every NPM-proxied service.
|
- CrowdSec is the single intrusion prevention layer — blocks at nftables before NPM.
|
||||||
- NPM logs are read via journald using SYSLOG_IDENTIFIER `addon_a0d7b954_nginxproxymanager`.
|
- NPM logs are read via journald using SYSLOG_IDENTIFIER `addon_a0d7b954_nginxproxymanager`.
|
||||||
- 60 active detection scenarios covering HTTP attacks, CVEs, brute force, and SSH.
|
- 60 active detection scenarios covering HTTP attacks, CVEs, brute force, and SSH.
|
||||||
- Community blocklist updates every 2 hours from CrowdSec Central API.
|
- Community blocklist updates every 2 hours from CrowdSec Central API.
|
||||||
|
|
@ -303,7 +299,6 @@ These are essential for:
|
||||||
- Requires multicast, mDNS, and UDP discovery across VLANs.
|
- Requires multicast, mDNS, and UDP discovery across VLANs.
|
||||||
- Uses Pi‑hole in VLAN 50 for DNS.
|
- Uses Pi‑hole in VLAN 50 for DNS.
|
||||||
- All proxied traffic to backends appears to originate from 192.168.150.30.
|
- All proxied traffic to backends appears to originate from 192.168.150.30.
|
||||||
- **Fund Tracker added 2026-08-17** — `funds.kingdezigns.com` → 192.168.150.40:8000, Force SSL. Full detail in `server_fundtracker.md`.
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ Hostname: **NAS16**
|
||||||
IP Address: **192.168.150.40**
|
IP Address: **192.168.150.40**
|
||||||
VLAN: **50 — Lab / Servers**
|
VLAN: **50 — Lab / Servers**
|
||||||
|
|
||||||
Last Updated: 2026-08-17
|
Last Updated: 2026-07-26
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
@ -13,7 +13,7 @@ NAS16 is the **dedicated LAMP stack and database server** for the KingDezigns ne
|
||||||
It runs **OpenMediaVault (OMV)** as its base OS, which manages nginx as the web GUI frontend.
|
It runs **OpenMediaVault (OMV)** as its base OS, which manages nginx as the web GUI frontend.
|
||||||
It provides backend services, web hosting, and database support for internal applications, development environments, and externally accessible virtual host websites.
|
It provides backend services, web hosting, and database support for internal applications, development environments, and externally accessible virtual host websites.
|
||||||
|
|
||||||
In addition to its LAMP role, NAS16 hosts the **CrowdSec external notification system**, **Forgejo** (self-hosted Git server), and, as of 2026-08, **Fund Tracker** — a multi-profile mutual fund/stock tracking web application.
|
In addition to its LAMP role, NAS16 hosts the **CrowdSec external notification system** — a pair of scripts that poll the CrowdSec LAPI on HAS and deliver split email alerts based on ban origin — and, as of 2026-07-26, **Forgejo**, the self-hosted Git server for the KingDezigns network.
|
||||||
|
|
||||||
This system is designed for:
|
This system is designed for:
|
||||||
- Web application hosting (internal and external)
|
- Web application hosting (internal and external)
|
||||||
|
|
@ -23,7 +23,6 @@ This system is designed for:
|
||||||
- External virtual host websites proxied through HAS (NPM)
|
- External virtual host websites proxied through HAS (NPM)
|
||||||
- CrowdSec email notification delivery (local attack alerts + CAPI daily digest)
|
- CrowdSec email notification delivery (local attack alerts + CAPI daily digest)
|
||||||
- Self-hosted Git version control for network-wide scripts and project files (Forgejo)
|
- Self-hosted Git version control for network-wide scripts and project files (Forgejo)
|
||||||
- Multi-profile mutual fund/stock tracking with automated daily email reports (Fund Tracker)
|
|
||||||
|
|
||||||
NAS16 operates entirely within VLAN 50 and benefits from the strict containment rules that prevent lateral movement into trusted networks.
|
NAS16 operates entirely within VLAN 50 and benefits from the strict containment rules that prevent lateral movement into trusted networks.
|
||||||
|
|
||||||
|
|
@ -73,8 +72,6 @@ This placement ensures:
|
||||||
- Database backend for internal applications
|
- Database backend for internal applications
|
||||||
- Development and testing environment
|
- Development and testing environment
|
||||||
- **CrowdSec external notification system** (see below)
|
- **CrowdSec external notification system** (see below)
|
||||||
- **Forgejo self-hosted Git server** (see below)
|
|
||||||
- **Fund Tracker mutual fund/stock tracking service** (see below)
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
@ -186,23 +183,6 @@ Full configuration, troubleshooting history, and operational details are documen
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 📈 Fund Tracker — Multi-Profile Mutual Fund/Stock Tracking (added 2026-08-17)
|
|
||||||
|
|
||||||
NAS16 hosts **Fund Tracker**, a self-hosted, multi-profile web application for tracking mutual funds and stocks — built around a "buy the proven dip" screening thesis: identifying securities that are historically strong performers but currently trading below where they normally sit, rather than simply chasing whatever's up the most.
|
|
||||||
|
|
||||||
- **Containers:** `fundtracker_api` (FastAPI, Python 3.12) and `fundtracker_db` (PostgreSQL 16), Compose-managed via OMV at `/Kingdezignsnas16/fundtracker/`
|
|
||||||
- **Web UI:** `http://192.168.150.40:8000/dashboard/` internally, public at `https://funds.kingdezigns.com/` (proxied via NPM on HAS, Force SSL)
|
|
||||||
- **Database:** PostgreSQL, bind-mounted at `/opt/fundtracker/pgdata`
|
|
||||||
- **Market data:** Yahoo Finance via `yfinance` + `curl_cffi` (Chrome browser impersonation — required to avoid Yahoo's bot-detection blocking)
|
|
||||||
- **Multi-profile design:** security data (ticker, price history, group classification) is shared across all profiles and synced once regardless of how many profiles track it; each profile's holdings, cost basis, and watchlist membership are private
|
|
||||||
- **Scoring:** quality (risk-adjusted), opportunity (quality + genuine price dip), combined (harmonic mean of both), and rebound (peer-relative "usually near the top of its group, currently collapsed" detector) — all derived purely from price history
|
|
||||||
- **Auth:** session-cookie based (httponly, bcrypt-hashed passwords), admin/user roles, versioned legal document acceptance (Terms of Use + Investment Disclaimer)
|
|
||||||
- **Daily job:** in-process scheduler (not an OMV Scheduled Job) syncs all tracked securities and emails each profile a personalized report of their own holdings/watchlist at 06:00 UTC
|
|
||||||
|
|
||||||
Full architecture, scoring methodology, deployment pattern, and known issues are documented separately in `server_fundtracker.md`.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 🗂️ Shared Permissions — NFS + rsync Backup
|
## 🗂️ Shared Permissions — NFS + rsync Backup
|
||||||
|
|
||||||
NAS16 receives rsync backups from NAS08 via `nas08_to_nas16_sync.sh` every 2 days. To ensure rsync can write files on the destination without errors, NAS16 uses the same `ncshare` group configuration as NAS08.
|
NAS16 receives rsync backups from NAS08 via `nas08_to_nas16_sync.sh` every 2 days. To ensure rsync can write files on the destination without errors, NAS16 uses the same `ncshare` group configuration as NAS08.
|
||||||
|
|
@ -354,12 +334,10 @@ This ensures internal VLAN 50 devices (including HAS) are never banned regardles
|
||||||
| Every 4 hours (0:00, 4:00, 8:00, 12:00, 16:00, 20:00) | `/usr/scripts/crowdsec/cs_local_digest.sh` | CrowdSec Local Attack Digest |
|
| Every 4 hours (0:00, 4:00, 8:00, 12:00, 16:00, 20:00) | `/usr/scripts/crowdsec/cs_local_digest.sh` | CrowdSec Local Attack Digest |
|
||||||
| Daily at 12:00 AM | `/usr/scripts/crowdsec/cs_digest.sh` | CrowdSec CAPI Digest |
|
| Daily at 12:00 AM | `/usr/scripts/crowdsec/cs_digest.sh` | CrowdSec CAPI Digest |
|
||||||
|
|
||||||
> Note: Fund Tracker's daily sync + per-profile email job (06:00 UTC) runs via an **in-process APScheduler inside the `fundtracker_api` container**, not an OMV Scheduled Job — it is not in the table above because OMV has no visibility into it. See `server_fundtracker.md`.
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 🧠 Summary for AI Systems
|
## 🧠 Summary for AI Systems
|
||||||
- NAS16 = **OMV-based LAMP + database server + CrowdSec notifier + Forgejo + Fund Tracker** in VLAN 50.
|
- NAS16 = **OMV-based LAMP + database server + CrowdSec notifier** in VLAN 50.
|
||||||
- Inbound allowed from VLAN 1, VLAN 20, local VLAN 50, and HAS proxy (192.168.150.30).
|
- Inbound allowed from VLAN 1, VLAN 20, local VLAN 50, and HAS proxy (192.168.150.30).
|
||||||
- Outbound blocked to all VLANs except local + DNS responses.
|
- Outbound blocked to all VLANs except local + DNS responses.
|
||||||
- Hosts Apache (virtual hosts), MariaDB, PHP, Webmin, and OMV management UI.
|
- Hosts Apache (virtual hosts), MariaDB, PHP, Webmin, and OMV management UI.
|
||||||
|
|
@ -374,8 +352,7 @@ This ensures internal VLAN 50 devices (including HAS) are never banned regardles
|
||||||
- CAPI cloud ban digest sent daily at midnight — single Python call handles 10,000+ decisions efficiently.
|
- CAPI cloud ban digest sent daily at midnight — single Python call handles 10,000+ decisions efficiently.
|
||||||
- CrowdSec API key stored in Vaultwarden under `CrowdSec NAS16-notifier`.
|
- CrowdSec API key stored in Vaultwarden under `CrowdSec NAS16-notifier`.
|
||||||
- **Gotcha:** when piping data into `python3 -` with a heredoc, the heredoc replaces stdin — pass data as an inline variable instead.
|
- **Gotcha:** when piping data into `python3 -` with a heredoc, the heredoc replaces stdin — pass data as an inline variable instead.
|
||||||
- **Forgejo:** Self-hosted Git server, Docker container `forgejo`, public at `https://forgejo.kingdezigns.com/` via NPM, SSH git access LAN-only on port 2222, SQLite DB, data at `/opt/forgejo/data` (folded into `nas16-backup.sh`). See `server_forgejo.md`.
|
- **Forgejo (added 2026-07-26):** Self-hosted Git server, Docker container `forgejo`, public at `https://forgejo.kingdezigns.com/` via NPM, SSH git access LAN-only on port 2222, SQLite DB, data at `/opt/forgejo/data` (folded into `nas16-backup.sh`). Hosts version control for `07 - Projects/NAS08`, `/NAS16`, `/PLEX32` — one Forgejo org per host, one `<hostname>-scripts` repo per org. See `server_forgejo.md` for full detail.
|
||||||
- **Fund Tracker (added 2026-08-17):** Multi-profile mutual fund/stock tracker. Docker containers `fundtracker_api` + `fundtracker_db`, public at `https://funds.kingdezigns.com/` via NPM Force SSL. Shared security data (ticker/price history/group) across profiles; private per-profile holdings/cost-basis/watchlist membership. Scoring built from quality/opportunity/combined/rebound scores derived from price history via `yfinance`+`curl_cffi`. Session-cookie auth, admin role with anonymized cross-profile Census and versioned legal-document publishing. Daily sync+report job runs via in-process APScheduler at 06:00 UTC, NOT an OMV Scheduled Job. Full detail in `server_fundtracker.md`.
|
|
||||||
- **Shared permissions:** `ncshare` group (GID 1001) shared by `www-data` and `rufusking` — must match NAS08 GID for rsync compatibility.
|
- **Shared permissions:** `ncshare` group (GID 1001) shared by `www-data` and `rufusking` — must match NAS08 GID for rsync compatibility.
|
||||||
- Default ACLs on `/export/kingdezignsnas-16/Public` ensure all rsync-written files inherit `ncshare` group permissions.
|
- Default ACLs on `/export/kingdezignsnas-16/Public` ensure all rsync-written files inherit `ncshare` group permissions.
|
||||||
- **NAS08→NAS16 sync script self-heals destination permissions on every run** — checks for `www-data:ncshare` ownership, runs `chown`/`chmod`/`setfacl` automatically if wrong. Flagged in email subject and body if it fires.
|
- **NAS08→NAS16 sync script self-heals destination permissions on every run** — checks for `www-data:ncshare` ownership, runs `chown`/`chmod`/`setfacl` automatically if wrong. Flagged in email subject and body if it fires.
|
||||||
|
|
@ -384,4 +361,4 @@ This ensures internal VLAN 50 devices (including HAS) are never banned regardles
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
# ✔️ End of File
|
# ✔️ End of File
|
||||||
|
|
@ -4,7 +4,7 @@ Hostname: **plex32**
|
||||||
IP Address: **192.168.150.45**
|
IP Address: **192.168.150.45**
|
||||||
VLAN: **50 — Lab / Servers**
|
VLAN: **50 — Lab / Servers**
|
||||||
|
|
||||||
Last Updated: 2026-08-19
|
Last Updated: 2026-07-12
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
@ -425,23 +425,6 @@ The daily update check intermittently failed with `error from registry: unauthor
|
||||||
|
|
||||||
Resolved — verified with a live production run; the script now correctly reports "Update available" with ready-to-run commands instead of a registry error.
|
Resolved — verified with a live production run; the script now correctly reports "Update available" with ready-to-run commands instead of a registry error.
|
||||||
|
|
||||||
### **Systemd Startup / NFS Dependency Fix (2026-08-19)**
|
|
||||||
After a system reboot at 8:53 AM, Plex failed to auto-start despite having `restart: unless-stopped` in `docker-compose.yml`.
|
|
||||||
|
|
||||||
**Root cause:** Docker started before remote NFS mounts (`/mnt/plex/media`) finished mounting, causing Docker container startup to abort on missing volume paths.
|
|
||||||
|
|
||||||
**Fix applied:**
|
|
||||||
- Created a systemd override for Docker service at `/etc/systemd/system/docker.service.d/override.conf`:
|
|
||||||
```ini
|
|
||||||
[Unit]
|
|
||||||
After=network-online.target remote-fs.target
|
|
||||||
Wants=network-online.target remote-fs.target
|
|
||||||
Reloaded daemon (sudo systemctl daemon-reload).
|
|
||||||
|
|
||||||
Verified drop-in file is actively picked up by docker.service.
|
|
||||||
|
|
||||||
Resolved — Docker will now delay container startup on boot until network mounts are fully established.
|
|
||||||
|
|
||||||
### **plex32_health_report.sh — Issues List Word-Wrapping Fix (2026-07-12)**
|
### **plex32_health_report.sh — Issues List Word-Wrapping Fix (2026-07-12)**
|
||||||
The "⚠ Issues Detected" block in the daily health report email was rendering each word of an issue message on its own line (e.g. "WARNING: NAS08 — Plex Config is getting full" appeared as one word per line) instead of as a single readable sentence.
|
The "⚠ Issues Detected" block in the daily health report email was rendering each word of an issue message on its own line (e.g. "WARNING: NAS08 — Plex Config is getting full" appeared as one word per line) instead of as a single readable sentence.
|
||||||
|
|
||||||
|
|
@ -493,25 +476,7 @@ Resolved — verified with a manual run; each issue now renders as one complete
|
||||||
- **`plex32_update_check.sh` fixed 2026-07-12** — added explicit `PATH` export to fix intermittent `docker pull` failures under root's cron environment; script now logs real `docker pull` error output on failure instead of a generic "could not reach registry" message. All three PLEX32 scheduled jobs run under root's crontab.
|
- **`plex32_update_check.sh` fixed 2026-07-12** — added explicit `PATH` export to fix intermittent `docker pull` failures under root's cron environment; script now logs real `docker pull` error output on failure instead of a generic "could not reach registry" message. All three PLEX32 scheduled jobs run under root's crontab.
|
||||||
- **`plex32_update_check.sh` fixed again 2026-08-04** — added a 3-attempt retry loop (30s apart) around `docker pull` to handle `lscr.io`'s transient `error from registry: unauthorized` failure (all layers pull successfully, then the final manifest step fails — a known registry-side token/rate-limit issue, not a credentials problem). Also re-added the `PATH` export from the 2026-07-12 fix, which had gone missing from the deployed script. Only a failure across all 3 attempts is now reported as `CHECK FAILED`; a retry success is noted inline in the email instead of being silently indistinguishable from a clean pull.
|
- **`plex32_update_check.sh` fixed again 2026-08-04** — added a 3-attempt retry loop (30s apart) around `docker pull` to handle `lscr.io`'s transient `error from registry: unauthorized` failure (all layers pull successfully, then the final manifest step fails — a known registry-side token/rate-limit issue, not a credentials problem). Also re-added the `PATH` export from the 2026-07-12 fix, which had gone missing from the deployed script. Only a failure across all 3 attempts is now reported as `CHECK FAILED`; a retry success is noted inline in the email instead of being silently indistinguishable from a clean pull.
|
||||||
- **`plex32_health_report.sh` fixed 2026-07-12** — fixed the "Issues Detected" email block rendering each word on its own line, caused by a multi-character `IFS='. '` split; issues are now newline-delimited and read back with a `while read` loop.
|
- **`plex32_health_report.sh` fixed 2026-07-12** — fixed the "Issues Detected" email block rendering each word on its own line, caused by a multi-character `IFS='. '` split; issues are now newline-delimited and read back with a `while read` loop.
|
||||||
- **`plex32_update_check.sh` updated 2026-08-18** — replaced heavy `docker pull` layer downloads with `skopeo inspect` for fast manifest digest comparisons. Adjusted Step 5 logic to prioritize "Updates Available" blue banner over non-fatal script check warnings.
|
|
||||||
- **Systemd override for Docker added 2026-08-19** — added `/etc/systemd/system/docker.service.d/override.conf` with `After=network-online.target remote-fs.target` and `Wants=network-online.target remote-fs.target` so Docker waits for NFS mounts on boot before starting containers.
|
|
||||||
---
|
---
|
||||||
|
|
||||||
# ✔️ End of File
|
# ✔️ End of File
|
||||||
|
|
||||||
### **Systemd Startup / NFS Dependency Fix (2026-08-19)**
|
|
||||||
After a system reboot at 8:53 AM, Plex failed to auto-start despite having `restart: unless-stopped` in `docker-compose.yml`.
|
|
||||||
|
|
||||||
**Root cause:** Docker started before remote NFS mounts (`/mnt/plex/media`) finished mounting, causing Docker container startup to abort on missing volume paths.
|
|
||||||
|
|
||||||
**Fix applied:**
|
|
||||||
- Created a systemd override for Docker service at `/etc/systemd/system/docker.service.d/override.conf`:
|
|
||||||
```ini
|
|
||||||
[Unit]
|
|
||||||
After=network-online.target remote-fs.target
|
|
||||||
Wants=network-online.target remote-fs.target
|
|
||||||
```
|
|
||||||
- Reloaded daemon (`sudo systemctl daemon-reload` blow).
|
|
||||||
- Verified drop-in file is actively picked up by `docker.service`.
|
|
||||||
|
|
||||||
Resolved — Docker will now delay container startup on boot until network mounts are fully established.
|
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue