Already Implemented
Migrated from the repository documentation set.
- Fresh VPS provisioned on Contabo (Ubuntu 24.04).
- Docker installed and configured.
- Docker Compose installed and configured.
- zsh installed.
- Shared Docker proxy network created for Traefik-routed stacks.
- Edge stack deployed and running (Traefik, Portainer, Kener).
- Edge stack runtime artifacts are split into
runtime/stacks/infrastructure/edge/docker-compose.traefik.yml,runtime/stacks/infrastructure/edge/docker-compose.portainer.yml, andruntime/stacks/infrastructure/edge/docker-compose.kener.yml. - Edge VPS env artifacts are split into per-service folders under
runtime/environments/vps/infrastructure/edge/{traefik,portainer,kener}. - Edge dev env templates are split into per-service folders under
runtime/environments/dev/infrastructure/edge/{traefik,portainer,kener}. - Traefik and Portainer were recreated from split edge artifacts in the approved change window and verified running.
- Portainer split runtime uses
portainer/portainer-ee:2.39.1to preserve compatibility with the existing Business Edition data volume. - Kener runtime env scaffolding is prepared in
runtime/environments/vps/infrastructure/edge/kener/.envandruntime/environments/vps/infrastructure/edge/kener/kener.env(host, origin, Redis URL template, SMTP values, and secret placeholders). - Kener overlay deployment remains active on VPS from
runtime/stacks/infrastructure/edgeusing the current split edge model. - Kener container is running and healthy (
rajnandan1/kener:v4.0.16) alongside existing edge services. - Kener public route validation from server source returns HTTP 200 at
https://kener.perspective-v.com. - Kener backend healthcheck returns HTTP 200 with body
okon direct container endpoint (/healthcheck). - Kener overlay keeps fallback private-only middleware as a commented NetBird line in
runtime/stacks/infrastructure/edge/docker-compose.kener.yml. - Uptime Kuma was retired completely from edge runtime: service removed from edge compose artifacts, container removed, data volume removed, and image removed from VPS.
- Traefik upgraded to v3.6 and pinned with DOCKER_API_VERSION=1.40 for Docker API compatibility.
- Let's Encrypt resolver moved to static Traefik config and verified active.
- NetBird deployed in Existing Traefik mode using combined netbird-server + dashboard.
- NetBird dashboard/API reachable at netbird.perspective-v.com.
- Traefik dashboard is protected by NetBird source allowlist plus Traefik basic auth; Portainer remains NetBird-only with built-in panel authentication; Kener is public and uses built-in panel authentication.
- Server-side NetBird-address validation confirms split admin-route behavior: Traefik dashboard returns HTTP 401 with basic-auth challenge on NetBird path while Portainer returns HTTP 200 app route; default-source checks return HTTP 403 (recorded in
docs/operations/validations/2026-04-15-netbird-route-validation.mdx). - Platform stack deployed from runtime/stacks/infrastructure/platform with Redis and RabbitMQ.
- Redis Insight is deployed in platform stack with active container/runtime env keys; route checks show HTTP 403 from default source and HTTP 200 on NetBird-address path (
docs/operations/validations/2026-04-15-netbird-route-validation.mdx). - Platform Redis host port is published on 6379 for developer access via
redis.perspective-v.com, while production containers continue using internal Docker hostredis. - Operations stack deployed from runtime/stacks/infrastructure/operations with Watchtower running,
DOCKER_API_VERSION=1.40, and Sunday 03:00 UTC schedule (0 0 3 * * 0). - Operations stack now runs dual scoped Watchtower services: baseline
watchtower(scope=none, weekly schedule) andwatchtower-fast(scope=fast, 1-hour interval3600). - Fast Watchtower now reads Gitea registry auth from the versioned Swarm secret
watchtower_gitea_registry_auth_v1; first authenticated poll is pending. - Runtime validation confirms active Watchtower commands: baseline
--scope none --schedule "0 0 3 * * 0"and fast--scope fast --interval "3600". - Operations stack now includes WUD (
getwud/wud:8.2.2) with persistent/store, Docker socket read-only access, and Discord trigger configuration sourced from VPS Operations.env. - WUD is exposed through Traefik at
wud.perspective-v.comwith NetBird-only middleware and security headers. - WUD container is healthy and serving HTTP on internal port 3000.
- Controlled WUD Discord trigger tests executed successfully through
/api/triggers/discord/main. - Non-NetBird source route check for
wud.perspective-v.comreturns HTTP 403 as expected. - WUD custom registry provider
custom.pvis configured with authenticated access tohttps://registry.perspective-v.comand is visible in WUD registries. - WUD watcher mode is set to discovery-by-default on VPS (
WUD_WATCHER_LOCAL_WATCHBYDEFAULT=true) so running containers are inventoried without per-container opt-in labels. - WUD tag-channel guardrails remain applied on selected services (Redis, RabbitMQ, MySQL, Verdaccio) using
wud.tag.includelabels. - Manual WUD full scan was executed through
POST /api/containers/watchafter watcher-mode change; inventory expanded from 4 to 25 running containers (includingdbskc-web). - Manual pre-upgrade rollback checkpoints were created for Verdaccio, Redis, RabbitMQ, and MySQL volumes under
tmp/backups/major-upgrade-20260410-215000. - Major runtime image upgrades were executed and are live: Verdaccio
6, Redis8-alpine, RabbitMQ4.2-management-alpine, and MySQL9.6-oraclelinux9. - Post-upgrade checks succeeded: Verdaccio endpoint ping returned HTTP 200, Redis authenticated PING returned PONG, RabbitMQ broker reports running on 4.2.5, and MySQL is healthy on 9.6.0.
- MySQL credential drift was remediated during the major upgrade window by controlled recovery-mode user alignment to live VPS
.envvalues forrootandappuser. - Dedicated
wud-monitorcredential was added to Registry basic-auth users and Operations WUD registry login was switched from admin towud-monitor. - Post-switch validation confirmed Registry
/v2/accepts the dedicated WUD credential (HTTP 200), and WUD still reportscustom.pvwith active container inventory. - Registry stack deployed from runtime/stacks/infrastructure/registry with Traefik basic-auth challenge on
registry.perspective-v.comand NetBird-only Registry Admin UI onregistry-admin.perspective-v.com. - Registry auth runtime cutover completed to basic-auth model; token-realm auth flow and
registry-auth-proxyare removed from active runtime behavior. - Registry Admin runtime uses internal registry endpoint
http://registry:5000on Docker network. - Dedicated
dbskc-ciregistry credential has been created on the deployed registry-admin runtime for dbskc image pipeline usage. - Shared registry auth file
/var/lib/traefik/registry-auth/registry.htpasswdis initialized on VPS with restricted permissions (600) and active user entries. - Traefik registry router now uses file-provider middleware (
registry-basic-auth@file) backed by the shared host htpasswd file. - Registry Admin is now wired to the same shared htpasswd file path (
RA_REGISTRY_HTPASSWD=/app/config/registry-auth/registry.htpasswd) so UI-managed users are shared with registry API auth source. - Post-rollout validation confirmed registry API still returns HTTP basic challenge and
docker loginsucceeds for admin using password-stdin. - Registry auth incident follow-up completed for
nishatcolony-ci: host/Traefik/Registry-Admin htpasswd checksums and entries were verified aligned, Traefik access logs confirmed user-specific pre-upstream 401s, and restarting onlytraefikrefreshed auth state sodocker loginnow succeeds for the newly managed user. - Registry auth refresh operating model is finalized as manual Traefik restart (including Portainer restart) after user credential changes when needed; no helper script rollout required for this phase.
- Registry ACL rows were normalized from anchored regex names to exact repository names for scoped CI user access consistency.
- Sync-blocking OCI-only debug tags were quarantined from active registry storage to restore Registry Admin catalog sync.
- Docker schema v2 compatible test image push validated (
library/alpine:ra-compat-v2), and Registry Admin catalog database repopulated. - Owner-approved direct VPS cutover to Docker Distribution v3 was executed by recreating the registry service from
runtime/stacks/infrastructure/registry; live container now runsregistry:3(distribution3.1.0). - Pre-cutover rollback artifacts for registry v3 migration were captured at
tmp/backups/registry-v3-cutover-20260413-225028includingregistry_registry_data.tgz,registry_registry_admin_data.tgz,registry_registry_admin_config.tgz, and image reference metadata files. - Post-cutover verification passed on VPS: registry API challenge remains
HTTP 401withWWW-Authenticate: Basic realm="traefik", and registry logs show successful authenticated repository/tag and manifest reads on existing images. - Post-cutover route validation from VPS source confirms access policy remains intact:
registry-admin.perspective-v.comreturnsHTTP 403for non-NetBird source and retiredregistry-ui.perspective-v.comnow returnsHTTP 404. - Feeds stack deployed from runtime/stacks/infrastructure/feeds with BaGet at nuget.perspective-v.com and Verdaccio at npm.perspective-v.com.
- BaGet Traefik basic auth removed; public restore/download works and publish remains API-key controlled.
- Repository-side feeds compose now keeps canonical BaGet and Verdaccio services only in
runtime/stacks/infrastructure/feeds/docker-compose.feeds.yml. - Repository-side feed env contracts now keep canonical feed keys in
runtime/environments/dev/infrastructure/feeds/feeds.dev.envandruntime/environments/vps/infrastructure/feeds/feeds.env. - Repository-side legacy feed bridge bootstrap helper was removed from
runtime/stacks/infrastructure/feeds/scripts/. - Repository-side feed runbook is now aligned to canonical endpoint operations in
runtime/stacks/infrastructure/feeds/README.md. - Repository-side Verdaccio auth policy is now hardened in
runtime/stacks/infrastructure/feeds/verdaccio/conf/config.yamlwithauth.htpasswd.max_users=-1, anonymous read/install (access: $all), and authenticated publish/unpublish ($authenticated). - VPS runtime feed validation confirms Verdaccio/BaGet auth behavior: registration blocked (
409), anonymous npm read allowed (200), unauthenticated npm write blocked (401), authenticated npm probe package available (200), BaGet no-key push rejected (401), and BaGet API-key push reached duplicate conflict path (409) with evidence indocs/operations/validations/2026-04-16-feeds-verdaccio-baget-auth-validation.mdx. - Repository-side feed env/runbook/state contracts are aligned to canonical endpoints
npm.perspective-v.com(Verdaccio) andnuget.perspective-v.com(BaGet). - Feed env artifacts now include
NPM_FEED_API_KEYinruntime/environments/dev/infrastructure/feeds/feeds.dev.env,runtime/environments/vps/infrastructure/feeds/feeds.env, and liveruntime/environments/vps/infrastructure/feeds/.env. - Azure Console pipeline now supports
NPM_FEED_API_KEYas the preferred npm publish secret inruntime/ci/azure-pipelines/build-and-push-console.yml, with backward-compatible fallback to legacy npm feed variables. - GitHub Actions Console pipeline now supports
NPM_FEED_API_KEYas the preferred npm publish secret inruntime/ci/github-actions/build-and-push-console.yml, with backward-compatible fallback to legacy npm feed variables. - CI consumers using npm feed auth are now synchronized to the same
NPM_FEED_API_KEYruntime value, and owner-confirmed CI npm install/publish validation passed (recorded indocs/operations/validations/2026-04-16-ci-npm-feed-api-key-validation.mdx). - CI consumers using NuGet feed auth are now validated with owner-confirmed CI NuGet restore/publish success against BaGet using
NUGET_FEED_URL/NUGET_FEED_TOKEN(recorded indocs/operations/validations/2026-04-16-ci-nuget-feed-token-validation.mdx). - Approved VPS feed retirement apply was executed from
runtime/stacks/infrastructure/feeds/docker-compose.feeds.ymlusing liveruntime/environments/vps/infrastructure/feeds/.envand orphan removal; running legacyprogetcontainer was removed. - Rollback snapshot and checksum for legacy ProGet data were captured at
tmp/backups/feeds-proget-retirement-20260416T180458Z(feeds_proget_packages.tarandfeeds_proget_packages.tar.sha256). - Residual legacy ProGet artifacts were removed from VPS runtime: Docker volume
feeds_proget_packagesand imageproget.inedo.com/productimages/inedo/proget:25.0.25. - Portainer first-install timeout issue resolved via container restart/recreate workflow.
- Uptime Kuma pinned to image version 2.2.1 in repository compose.
- Top-level repository folders renamed from planning to docs and deployed to prod.
- Runtime migration started: docs/docker moved to runtime/stacks and docs/ci moved to runtime/ci.
- dbskc CI templates were added under runtime/ci for GitHub Actions and Azure Pipelines with
deploy/dbskcbranch trigger anddbskc-webimage target. - Repository-side Identity/Graph/Console CI templates under runtime/ci are now aligned to deploy branches in both CI systems (
deploy/identity,deploy/graph,deploy/console). - Azure pipeline templates under runtime/ci now use
docker login --password-stdinwith explicit empty-secret guard checks for registry authentication. - Azure pipeline templates for
identity,graph, andconsolenow support feed URL/token contracts with legacy variable fallback compatibility. - dbskc CI credentials are validated (
dbskc-cilogin works) and dbskc pipeline push to private registry is successful with image visibility in Registry Admin. - dbskc VPS runtime env is now organized at
runtime/environments/vps/services/perspective-v/dbskc/.envwith tracked placeholderruntime/environments/vps/services/perspective-v/dbskc/dbskc.env. - dbskc website stack path is now organized at
runtime/stacks/services/perspective-v/dbskc. - dbskc stack was re-created with Watchtower fast-scope label (
com.centurylinklabs.watchtower.scope=fast) so it is targeted bywatchtower-fast. - Public route validation passed for
dbskc.com: HTTPS returns HTTP 200 and HTTP endpoint redirects to HTTPS (308). - Prepared the separate public
dev.dbskc.comNext.js deployment:websites-dev-dbskcSwarm manifest, VPS launcher, private Gitea image targetdev-dbskc-web, and fast Watchtower labels. Initial image build and route validation remain pending the application deployment-branch merge. - nishatcolony VPS runtime env is now organized at
runtime/environments/vps/services/perspective-v/nishatcolony/.envwith tracked placeholderruntime/environments/vps/services/perspective-v/nishatcolony/nishatcolony.env. - Repository-side Perspective-V service envs are now mirrored by service under
runtime/environments/vps/services/perspective-v/{identity,graph,console,dbskc,nishatcolony}with matching dev templates underruntime/environments/dev/services/perspective-v/{identity,graph,console,dbskc,nishatcolony}. - Repository-side Perspective-V service runbooks were updated to use service-local env paths inside the new mirrored structure.
- Repository-side Perspective-V compose now allows
identity+graph+consolestartup without api-gateway dependency by removing console hard dependency on api-gateway. - Repository-side standalone service artifacts were added for
identity,graph, andconsoleunderruntime/stacks/services/*with matching VPS tracked env templates underruntime/environments/vps/services/*. - Repository-side syassociates service artifacts were added under
runtime/stacks/services/syassociates.pk/{syassociates.pk,service.syassociates.pk}with matching env placeholders already present underruntime/environments/{dev,vps}/services/syassociates.pk. - Repository-side gateway/service wiring is aligned to the existing external
proxynetwork; no dedicated gateway-only network is required. - Repository-side routing model now keeps
consoleas direct Traefik public app whileidentityandgraphare marked as Kong upstream backends (no direct Traefik exposure). - Repository-side Watchtower label compliance sweep is complete for service stacks: all compose files under
runtime/stacks/servicesnow set bothcom.centurylinklabs.watchtower.enable=trueandcom.centurylinklabs.watchtower.scope=fast. - Repository-side service hardening sweep is complete for Traefik-exposed stacks: public services under
runtime/stacks/servicesnow pin Traefik runtime network withtraefik.docker.network=proxywhile keeping TLS + Let's Encrypt + security headers labels. - Repository-side service hardening sweep is complete for container readiness checks: healthchecks are now present on service stack containers including
arnexglobal,dbskc,nishatcolony, standaloneconsole, andperspective-vconsole. - Healthcheck compatibility remediation was applied for nginx/alpine web stacks (
console,arnexglobal,dbskc,nishatcolony, andperspective-vconsole):bash-dependent checks were replaced with shell-compatiblewgetprobes. consolecontainer was recreated fromruntime/stacks/services/perspective-v/console, and live container health is nowhealthy.- Repository-side service compose project-name normalization is complete: all compose files under
runtime/stacks/servicesnow declarename: "perspective-v". - nishatcolony website stack path is now organized at
runtime/stacks/services/perspective-v/nishatcolony. - Public route validation passed for
nishatcolony.pk: HTTPS returns HTTP 200 and HTTP endpoint redirects to HTTPS (301). - Non-production env templates moved to runtime/environments/dev.
- Non-production database env templates reorganized into per-engine folders under runtime/environments/dev/infrastructure/databases.
- Source-of-truth VPS stack artifacts were synced from prod/docker into runtime/stacks (edge, platform, operations, registry, feeds, netbird).
- Active VPS
.envfiles from prod/docker were moved to runtime/environments/vps. - Git ignore policy now tracks named env files under runtime/environments while keeping plain
.envfiles ignored. - Residual
.envfiles were removed from runtime/stacks and preserved under runtime/environments/vps. - Password and secret values in tracked named env files under runtime/environments/vps were replaced with example placeholder strings while preserving host/domain entries.
- Edge Traefik ACME runtime file is host-managed at /var/lib/traefik/letsencrypt/acme.json with file mode 600.
- Traefik service was re-recreated using edge service-local runtime env source-of-truth while keeping host ACME storage mounted at
/var/lib/traefik/letsencrypt. - runtime/stacks/infrastructure/netbird now contains active tracked NetBird artifacts (docker-compose.yml and config.yaml) with active VPS env at runtime/environments/vps/infrastructure/netbird/netbird.env.
- NetBird stack was recreated from runtime/stacks/infrastructure/netbird after latest-image breakage; both
netbird-serverandnetbird-dashboardare running on refreshed images. - NetBird dashboard compose wiring now loads VPS env via
env_file: ../../environments/vps/infrastructure/netbird/.env; post-fix checks confirm required AUTH/endpoint variables are present andhttps://netbird.perspective-v.com/api/instancereturns HTTP 200. - NetBird VPS env values for embedded IdP dashboard auth were corrected to keep
AUTH_CLIENT_SECRETempty in bothruntime/environments/vps/infrastructure/netbird/.envandruntime/environments/vps/infrastructure/netbird/netbird.env. - NetBird
dashboardservice was force-recreated fromruntime/stacks/infrastructure/netbirdafter env correction, and runtime container env now confirmsAUTH_CLIENT_SECRET=. - Transitional prod folder was removed after runtime sync completion.
- Database env files prepared from runtime/stacks/infrastructure/databases templates and DB engine bind IPs set to 0.0.0.0.
- MSSQL, PostgreSQL, MySQL, and MongoDB containers deployed from runtime/stacks/infrastructure/databases.
- pgAdmin, phpMyAdmin, and mongo-express admin services deployed from runtime/stacks/infrastructure/databases admin profiles.
- Traefik dynamic security config now includes
security-headers-allow-sameoriginfor pgAdmin-compatible Query Tool framing while keeping strict headers for other routes. - PostgreSQL stack pgAdmin router now uses
netbird-only@docker,security-headers-allow-sameorigin@fileto resolve pgAdmin Query Tool iframe refusal. - pgAdmin container was re-created from VPS PostgreSQL
.env, and running container labels now reflectsecurity-headers-allow-sameorigin@filemiddleware. - Database stacks were recreated using service-local VPS
.envfiles under runtime/environments/vps/infrastructure/databases/*/.env (not{service}.envplaceholders). - Live DB credentials were aligned to VPS
.envvalues and validated in running containers for MSSQL, PostgreSQL, MySQL, and MongoDB. - PostgreSQL + pgAdmin were re-recreated from
runtime/environments/vps/infrastructure/databases/postgres/.envand verified against live container env/auth checks. - PostgreSQL persisted credential drift remediation completed: after recreate from
.env, livepostgresrole password was reset to.envvalue and non-local auth now passes with.envwhile failing with placeholderpostgres.envpassword. - Mongo Express built-in auth credentials are now sourced from VPS
.env, and mongo-express is running with successful MongoDB authentication. - NetBird interface and server VPN IP detected on VPS (
wt0,100.83.72.162). - DB and Redis firewall cutover script executed; UFW now allows DB engine ports and Redis port 6379 only on NetBird interface (wt0).
- Redis developer hostname resolves publicly to VPS (
redis.perspective-v.com). - Friendly DB and DB UI hostnames resolve publicly to VPS.
- Server-side TCP probes to DB ports succeeded on NetBird IP and friendly DB hostnames.
- Object-storage runtime/env layout is now RustFS-only under
runtime/stacks/infrastructure/object-storage/rustfsandruntime/environments/{dev,vps}/infrastructure/object-storage/rustfs. - RustFS host bind-mount directories were created at
/var/lib/rustfs/dataand/var/lib/rustfs/logswith ownership10001:10001and mode750on data/logs. - RustFS server-local runtime env is active at
runtime/environments/vps/infrastructure/object-storage/rustfs/.envwith explicit non-default API credentials (RUSTFS_ACCESS_KEY/RUSTFS_SECRET_KEY). - RustFS stack deployed from
runtime/stacks/infrastructure/object-storage/rustfs;rustfscontainer is healthy and is now the sole active object-storage runtime. - RustFS NetBird-address validation path succeeds using SNI
--resolveto server NetBird IP: console UI endpoint/rustfs/console/index.htmlreturns HTTP 200 and API root returns XMLAccessDenied(backend reached, auth gate active). - NetBird client validation succeeded for RustFS key login: console at
rustfs.perspective-v.comauthenticated successfully when pointing server URL torustfs-api.perspective-v.comand using access/secret key credentials. - RustFS routes
rustfs.perspective-v.comandrustfs-api.perspective-v.comreturn expected HTTP 403 responses from non-NetBird sources. - Traefik ACME state now contains RustFS hostnames (
rustfs.perspective-v.com,rustfs-api.perspective-v.com). - RustFS DNS status is dual-stack complete:
rustfs.perspective-v.comandrustfs-api.perspective-v.comboth resolve with A (161.97.83.142) and AAAA (2a02:c207:2320:1427::1) records. - MinIO decommission completed:
miniocontainer removed,objectstorage_minio_datavolume removed, MinIO images (minio/minioandminio/mc) removed, and MinIO runtime stack/env artifacts removed from repository paths. - Runtime sweep (including ignored
.envfiles) confirms no remaining MinIO hostnames, MinIO internal endpoints, orMINIO_*app-env references underruntime/environmentsandruntime/stacks/services. - Gateway VPS env scaffolding is now present at
runtime/environments/vps/infrastructure/gateway/.env(live runtime source) andruntime/environments/vps/infrastructure/gateway/kong.env(tracked placeholder template). - Gateway runbook now documents VPS env paths in
runtime/stacks/infrastructure/gateway/README.md. - Gateway stack is deployed on VPS from
runtime/stacks/infrastructure/gatewayusingruntime/environments/vps/infrastructure/gateway/.env;kong-migrationscompleted and Kong is healthy. - Gateway route validation passed for current baseline:
api.perspective-v.comreaches Kong (HTTP 404 before service route provisioning), and non-NetBird access tokonga.perspective-v.comis denied (HTTP 403). - Konga NetBird-address path validation returns HTTP 200 (built-in login route reachable), and PostgreSQL metadata objects for Kong are confirmed present (
kong_userrole andkong_dbdatabase) indocs/operations/validations/2026-04-15-netbird-route-validation.mdx. - Kong Admin API exposure policy is enforced in runtime: no host-published admin ports, and Konga container can reach
http://kong:8001/statusover Docker network. - Ocelot-to-Kong parity artifacts were added under
runtime/stacks/infrastructure/gateway:ocelot-to-kong-mapping.mdandkong-bootstrap-ocelot.sh. - Kong bootstrap now manages full Ocelot parity set in DB mode with idempotent upserts for services, routes, request-transformer rewrites, protected-route JWT, route rate-limits, global CORS, global correlation-id, and issuer consumer credential.
- Ocelot migration route inventory is present in Kong with 5 services and 8 routes tagged
ocelot-migration. - Ocelot migration plugin inventory is present in Kong with expected bindings: global
cors+correlation-id, per-route request-transformer and rate-limiting, and JWT on protected routes only. - Ocelot migration JWT credential is present for consumer
ocelot-jwt-issuerwith keyhttps://identity.perspective-v.comand algorithmHS256. - Gateway bootstrap reliability hardening is implemented in
kong-bootstrap-ocelot.shwith bounded curl connect/max-time and retry controls plus corrected per-route plugin-id resolution by exact plugin name. - Gateway parity smoke evidence is captured for migrated public/protected routes with JWT allow/deny outcomes and upstream pass-through status codes.
- Dedicated gateway parity validation record is added at
docs/operations/validations/2026-04-16-gateway-ocelot-parity-validation.mdx, including route smoke matrix and request-transformer rewrite mapping. - Gateway compatibility routes are deployed and verified on public endpoint:
https://api.perspective-v.com/identity/docs/index.htmlreturns HTTP 200,https://api.perspective-v.com/identity/swagger/v1/swagger.jsonreturns HTTP 200,https://api.perspective-v.com/swagger/v1/swagger.jsonreturns HTTP 200, andhttps://api.perspective-v.com/resumenow resolves to upstream behavior (HTTP 400) instead of Kong route-miss HTTP 404. - Gateway gopher compatibility routes are deployed and verified with .NET-aligned mapping: Kong now has
graph-gopher-credential-public,graph-gopher-serviceprovider-public,graph-gopher-serviceprovideremail-public,graph-gopher-platform-public, andgraph-gopher-ui-public; API calls underhttps://api.perspective-v.com/graph/gopher/{credential,serviceprovider,serviceprovideremail,platform}resolve through explicit public routes, while UI paths/resumeand/gopher/{credential,serviceprovider,serviceprovideremail,platform}are passed through as UI endpoints (not rewritten to/graph/*). - Kong global CORS allow-headers now include Apollo GraphQL client headers (
apollographql-client-name,apollographql-client-version) in bootstrap and gateway env templates, removing preflight rejection for console-origin graph API requests. - Live Kong global CORS origins were updated on VPS to explicitly allow
https://console.perspective-v.comandhttps://hassan.taj.contact; preflight checks onhttps://api.perspective-v.com/graph/gopher/credentialnow return HTTP 200 with matchingaccess-control-allow-originfor both origins. - Live Kong route
graph-resume-publicnow allowsPOST,OPTIONS, and global CORS origins includehttps://hassantaj.github.io; preflight checks onhttps://api.perspective-v.com/graph/resumereturn HTTP 200 with matchingaccess-control-allow-originfor bothhttps://console.perspective-v.comandhttps://hassantaj.github.io. - Repository-side Kong bootstrap now includes additive graph parity routes
graph-docs-public(/graph/docs*->/docs*) andgraph-v1-protected(/graph/v1/*->/api/v1/*) with rate-limiting and JWT ongraph-v1-protectedonly. - Repository-side gateway artifacts now include graph v1/docs rollout documentation at
docs/operations/validations/2026-04-21-graph-v1-kong-access-validation.mdxanddocs/operations/change-records/cr-2026-04-21-graph-v1-kong-route-rollout.mdx. - Repository-side gateway client imports now include Hoppscotch-compatible OpenAPI template
runtime/stacks/infrastructure/gateway/client-imports/graph-v1-hoppscotch-openapi.json. - Owner-approved VPS apply for graph v1/docs gateway extension is complete;
kong-bootstrap-ocelot.shexecuted successfully and live route inventory now includesgraph-docs-publicandgraph-v1-protectedwith expected plugin bindings. - Post-apply graph v1/docs smoke checks are recorded:
/graph/docsreturns HTTP 500 (public route reached),/graph/v1/healthwithout JWT returns HTTP 401, and/graph/v1/healthwith valid JWT returns HTTP 500 (JWT allow-path reached upstream). - Post-apply CORS preflight for
OPTIONS /graph/v1/healthreturns HTTP 200 with expected allow-origin/method/header values forhttps://console.perspective-v.com. - Gateway stack now includes decK declarative automation state at
runtime/stacks/infrastructure/gateway/kong.ymlplus runbook sync guidance inruntime/stacks/infrastructure/gateway/README.md. - decK is installed natively on VPS host at
/usr/local/bin/deck(v1.58.0), local declarative validation now passes forruntime/stacks/infrastructure/gateway/kong.yml, and online connectivity is verified from host binary to Kong Admin API (deck gateway pingsucceeded). - Declarative gateway state drift cleanup is applied in
runtime/stacks/infrastructure/gateway/kong.yml: obsolete legacygraphservice/routes were removed so decK no longer proposes unintended route/service creation. - Ocelot-to-Kong graph parity in declarative state is now synchronized for versioned graph routes:
graph-resume-version-publicwas added (/graph/v{version}/resume/{endpoint}->/api/v{version}/resume/{endpoint}) andgraph-protectednow matches/graph/v{version}/{endpoint}with methodsGET,POST,PUT,DELETE,OPTIONSand rewrite to/api/v{version}/{endpoint}. - Owner-approved host-native decK sync was executed using rendered state (
envsubst < kong.yml) against live Kong Admin API; pre-sync showed route/plugin/JWT drift and post-sync diff returnedCreated: 0, Updated: 0, Deleted: 0. - Live JWT credential secret for consumer
ocelot-jwt-issueris now aligned to VPSKONG_JWT_HMAC_SECRETthrough decK sync. - Graph resume access-token route is now public: declarative route updated to regex and synced via decK so
/graph/v1/resume/GetByAccessTokenno longer returns Kong 401. - Graph service recovery is complete after owner-approved pull and recreate of
registry.perspective-v.com/graph:latest; container is nowrunningandhealthy(no restart loop). - Public docs endpoints are now accessible through Kong:
https://api.perspective-v.com/graph/docs/serves Scalar (GraphService APItitle) andhttps://api.perspective-v.com/identity/docs/index.htmlserves Swagger (IdentityService APItitle). - Root cause of prior graph docs outage was upstream runtime failure in
graphcontainer (GraphService.dllmissing at startup), not Kong route mismatch. - Outbound SSH spike incident triage completed on VPS host
161.97.83.142; active source was a root process./main 22 bune.txtfrom/tmp/.ICE-unix/.x/main(non-stack, host-level process chain). - Malicious process chain and detached screen session were terminated; outbound port 22 sockets from the offending PID dropped to zero.
- Suspicious artifact directory was copied for evidence to
/root/incident-2026-04-11/suspect/x-dir-copyand original path was quarantined as/tmp/.ICE-unix/.x.quarantined.<timestamp>. - Temporary outbound SSH containment was applied in UFW (
deny out 22/tcpfor IPv4 and IPv6). - SSH hardening applied: key-only auth enforcement (
AuthenticationMethods publickey), password/interactive auth disabled directives, root login constrained to key-only,MaxAuthTries=3, andLoginGraceTime=30. - Root password was rotated and
authorized_keystrust was reset to newly approved SSH keys. - Contabo VNC/remote console access was disabled after incident containment.
- VS Code SSH and Tabby SSH access were reset and re-approved with fresh trusted key material.
- SSH auth matrix was revalidated after config precedence fix (
/etc/ssh/sshd_config.d/50-cloud-init.confset toPasswordAuthentication no); effective runtime now showspasswordauthentication no,kbdinteractiveauthentication no, andauthenticationmethods publickey. - Unexpected immutable attribute on
/var/logwas removed to restore normal logging behavior. - Fail2ban was installed, enabled, and configured with active
sshdjail (backend=systemd) and live brute-force banning. - Post-incident persistence quick checks found no known indicator strings in systemd unit files or cron paths, and no root crontab entries were present.
- Uptime Kuma monitor inventory was audited and confirmed HTTP-only monitors; no SSH-type monitor was configured.
- Incident archive bundle was created in-repo at
Incidents/2026-04-12-0015-ssh-outbound-spike/with markdown reports and raw evidence exports for provider response and audit trail. - Same-day post-containment revalidation was captured at
2026-04-12T02:09:23+02:00: outbound TCP/22 remained inactive, process attribution showed inbound-onlysshdsessions, UFW outbound 22 deny remained active, and SSH/Fail2ban control snapshots were archived in evidence files23through30. - Permanent outbound SSH policy tooling was implemented at
runtime/stacks/infrastructure/operations/ssh-egress-policy.shwith script-managed exception lifecycle, append-only policy logging, GitHub-over-443 SSH client setup, and blocked-attempt scanning. - Outbound SSH deny was normalized to a logging-enabled dual-stack rule (
DENY OUT 22/tcpwith(log, out)for IPv4 and IPv6). - Root SSH client configuration for GitHub was pinned to
ssh.github.com:443and validated with effective config plus TCP reachability checks. ssh-egress-policy-maintenance.timerwas installed and enabled to run recurring exception-expiry sweeps and blocked-attempt scans.- Controlled outbound TCP/22 simulations now generate UFW block entries and policy detector events (
blocked-ssh-detected) captured in incident evidence. - SSH egress Discord webhook notifications were upgraded to Markdown templates (quote plus ordered-list structure) for exception open/close, blocked-detection alerts, and alert-test messages.
- SSH egress Discord webhook notification templates were refined to use underlined headings (instead of quote-style titles) plus ordered-list fields in embed descriptions.
- SSH egress alert investigation on 2026-04-17 confirmed recurring Discord alerts were detector false positives:
blocked-scanmatched inboundUFW BLOCKevents andDPT=22xxprefixes (for example2202and2222) as outbound SSH; live socket checks during investigation showed zero outbound connections to destination port 22. - Repository-side remediation for 2026-04-17 SSH egress false positives is now implemented in
runtime/stacks/infrastructure/operations/ssh-egress-policy.sh: blocked-scan keeps only outbound exactDPT=22events and blocked-alert snippet code fences are escaped to prevent shell command-substitution errors during Discord message formatting. - Approved VPS validation for the 2026-04-17 SSH egress fix is complete: replaying a known false-positive window produced zero matches under the updated filter, a controlled outbound probe to
198.51.100.22:22produced outbound exactDPT=22block matches, and directblocked-scanexecution (webhook-disabled test mode) logged detection without formatter shell errors. - Tier-1 database backup timer rollout was executed on VPS with repository root override (
/home/repo/contabo-server-setup) andtier1-db-backup.timeris active/enabled. - First successful Tier-1 manual backup run completed for postgres/mysql/mongodb/mssql with artifacts at
/home/repo/contabo-server-setup/tmp/backups/tier1-20260415T205728Z. - Backup manifest with checksum metadata was generated at
/home/repo/contabo-server-setup/tmp/backups/tier1-20260415T205728Z/manifest.csv. - First-run backup evidence was captured at
/home/repo/contabo-server-setup/tmp/backups/evidence/tier1-backup-evidence-20260415T205803Z.txt. - Repository Tier-1 backup policy artifacts were updated to strict rolling retention (keep newest 3) and weekly default schedule (Sunday 03:00 UTC) across
db-backup.sh,install-tier1-backup-timer.sh, systemd templates, and related runbooks, including explicit manual rerun guidance. - Approved VPS Tier-1 policy apply is complete: active systemd units now use
ExecStart=...db-backup.sh run --keep-last-backups 3andOnCalendar=Sun *-*-* 03:00:00. - Refreshed post-apply evidence was captured at
/home/repo/contabo-server-setup/tmp/backups/evidence/tier1-backup-evidence-20260416T222414Z.txt. - End-to-end PostgreSQL restore validation drill was completed from latest Tier-1 backup with measured RTO 196s and RPO 238s (both within 4h/1h targets), documented at
docs/operations/restore-validations/rv-20260415t210554z-postgres-tier1.mdx. - Restore drill evidence was captured at
/home/repo/contabo-server-setup/tmp/backups/evidence/restore-validation-20260415T210554Z.txt. - Encrypted Tier-1 Google Drive delivery is implemented in the repository:
db-backup.shdiscovers Swarm tasks, reads mounted secrets, writes PostgreSQL globals plus one collision-safe custom dump for every connectable non-template database, covers all non-system MySQL databases and MongoDB, uploads only behindDB_OFFSITE_ENABLED=true, verifies withrclone cryptcheck, retains 12 remote/3 local sets, and preserves partial staging on failure. MSSQL remains supported but excluded while its service is0/0. - Lightweight monitoring baseline is formalized with measured Kener/WUD/Watchtower footprint and no heavy observability stack (
docs/operations/baselines/lightweight-monitoring-baseline.mdx). - Controlled monthly DB maintenance schedule is formalized at first-Saturday 02:00 UTC with pre/post evidence requirements (
docs/operations/baselines/monthly-db-maintenance-schedule.mdx). - One tabletop drill was executed against the incident-response and host-integrity runbooks (
docs/operations/tabletop-drills/tt-20260415t220000z-ssh-egress-policy.mdx). - State/document taxonomy alignment is implemented in tracked docs: decision/state under
docs/state, operational artifacts underdocs/operations, and setup guidance underdocs/runtimewith refreshed references. - Current operator guide set is implemented under
docs/runtime, includingoverview.mdx, per-stack guides,environments.mdx,ci.mdx,wrapper-scripts.mdx, andservices/overview.mdx. - Legacy repository documentation folder
docs/was retired after migration;docs/is now the sole tracked documentation surface. - Cross-platform launcher scripts are implemented under
runtime/scriptsfor active infrastructure and service compose targets, backed by shared helper logic for live VPS.env, placeholder fallback, anddevtemplate resolution. - Zitadel identity provider is deployed from
runtime/stacks/infrastructure/zitadel/docker-compose.ymlas two containers: core API + console (ghcr.io/zitadel/zitadel:v4.15.2, h2c on :8080) and Login V2 UI (ghcr.io/zitadel/zitadel-login:v4.15.2, :3000), behind the shared edge Traefik on theproxynetwork. - Zitadel uses the shared Postgres on
postgres-networkand auto-creates databasezitadel_dband userzitadel_db_usrvia the Postgres admin connection on first init. - Zitadel external domain is
auth.perspective-v.comwith Traefik TLS termination (ExternalSecure=true,TLS_ENABLED=false, h2c backend); the OIDC issuer ishttps://auth.perspective-v.com. - Zitadel Traefik routing splits the single host:
/ui/v2/login/*and/route to the login container;/api(prefix-stripped) and all other paths route to the core over h2c. - Zitadel mints a
login-clientPAT and an admin service-account PAT (zitadel-admin-sa, IAM_OWNER) at init into the sharedzitadel-bootstrapvolume; the admin PAT drives post-init API configuration. - Zitadel instance domain policy sets
USERLOGINMUSTBEDOMAIN=falseso loginnames are bare usernames (the verified email also works to log in). - Zitadel org primary domain is set to
auth.perspective-v.com(custom, auto-verified) viaruntime/stacks/infrastructure/zitadel/set-org-primary-domain.sh, replacing the auto-generated<org>.<instance-domain>; the seeded admin username is normalized from the init-baked domain-qualified form to the bare username viaruntime/stacks/infrastructure/zitadel/normalize-admin-username.sh. - Zitadel runtime env lives at
runtime/environments/vps/infrastructure/zitadel/.env; the dev template with placeholder secrets isruntime/environments/dev/infrastructure/zitadel/zitadel.dev.env. - Zitadel SMTP is configured and active via the Admin API (host
fusion.mxrouting.net:465, implicit TLS, senderno-reply@perspective-v.com/ "Perspective-V"); theFIRSTINSTANCE_SMTPCONFIGURATION_*env keys only seed at first init, so on an existing instance SMTP is set through the Admin API (/admin/v1/smtpadd +_activate) or the console (Instance → Notifications → SMTP). - Zitadel operational guardrail: the
login-clientservice user must never be deactivated — it backs the Login V2 UI and deactivating it locks out all logins; event-store reactivation only updates one of Zitadel's three projection schemas (projections/auth/adminapi) so token validation stays broken, and recovery requires a re-init. Thezitadel-admin-saIAM_OWNER service account is the one safe to disable when not running API-driven config. - Zitadel stack setup guide is published at
docs/runtime/stacks/zitadel.mdx(registered indocs/docs.jsonand the Infrastructure Stacks index), covering the dev bring-up from the env template, post-init scripts, SMTP, validation, guardrails, and the re-init procedure. - Multi-Drive encrypted backup tooling is implemented under
operations/: shared env/lock/rclone helpers, Swarm-aware WordPress and database backups, root-only config preparation, safe diagnostics, systemd installers/reference units, and stubbed behavioral tests. - The four WordPress backup registries use active external Swarm volume names. Gorsi's
two sites route to
gorsistudio_crypt; dbskc, wcblahore, shared databases, and physical PostgreSQL snapshots route centrally. Both Nishat variants are outside backup scope. - WordPress archives contain the site database, volume files, and SHA-256 manifest; they are uploaded through rclone crypt, verified before cleanup/pruning, run last-day monthly at 03:00 UTC, and retain four remote archives per site.
- WordPress dry-runs now authenticate to MySQL and require the configured site database; WordPress and Tier-1 MySQL dumps disable GTID statements.
- Monthly PostgreSQL physical backup and guarded restore tooling is implemented under
operations/: onlinepg_basebackupwith included WAL/native manifest, four-remote and two-local sliding retention, a first-Sunday 04:00 UTC systemd installer, and isolated scratch restore guards for the PostgreSQL 18 volume layout. - WordPress, weekly logical database, and monthly physical workflows share a six-hour bounded-wait lock and retain source/upload/verification failures with sanitized evidence.
- The configuration contract is
/etc/contabo-backups/backup.envfor operations and writable/etc/contabo-backups/rclone.conffor OAuth/crypt state, both root-only; the tracked non-secret template remainsruntime/environments/dev/infrastructure/backups/backups.dev.env. - The encrypted Google Drive setup, multi-account onboarding, validation, diagnostics, restore, and approval-gated rollout guide is published at
docs/runtime/stacks/wp-backups.mdx; repository tests pass without real Docker, Google, or production mutations. - Approved production bootstrap began on 2026-08-14: rclone
1.60.1is installed and/etc/contabo-backups/{backup.env,rclone.conf}exists with required root ownership and0700/0600permissions. The four non-secret rclone remote sections are installed; both OAuth identities/quotas and both crypt configurations are now verified. This bootstrap was followed by the completed activation recorded below. - Encrypted canaries passed on both
contabo_cryptandgorsistudio_crypt: each upload matched withcryptcheck, downloaded through crypt with matching SHA-256, and appeared only as a.binobject through the underlying Drive remote. - First encrypted WordPress validation passed for
store.gorsistudio.com, including manifest verification, 4,411 restored volume entries, 12 restored MySQL tables, and complete scratch cleanup. The existing Tier-1 set also passed central upload, eight-artifactcryptcheck, PostgreSQL download checksum, scratch restore/query, and cleanup. Production services were not restarted and MSSQL remained0/0. - Final encrypted backup activation completed on 2026-08-14: the four-site WordPress
dry-run/real workflow passed; logical set
tier1-20260814T211722Zverified nine PostgreSQL databases plus globals, four MySQL databases, and MongoDB; physical setpostgres-physical-20260814T212317Zpassed cryptcheck, decrypted checksum validation, nativepg_verifybackup, isolated readiness/database-count/query checks, and scratch cleanup. DB_OFFSITE_ENABLEDandPOSTGRES_PHYSICAL_OFFSITE_ENABLEDare active withDB_ENGINES=postgres,mysql,mongodb. Weekly database, last-day WordPress, and first-Sunday PostgreSQL physical timers are enabled/active; both Drive destinations connect, final unit results are successful, and MSSQL remains0/0.- Large PostgreSQL native tar validation now consumes the complete listing without early-exit SIGPIPE false failures. Failed/unverified physical staging is excluded from automatic local retention; the blocked first attempt remains preserved with sanitized evidence.
- Docker Swarm is live on the VPS (single-node manager, advertise
161.97.83.142): 7 external overlay networks (proxy,platform,postgres-network,mssql-network,mysql-network,mongodb-network,object-storage), 30+ Docker secrets fromswarm/secrets/create-all-secrets.sh, and all activedatabase/platform/edge/panel/service/websites-*stacks deployed viaswarm/scripts/**. - Swarm data preservation: every stack maps its data volume to the original compose-named volume with
external: true(e.g.netbird_netbird_data,databases_postgres-data,perspective-v_dbskc_data); pre-migration data is intact. Emptyinfra-*/svc-*volumes created by the first (pre-mapping) deploy are orphans. - Traefik on Swarm publishes ports 80/443 in
mode: host(not the ingress mesh) so it sees real client IPs; without this, ingress SNAT (10.0.0.2) breaks thenetbird-only(100.64.0.0/10) allowlist that gates all admin UIs. Admin UIs (portainer, pgadmin, phpmyadmin, rustfs, konga, rabbitmq, redis-insight, mongo-express, registry-admin, wud, kong-admin, traefik dashboard) are reachable only over the NetBird VPN. swarm/secrets/create-all-secrets.shstrips surrounding quotes from.envvalues before creating secrets (quoted values likeMYSQL_PWD="…"otherwise store literal quotes and break auth).- Swarm services without
_FILEsupport are fed secrets via command wrappers: kener injectsKENER_SECRET_KEYandSMTP_PASSWORD; vaultwarden injectsADMIN_TOKEN(kept quoted in.envfor shell sourcing, soenv_filecannot deliver it unquoted). - Multi-service Swarm launchers load every fragment's owning environment source; website fragments retain per-service database variables.
- Zitadel Login V2 on Swarm needs a dedicated
PathPrefix('/ui/v2/login')router tozitadel-login(the corezitadelrouter excludes that prefix andzitadel-rootonly matches exact/). - Traefik dashboard on Swarm requires a dummy
traefik.http.services.*.loadbalancer.server.portlabel on the traefik service or the swarm provider drops the dashboard router ("port is missing"); dashboard basic-auth usesadmin-auth@file→/var/lib/traefik/registry-auth/registry.htpasswd(a single-file bind mount — edits need a traefik restart to take effect). - phpMyAdmin extra themes (darkwolf 5.2, boodark 1.2.0) are extracted to host
/var/lib/phpmyadmin/themes/*and bind-mounted inswarm/stacks/panels/phpmyadmin.yml.
Gitea Unified Package Registry Migration (2026-07-01)
-
Single Gitea instance deployed as a package-only registry (git features disabled: SSH off, registration disabled, no repos,
MAX_CREATION_LIMIT=0,DEFAULT_ALLOW_CREATE_ORGANIZATION=false, org menu trimmed to packages) atgitea.perspective-v.combehind edge Traefik with a valid Let's Encrypt cert; stackservice(swarm/stacks/services/gitea/gitea.yml) is 1/1 healthy (~112 MiB). -
The Swarm source now renders pgAdmin, phpMyAdmin, Mongo Express, Konga, Redis Insight, Portainer, WUD, and NetBird Dashboard from eight fragments in the
panelstack, preserving the role label, image digests, external volumes, and five-suspended/three-running baseline. -
Vaultwarden, Gitea, and RustFS now share
service; Zitadel runs inservice-zitadel. Their exact prior images and external data were preserved. Post-cutover checks passed: Vaultwarden/alive200, Zitadel/debug/ready200 and root 308, Gitea health 200 and registry challenge 401, and both RustFS routes remain NetBird-restricted. -
Stack launchers parse env values literally, load every service-local env source required by split stacks, and use
--resolve-image changed; all 15 canonical launchers render complete DEV service definitions. -
Production naming rollout evidence is recorded in
docs/operations/change-records/cr-2026-08-14-swarm-service-naming-rollout.mdx. -
Gitea serves ALL packaging under org owner
perspective-v: Docker images (gitea.perspective-v.com/perspective-v/<img>), npm (/api/packages/perspective-v/npm/), and NuGet (/api/packages/perspective-v/nuget/index.json). -
Gitea auth model is Gitea user + access token:
write:packagescope to push,read:packagescope to pull; admin user ispvadmin(Gitea reservesadmin). -
Gitea deploy artifacts use the shared
swarm/scripts/services/service.{sh,bat}launcher, VPS envruntime/environments/vps/infrastructure/scm/gitea/.env, dev templateruntime/environments/dev/infrastructure/scm/gitea/gitea.dev.env, andgitea_db_passwordinswarm/secrets/create-all-secrets.sh; a deploy-time fix removedDEFAULT_REPO_UNITS/DISABLED_REPO_UNITS(they emptied the fork-unit set and caused a fatalno default fork repository units found). -
All package data migrated into Gitea: NuGet 45 versions (from BaGet), Docker 20 tags across 11 repos (from old
registry.perspective-v.com), and npm@pv/core14 versions (from Azure DevOpspv-ngfeed); Verdaccio was empty (nothing to migrate). -
CI/CD pipeline templates repointed to Gitea endpoints +
perspective-vnamespace (runtime/ci/github-actions/*,runtime/ci/azure-pipelines/*,runtime/ci/README.md). -
WUD reconfigured to watch the Gitea registry: the WUD manifest (now
swarm/stacks/panels/wud.yml) and VPS env point togitea.perspective-v.com, with a dedicated Giteawud-monitoruser +read:packagetoken and recreatedwud_registry_passwordsecret; unquoted cron values in the operations env were also fixed. -
All 11 running services use Gitea images. The header-defined stack rollout restored
nishatcolony-webfrom source drift back to its existing Gitea image; both Nishat services are 1/1,nishatcolony.pkreturns 200, and the intended WordPress route atnew.nishatcolony.pkstill exposes its pre-existing 500. -
Legacy 5 package services were RETIRED and removed:
infra-registry(docker-registryregistry.perspective-v.com+ registry-adminregistry-admin.perspective-v.com) andinfra-feeds(ProGetproget.perspective-v.com+ BaGetnuget.perspective-v.com+ Verdaccionpm.perspective-v.com); their old hosts now return 404. Related secrets removed:registry_*,baget_api_key,npm_feed_api_key. -
Gitea usage/token guidance is published at
docs/runtime/stacks/gitea.mdx; the completed legacy-service retirement record isdocs/runtime/gitea-retirement-runbook.mdx. -
Swarm source and launchers are organized by runtime role, with one YAML fragment per active service and multi-file rendering validated for every stack.
-
The production role-layout rollout is complete: Redis, RabbitMQ, Watchtower, RustFS, Kong, NetBird, Panels, Traefik, and Kener run under their documented stack/service identities with preserved external state and image digests.
-
Kong's migration task now reads its PostgreSQL password from the existing Docker secret and completes successfully instead of remaining failed at
0/1. -
Host-wide backup and systemd tooling is active under
operations/; both production timers use the canonical paths and the retired compatibility executables have been removed. -
The header-defined production namespace rollout is complete: all 37 services now use the stack value declared by their manifest, with images, desired replicas, named volumes, secrets, routes, and access policies preserved. Kong's admin router now explicitly binds to its port-8001 Traefik service, and production backup dry-runs resolve the renamed
database_*tasks. -
Final rollout evidence is recorded in
docs/operations/change-records/cr-2026-08-14-swarm-header-stack-rollout.mdx. -
Pi-hole administration is now available at
pihole.home.perspective-v.comthrough Contabo Traefik withnetbird-only+security-headers. The route forwards over NetBird to100.83.117.37:8053and uses a dedicatedHost: pi.holebackend-header middleware required by Pi-hole v6. Public access returns 403; authorized NetBird access reaches/admin/loginwith HTTP 200 and a trusted Let's Encrypt certificate. Source/live dynamic-config hashes match and the installer drift check is clean.
Superseded by the Gitea migration
- SUPERSEDED (retired 2026-07-01): all Registry stack entries above (docker-registry
registry:3/distribution3.1.0, Registry Admin, shared htpasswd basic-auth model,wud-monitorregistry credential, registry v3 cutover) — replaced by the Gitea Docker package registry. - SUPERSEDED (retired 2026-07-01): all Feeds stack entries above (BaGet at
nuget.perspective-v.com, Verdaccio atnpm.perspective-v.com, ProGet retirement,NPM_FEED_API_KEY/NUGET_FEED_TOKENCI contracts against BaGet/Verdaccio) — replaced by Gitea npm/NuGet package endpoints.
Homelab LAN certificate export (2026-09-15)
- Added
operations/traefik/export-homelab-certs.pyto the repository. It reads/var/lib/traefik/letsencrypt/acme.jsonand emits only the six selected*.home.perspective-v.comPEM pairs needed by the private homelab edge. - The exporter fails closed on missing or malformed entries and writes no key material to logs. Existing Contabo Traefik routes, ACME renewal, and public listeners were not changed.
Contabo homelab split-DNS documentation (2026-09-15)
- Added docs/runtime/stacks/homelab.mdx, linked it from the runtime stack index and overview, and documented the public Contabo path versus the LAN Pi-hole path.
- Recorded the Namecheap/public-DNS boundary, PTCL F1611A LAN answer, Pi-hole application overrides, NetBird-only dashboard policy, and shared TLS certificate handoff in docs/state/dns-info.mdx.
- Added the exporter invocation and failure-handling guidance to operations/traefik/README.md; no production service, route, secret, or certificate store was changed by this documentation update.
Fumadocs documentation site (2026-10-10)
- Added a Next.js/Fumadocs frontend that serves the shared
docs/corpus while retainingdocs.jsonfor the existing Mintlify navigation configuration. - Added an isolated
websites-perspective-v-docsSwarm stack and a registry-authenticated launcher fordocs.perspective-v.com.