# INITKOA CONTEXT PACK repository: Rejean-McCormick/Konnaxion_Capsule_Manager source_commit: 9054fbb9c2f028b1030c7ba25ef45d9d4d16b4b2 source_mode: git working_tree_markdown: clean working_tree_selected: clean selection_mode: markdown wiki_source_commit: none wiki_working_tree_markdown: none policy_version: 2026-09-10.13 repo_files: 26 wiki_files: 0 source_files: 26 included_files: 26 excluded_files: 0 duplicate_files: 0 content_bytes: 706157 authority_counts: {"reference":26} content_role_counts: {"knowledge":26} generated_at: 2026-09-10T13:04:19-04:00 files: 26 content_sha256: fa167427feab1470736c8057a1748f9aac3142d3eb2a09e80eca6c0ed7d685ec ================================================================================================ FILE INDEX ================================================================================================ 01. [reference] [knowledge] docs/DOC-00_Konnaxion_Canonical_Variables.md | bytes=20887 | sha256=5931d3e737761ca6b0708978ef3eb8764b6214c1da87f6a552c3ca03e976df66 02. [reference] [knowledge] docs/DOC-01_Konnaxion_Product_Vision.md | bytes=16442 | sha256=73a442a8662c432a2fa4ede02a100847764f171d20eecbd28090f95e8334cbb3 03. [reference] [knowledge] docs/DOC-02_Konnaxion_Capsule_Architecture.md | bytes=20838 | sha256=ec7f2f524c76cb47e45d2313a62065c0709037df564423dec8a7b6ef924c8040 04. [reference] [knowledge] docs/DOC-03_Konnaxion_Capsule_Format.md | bytes=35302 | sha256=f5b2634c1d3517296515524e7f7ff3a0b4e994e00bf9dccef31891ec319ab297 05. [reference] [knowledge] docs/DOC-04_Konnaxion_Manager_Architecture.md | bytes=23172 | sha256=98b477b85903cfb8f072289acfea95f951332db5c44bd4f46db83e2d38342c19 06. [reference] [knowledge] docs/DOC-05_Konnaxion_Agent_Security_Model.md | bytes=29941 | sha256=a32a77f3a197fa638debb551363e5f833227eab22cd8f7a8adc8c23f364c1b0c 07. [reference] [knowledge] docs/DOC-06_Konnaxion_Network_Profiles.md | bytes=48379 | sha256=3629ebc4e880a46312236e03c43d61b9bad8cc0accac2393fe4298dffab03df9 08. [reference] [knowledge] docs/DOC-07_Konnaxion_Security_Gate.md | bytes=19071 | sha256=d751f2c2947a8af18ef36125e3b1cc539ab3a182ed4dfd595895c6eb3e5c975a 09. [reference] [knowledge] docs/DOC-08_Konnaxion_Runtime_Docker_Compose.md | bytes=41438 | sha256=81182fd86c03a49d26f90bd0fc95635b1a7a899c8a28d8a777e2bd587e0864b2 10. [reference] [knowledge] docs/DOC-09_Konnaxion_Backup_Restore_Rollback.md | bytes=31725 | sha256=61b390afd59da3e4c12e328f7efc0e1886e143e2861c3468d3dd03f442d5ec46 11. [reference] [knowledge] docs/DOC-10_Konnaxion_Builder_CLI.md | bytes=48385 | sha256=abad2df0bc7dfef67b5dc8fc1b9f0ad2a2c4cc67abc76c7337f4919199ee744c 12. [reference] [knowledge] docs/DOC-11_Konnaxion_Box_Appliance_Image.md | bytes=36334 | sha256=149f630651e1239345bcb8f0f3af7104aa433842fd3b466dc42adb0670fad8a9 13. [reference] [knowledge] docs/DOC-12_Konnaxion_Install_Runbook.md | bytes=36344 | sha256=dd8756fdaedcb63c683c16495edf32324dd7c0cd2aaa23158d6ba363da14d24f 14. [reference] [knowledge] docs/DOC-13_Konnaxion_Threat_Model.md | bytes=31694 | sha256=019ac09c9625f43448bac0df63a890b8f7a59bafb8899bdfacbbee46de0244ed 15. [reference] [knowledge] docs/DOC-14_Konnaxion_Operator_Guide.md | bytes=30044 | sha256=597ccb82ba63821d3afea0143b209e33cfb1b4dc0e5917ad553c3d71daeb774d 16. [reference] [knowledge] docs/DOC-15_Konnaxion_Developer_Guide.md | bytes=23110 | sha256=727fa7e59e09f67fe4ab4c453e28586f7c90610582543e3f083b9b7cfb1f6b6c 17. [reference] [knowledge] docs/DOC-16_Konnaxion_Manager_GUI_Technical_Contract.md | bytes=48068 | sha256=8e7785c59a59ce44f1c40f64ea9d2e06253d54d3878ff1eb0c669c7a4217f14d 18. [reference] [knowledge] docs/DOC-17_Konnaxion_GUI_Action_Coverage_Contract.md | bytes=26791 | sha256=62a12d92349211df0508b888ce8042ac4f3cfd1f03993c856f6e88095a9d0df2 19. [reference] [knowledge] docs/DOC-17A_Konnaxion_GUI_Action_Payload_Contract.md | bytes=22002 | sha256=6530d2d097b87e8617ecf1766ff758144b4114b67d5f4626679d635c51c2f445 20. [reference] [knowledge] docs/DOC-17B_Konnaxion_GUI_Action_UI_Test_Contract.md | bytes=14113 | sha256=f66c6d0f3c80e59ae1ee20e9bb2737b43fb9ee4be347200cebaf07dddf04b74d 21. [reference] [knowledge] docs/DOC-18_Konnaxion_GUI_Target_Modes.md | bytes=29493 | sha256=9642b502be6f219df0aba432029b49def5d029151630ad9cb67d8189c87bec19 22. [reference] [knowledge] docs/DOC-19_Konnaxion_GUI_Page_Split_Droplet_Payload_Contract.md | bytes=21458 | sha256=3dbe5aa0d419acfc607555dcae509dcd4e0d5b002f6b172828ad68016add457f 23. [reference] [knowledge] docs/DOC-20_Konnaxion_Package_Types_and_Artifact_Lifecycle.md | bytes=22051 | sha256=7f9bb8a4f2b393fb995f52a5116adbddf82f1806c6b2d2bbadacd48fbf288bbb 24. [reference] [knowledge] docs/DOC-22_SecurityDiag_Integration.md | bytes=2566 | sha256=b316997c059e375f58e2ace0cef1d9b32e7320c71c6a524d1f6f0eaaa3f4b084 25. [reference] [knowledge] docs/DOC-23_Capsule_Installed_Artifact_and_Composition_Contract.md | bytes=9253 | sha256=6386d267daa718d048f333023d6dd4e4a210afd020727d39be60ef09783d9f63 26. [reference] [knowledge] README.md | bytes=17256 | sha256=67da322c4a3e085d1385613d9d801238b01583d33aadbf654dcbb52eb204246f ================================================================================================ FILE: docs/DOC-00_Konnaxion_Canonical_Variables.md AUTHORITY: reference CONTENT_ROLE: knowledge CONTENT_SHA256: 5931d3e737761ca6b0708978ef3eb8764b6214c1da87f6a552c3ca03e976df66 CONTENT_BYTES: 20887 ================================================================================================ --- doc_id: DOC-00 title: Konnaxion Canonical Variables project: Konnaxion app_version: v14 param_version: kx-param-2026.04.30 status: canonical-draft owner: Konnaxion last_updated: 2026-04-30 depends_on: [] --- # DOC-00 — Konnaxion Canonical Variables ## 0. Purpose This document is the canonical reference for Konnaxion naming, paths, variables, profiles, ports, services, instance states, backup/restore/rollback resource statuses, CLI commands, and documentation alignment rules. Every other Konnaxion documentation file must align with this document. This document defines the target architecture for the new Konnaxion portable appliance/capsule system, not only the legacy VPS deployment. --- ## 1. Canonical Product Names | Concept | Canonical Name | Do Not Use | |---|---|---| | Main platform | `Konnaxion` | Connexion, Konexion, Konnexion | | Current application version | `Konnaxion v14` | V14 app, Konnaxion app, platform without version | | Portable deployment file | `Konnaxion Capsule` | magic file, bundle, random archive | | Capsule file extension | `.kxcap` | `.zip`, `.tar.gz`, `.konnaxion` | | Management application | `Konnaxion Capsule Manager` | launcher, installer, dashboard | | Local privileged system service | `Konnaxion Agent` | daemon, root helper, service helper | | Build tool | `Konnaxion Capsule Builder` | packager, compiler, exporter | | Plug-and-play dedicated machine | `Konnaxion Box` | local server, mini PC, generic appliance | | Installed runtime environment | `Konnaxion Instance` | installation, copy, local deploy | | Generic physical or virtual host | `Konnaxion Host` | random server, local machine | --- ## 2. Canonical Application Stack Konnaxion must always be described using the following stack: ```text Frontend: Next.js / React / TypeScript Backend: Django + Django REST Framework Database: PostgreSQL Background jobs: Celery Broker/result backend: Redis Reverse proxy: Traefik Media/static service: Nginx Runtime target: Docker Compose ``` Do not describe the target appliance architecture as Kubernetes, serverless, pure systemd, or static hosting unless a future architecture decision explicitly changes this document. --- ## 3. Canonical Product Architecture ```text Konnaxion Box └── Konnaxion Capsule Manager └── Konnaxion Agent └── Docker Compose Runtime └── Konnaxion Instance ├── traefik ├── frontend-next ├── django-api ├── postgres ├── redis ├── celeryworker ├── celerybeat ├── flower └── media-nginx ``` Canonical separation: ```text Capsule = code + images + manifest + profiles + templates Instance = data + secrets + logs + backups + media ``` The capsule is portable and mostly immutable. The instance is local, stateful, and environment-specific. --- ## 4. Canonical Capsule Format ### 4.1 File Naming Canonical capsule filename pattern: ```text konnaxion-v14-demo-YYYY.MM.DD.kxcap ``` Example: ```text konnaxion-v14-demo-2026.04.30.kxcap ``` Canonical variables: ```text CAPSULE_ID=konnaxion-v14-demo-2026.04.30 CAPSULE_VERSION=2026.04.30-demo.1 APP_VERSION=v14 ``` ### 4.2 Capsule Internal Structure Canonical `.kxcap` structure: ```text .kxcap ├── manifest.yaml ├── docker-compose.capsule.yml ├── images/ │ ├── frontend-next.oci.tar │ ├── django-api.oci.tar │ ├── traefik.oci.tar │ └── media-nginx.oci.tar ├── profiles/ │ ├── local_only.yaml │ ├── intranet_private.yaml │ ├── private_tunnel.yaml │ ├── public_temporary.yaml │ ├── public_vps.yaml │ └── offline.yaml ├── env-templates/ │ ├── django.env.template │ ├── postgres.env.template │ ├── redis.env.template │ └── frontend.env.template ├── migrations/ ├── seed-data/ ├── healthchecks/ ├── checksums.txt └── signature.sig ``` ### 4.3 Capsule Must Never Contain The capsule must never contain real production secrets. Forbidden inside `.kxcap`: ```text real DJANGO_SECRET_KEY real POSTGRES_PASSWORD real DATABASE_URL SSH private key API token Git token provider token unencrypted production DB dump complete .env file containing secrets private certificate key ``` The capsule may contain templates, defaults, non-secret examples, and schema definitions. --- ## 5. Canonical Paths ## 5.1 Legacy VPS Paths The following paths are legacy deployment paths from the historical VPS environment: ```text /home/deploy/apps/Konnaxion /home/deploy/apps/Konnaxion/backend /home/deploy/apps/Konnaxion/frontend ``` They must be marked as: ```text legacy_vps ``` They are not the canonical target paths for the capsule/appliance architecture. ## 5.2 Target Appliance Paths Canonical root path: ```text /opt/konnaxion ``` Canonical directory layout: ```text /opt/konnaxion/ ├── capsules/ ├── instances/ ├── shared/ ├── releases/ ├── manager/ ├── agent/ └── backups/ ``` Canonical backup storage: ```text /opt/konnaxion/backups// = canonical backup storage root /opt/konnaxion/instances//backups/ = optional instance-local pointer/cache/state directory ``` Canonical installed-artifact registry: ```text /shared/registry/installed-artifacts.json ``` Canonical artifact descriptor names: ```text source tree: capsule-artifact.yaml packaged capsule: artifact.yaml product-owned integrated contributions: contributions/* ``` The registry is deployment/discovery state. It must not contain product-owned routes, navigation, commands, inspectors, or presentation state. Backups must be treated as **application data recovery artifacts**, not full host snapshots. Normal Konnaxion backup/restore must never preserve or restore: ```text full disk image /tmp /dev/shm system crontabs user crontabs old authorized_keys old sudoers files unknown Docker volumes Docker daemon state Docker socket unverified host binaries ``` Canonical instance layout: ```text /opt/konnaxion/instances// ├── env/ ├── postgres/ ├── redis/ ├── media/ ├── logs/ ├── backups/ └── state/ ``` Canonical release layout: ```text /opt/konnaxion/releases// /opt/konnaxion/current -> /opt/konnaxion/releases/ ``` Canonical capsule storage: ```text /opt/konnaxion/capsules/.kxcap ``` --- ## 6. Canonical Identifiers | Entity | Canonical Variable | Example | |---|---|---| | Instance | `INSTANCE_ID` | `demo-001` | | Release | `RELEASE_ID` | `20260430_173000` | | Capsule | `CAPSULE_ID` | `konnaxion-v14-demo-2026.04.30` | | Application version | `APP_VERSION` | `v14` | | Capsule version | `CAPSULE_VERSION` | `2026.04.30-demo.1` | | Parameter version | `PARAM_VERSION` | `kx-param-2026.04.30` | | Network profile | `NETWORK_PROFILE` | `intranet_private` | | Exposure mode | `EXPOSURE_MODE` | `private` | --- ## 7. Canonical Network Profiles | Profile | Variable Value | Description | Default | |---|---|---|---| | Local only | `local_only` | Accessible only from the local machine | No | | Intranet private | `intranet_private` | Accessible from the LAN only | Yes | | Private tunnel | `private_tunnel` | Accessible through a private tunnel/VPN | No | | Public temporary | `public_temporary` | Temporarily exposed for demos | No | | Public VPS | `public_vps` | Full public VPS deployment | No | | Offline | `offline` | No external network exposure | No | Canonical default: ```env NETWORK_PROFILE=intranet_private EXPOSURE_MODE=private ``` Public exposure must never be the default. --- ## 8. Canonical Exposure Modes | Mode | Variable Value | Rule | |---|---|---| | Private | `private` | Default mode | | LAN | `lan` | Local network only | | VPN | `vpn` | Private tunnel only | | Temporary tunnel | `temporary_tunnel` | Public tunnel with mandatory expiration | | Public | `public` | Public deployment only for approved `public_vps` profile | Canonical public mode variables: ```env KX_EXPOSURE_MODE=private KX_PUBLIC_MODE_ENABLED=false KX_PUBLIC_MODE_DURATION_HOURS= KX_PUBLIC_MODE_EXPIRES_AT= ``` Rule: ```text If KX_PUBLIC_MODE_ENABLED=true, then KX_PUBLIC_MODE_EXPIRES_AT is mandatory. ``` --- ## 9. Canonical Ports ### 9.1 Allowed Entry Ports | Port | Usage | Public VPS | Intranet | Local | |---:|---|---:|---:|---:| | `443` | HTTPS via Traefik | Yes | Yes | Optional | | `80` | HTTP redirect to HTTPS | Yes | Optional | No | | `22` | SSH admin access | Restricted | Not recommended | No | ### 9.2 Always-Internal Ports | Port | Service | Rule | |---:|---|---| | `3000` | Next.js direct | Never public | | `5000` | Django/Gunicorn internal | Never public | | `5432` | PostgreSQL | Never public | | `6379` | Redis | Never public | | `5555` | Flower/dashboard | Never public | | `8000` | Django development server | Never public | ### 9.3 Forbidden Public Surfaces The following must never be exposed directly: ```text Next.js direct port Django direct port PostgreSQL Redis Flower/dashboard Docker daemon TCP socket Docker socket mount into app containers ``` --- ## 10. Canonical Routing All Konnaxion deployments must use the following routing model: ```text https:/// -> frontend-next https:///api/ -> django-api https:///admin/ -> django-api https:///media/ -> media-nginx ``` Traefik is the canonical public or LAN entry point. No user-facing request should directly target `frontend-next`, `django-api`, `postgres`, `redis`, or `celeryworker`. --- ## 11. Canonical Docker Services | Canonical Service Name | Role | |---|---| | `traefik` | Reverse proxy and only HTTP(S) entry point | | `frontend-next` | Next.js production frontend | | `django-api` | Django/Gunicorn API service | | `postgres` | PostgreSQL database | | `redis` | Redis broker/result backend | | `celeryworker` | Celery workers | | `celerybeat` | Celery scheduler | | `flower` | Celery monitoring, private only | | `media-nginx` | Media/static file service | | `kx-agent` | Local privileged agent for Manager actions | Avoid inconsistent names such as: ```text backend api web next frontend db cache worker ``` unless they are explicitly mapped to the canonical service names. --- ## 12. Canonical Environment Variables ## 12.1 Django ```env DJANGO_SETTINGS_MODULE=config.settings.production DJANGO_SECRET_KEY= DJANGO_DEBUG=False DJANGO_ALLOWED_HOSTS= DJANGO_ADMIN_URL=admin/ USE_DOCKER=yes SENTRY_DSN= ``` ## 12.2 Database ```env DATABASE_URL=postgres://konnaxion:@postgres:5432/konnaxion POSTGRES_HOST=postgres POSTGRES_PORT=5432 POSTGRES_DB=konnaxion POSTGRES_USER=konnaxion POSTGRES_PASSWORD= ``` ## 12.3 Redis and Celery ```env REDIS_URL=redis://redis:6379/0 CELERY_BROKER_URL=redis://redis:6379/0 CELERY_RESULT_BACKEND=redis://redis:6379/0 ``` ## 12.4 Frontend ```env NEXT_PUBLIC_API_BASE=https:///api NEXT_PUBLIC_BACKEND_BASE=https:// NEXT_TELEMETRY_DISABLED=1 NODE_OPTIONS=--max-old-space-size=4096 ``` ## 12.5 Konnaxion Manager Variables All capsule/manager variables must use the `KX_` prefix. ```env KX_INSTANCE_ID=demo-001 KX_CAPSULE_ID=konnaxion-v14-demo-2026.04.30 KX_CAPSULE_VERSION=2026.04.30-demo.1 KX_APP_VERSION=v14 KX_PARAM_VERSION=kx-param-2026.04.30 KX_NETWORK_PROFILE=intranet_private KX_EXPOSURE_MODE=private KX_PUBLIC_MODE_ENABLED=false KX_PUBLIC_MODE_EXPIRES_AT= KX_REQUIRE_SIGNED_CAPSULE=true KX_GENERATE_SECRETS_ON_INSTALL=true KX_ALLOW_UNKNOWN_IMAGES=false KX_ALLOW_PRIVILEGED_CONTAINERS=false KX_ALLOW_DOCKER_SOCKET_MOUNT=false KX_ALLOW_HOST_NETWORK=false KX_BACKUP_ENABLED=true KX_BACKUP_ROOT=/opt/konnaxion/backups KX_BACKUP_RETENTION_DAYS=14 KX_DAILY_BACKUP_RETENTION_DAYS=14 KX_WEEKLY_BACKUP_RETENTION_WEEKS=8 KX_MONTHLY_BACKUP_RETENTION_MONTHS=12 KX_PRE_UPDATE_BACKUP_RETENTION_COUNT=5 KX_PRE_RESTORE_BACKUP_RETENTION_COUNT=5 KX_COMPOSE_FILE=/opt/konnaxion/instances//state/docker-compose.runtime.yml KX_BACKUP_DIR=/opt/konnaxion/backups/// KX_HOST= KX_ALLOWED_INTEGRATION_CONTRACTS=koali-ui/v1,module-interface-manifest/v1 ``` `KX_ALLOWED_INTEGRATION_CONTRACTS` controls admission of public integrated-UI manifest contracts only. It does not make a composition host mandatory for a standalone product. --- ## 13. Canonical Security Gate Every Konnaxion Instance must pass a Security Gate before startup. ### 13.1 Security Gate Status Values | Status | Meaning | |---|---| | `PASS` | Compliant | | `WARN` | Non-blocking issue | | `FAIL_BLOCKING` | Startup forbidden | | `SKIPPED` | Not applicable for the selected profile | | `UNKNOWN` | Could not be verified | ### 13.2 Mandatory Security Gate Checks ```text capsule_signature image_checksums manifest_schema secrets_present secrets_not_default firewall_enabled dangerous_ports_blocked postgres_not_public redis_not_public docker_socket_not_mounted no_privileged_containers no_host_network allowed_images_only admin_surface_private backup_configured ``` ### 13.3 Blocking Failures The following checks must block startup if they fail: ```text capsule_signature image_checksums manifest_schema secrets_present secrets_not_default dangerous_ports_blocked postgres_not_public redis_not_public docker_socket_not_mounted no_privileged_containers no_host_network allowed_images_only ``` --- ## 14. Canonical Instance States | State | Canonical Value | |---|---| | Created but never started | `created` | | Capsule import in progress | `importing` | | Verification in progress | `verifying` | | Ready to start | `ready` | | Starting | `starting` | | Running | `running` | | Stopping | `stopping` | | Stopped | `stopped` | | Updating | `updating` | | Rolling back | `rolling_back` | | Recoverable issue | `degraded` | | Failed | `failed` | | Blocked by security | `security_blocked` | ## 14.1 Canonical Backup Resource Statuses Backup statuses are **resource statuses**, not Konnaxion Instance states. | Backup State | Canonical Value | |---|---| | Backup record created | `created` | | Backup running | `running` | | Backup verification running | `verifying` | | Backup verified and usable | `verified` | | Backup failed | `failed` | | Backup expired by retention policy | `expired` | | Backup deleted | `deleted` | | Backup quarantined by safety check | `quarantined` | ## 14.2 Canonical Restore Resource Statuses Restore statuses are **resource statuses**, not Konnaxion Instance states. | Restore State | Canonical Value | |---|---| | Restore planned | `planned` | | Restore preflight running | `preflight` | | Creating pre-restore backup | `creating_pre_restore_backup` | | Restoring database | `restoring_database` | | Restoring media | `restoring_media` | | Running migrations | `running_migrations` | | Running Security Gate | `running_security_gate` | | Running healthchecks | `running_healthchecks` | | Restore completed | `restored` | | Restore completed with issues | `degraded` | | Restore failed | `failed` | | Restore rolled back | `rolled_back` | ## 14.3 Canonical Rollback Resource Statuses Rollback statuses are **resource statuses**, not Konnaxion Instance states. | Rollback State | Canonical Value | |---|---| | Rollback planned | `planned` | | Rollback running | `running` | | Capsule pointer restored | `capsule_repointed` | | Data restored | `data_restored` | | Healthchecks running | `healthchecking` | | Rollback completed | `completed` | | Rollback failed | `failed` | --- ## 15. Canonical CLI The canonical CLI command is: ```text kx ``` Canonical public/operator command groups: ```bash kx capsule build kx capsule verify kx capsule import kx instance create kx instance start kx instance stop kx instance status kx instance logs kx instance backup kx instance restore kx instance restore-new kx instance update kx instance rollback kx instance health kx backup list kx backup verify kx backup test-restore kx security check kx network set-profile ``` Internal Agent operations may exist, but must not be documented as ordinary operator commands unless explicitly promoted here. Internal-only examples: ```bash kx backup preflight kx backup postflight kx instance stop-services kx instance fix-permissions ``` These internal operations are allowlisted Agent actions and should normally be invoked by the Manager, not by end users. Examples: ```bash kx capsule build --profile demo --output konnaxion-v14-demo-2026.04.30.kxcap kx capsule verify konnaxion-v14-demo-2026.04.30.kxcap kx capsule import konnaxion-v14-demo-2026.04.30.kxcap kx instance start demo-001 --network intranet_private kx instance backup demo-001 --class manual kx backup verify demo-001_20260430_230000_manual kx instance restore-new --from demo-001_20260430_230000_manual --new-instance-id demo-restore-001 kx instance health demo-001 kx security check demo-001 ``` --- ## 16. Canonical Documentation Files All Konnaxion appliance/capsule documentation must follow this naming plan: ```text DOC-00_Konnaxion_Canonical_Variables.md DOC-01_Konnaxion_Product_Vision.md DOC-02_Konnaxion_Capsule_Architecture.md DOC-03_Konnaxion_Capsule_Format.md DOC-04_Konnaxion_Manager_Architecture.md DOC-05_Konnaxion_Agent_Security_Model.md DOC-06_Konnaxion_Network_Profiles.md DOC-07_Konnaxion_Security_Gate.md DOC-08_Konnaxion_Runtime_Docker_Compose.md DOC-09_Konnaxion_Backup_Restore_Rollback.md DOC-10_Konnaxion_Builder_CLI.md DOC-11_Konnaxion_Box_Appliance_Image.md DOC-12_Konnaxion_Install_Runbook.md DOC-13_Konnaxion_Threat_Model.md DOC-14_Konnaxion_Operator_Guide.md DOC-15_Konnaxion_Developer_Guide.md ``` --- ## 17. Canonical Document Header Every documentation file must begin with this metadata block: ```yaml --- doc_id: DOC-XX title: project: Konnaxion app_version: v14 param_version: kx-param-2026.04.30 status: draft owner: Konnaxion last_updated: 2026-04-30 depends_on: - DOC-00_Konnaxion_Canonical_Variables.md --- ``` --- ## 18. Terms to Avoid | Avoid | Use Instead | |---|---| | magic file | `Konnaxion Capsule` | | app | `Konnaxion Capsule Manager` when referring to the manager | | daemon | `Konnaxion Agent` | | local server | `Konnaxion Box` or `Konnaxion Host` | | open to web | `KX_EXPOSURE_MODE=public` | | private mode | `NETWORK_PROFILE=intranet_private` or `private_tunnel` | | bundle | `Konnaxion Capsule` | | deployment | `Konnaxion Instance` when installed locally | --- ## 19. Documentation Alignment Rules Every future document must use: ```text Konnaxion Capsule Konnaxion Capsule Manager Konnaxion Agent Konnaxion Box Konnaxion Host Konnaxion Instance .kxcap KX_* variables canonical NETWORK_PROFILE values canonical Docker service names canonical ports canonical instance states canonical backup/restore/rollback resource statuses canonical CLI commands canonical backup paths and variables ``` Every future document must avoid inventing: ```text new service names new profile names new public ports new directory roots new state names new backup/restore/rollback statuses new security statuses new environment variable prefixes new backup path conventions ``` If a future document needs a new variable, profile, service, state, or term, update `DOC-00_Konnaxion_Canonical_Variables.md` first. --- ## 20. Canonical Target Statement The target system is: ```text Konnaxion as a portable, signed, plug-and-play capsule, managed by a local Capsule Manager and privileged Agent, private-by-default, deployable on a Konnaxion Box, intranet, private tunnel, temporary public tunnel, or hardened VPS, with minimal user configuration and mandatory security gates. ``` The legacy VPS deployment remains useful as historical reference, but the new target is the capsule/appliance architecture. --- ## 21. Fixed Decisions The following decisions are fixed by this document: ```text Source of truth document: DOC-00_Konnaxion_Canonical_Variables.md Target architecture: Konnaxion Capsule + Konnaxion Capsule Manager + Konnaxion Agent + Docker Compose Runtime Default network profile: intranet_private Default exposure: private Security model: private-by-default, deny-by-default, signed capsules only Runtime: Traefik + Next.js + Django + PostgreSQL + Redis + Celery + Nginx/media Target root path: /opt/konnaxion Manager variable prefix: KX_ Capsule extension: .kxcap Canonical backup root: /opt/konnaxion/backups// Canonical CLI: kx ``` ================================================================================================ FILE: docs/DOC-01_Konnaxion_Product_Vision.md AUTHORITY: reference CONTENT_ROLE: knowledge CONTENT_SHA256: 73a442a8662c432a2fa4ede02a100847764f171d20eecbd28090f95e8334cbb3 CONTENT_BYTES: 16442 ================================================================================================ # DOC-01_Konnaxion_Product_Vision.md ```yaml id="doc01-meta" doc_id: DOC-01 title: Konnaxion Product Vision project: Konnaxion app_version: v14 param_version: kx-param-2026.04.30 status: draft depends_on: - DOC-00_Konnaxion_Canonical_Variables.md canonical_terms: - Konnaxion - Konnaxion Capsule - Konnaxion Capsule Manager - Konnaxion Agent - Konnaxion Box - Konnaxion Instance - KX_* ``` --- # 1. Vision produit **Konnaxion** doit devenir une plateforme collaborative, éducative, civique et créative pouvant être déployée comme une **appliance portable, sécurisée et plug-and-play**. La cible produit n’est pas seulement une application web hébergée sur un VPS. La cible est : ```text id="vision-target" Konnaxion dans une capsule, installable sur une machine dédiée, opérable en intranet, activable en démo privée ou publique temporaire, avec configuration minimale, sécurité intégrée, et déploiement reproductible. ``` Konnaxion v14 existe déjà comme plateforme modulaire avec plusieurs domaines fonctionnels : **Kollective Intelligence**, **ethiKos**, **Konsultations**, **KeenKonnect**, **KonnectED** et **Kreative**. Ces domaines couvrent la réputation/expertise, le vote pondéré, les débats structurés, les consultations, les projets collaboratifs, l’éducation, les portfolios, les ressources de connaissance, la création culturelle et la conservation numérique. --- # 2. Formule produit La formulation officielle du produit cible est : ```text id="product-formula" Konnaxion = plateforme applicative modulaire Konnaxion Capsule = format portable signé Konnaxion Capsule Manager = application de gestion plug-and-play Konnaxion Agent = service système sécurisé Konnaxion Box = machine dédiée prête à l’emploi Konnaxion Instance = installation active avec données, secrets et état runtime ``` Le produit doit permettre à une organisation de brancher une machine, démarrer Konnaxion, choisir un mode réseau, et obtenir une URL fonctionnelle sans comprendre Docker, Traefik, PostgreSQL, Redis, Celery, ports, certificats ou fichiers `.env`. --- # 3. Positionnement Konnaxion doit être positionné comme : ```text id="positioning" Une plateforme modulaire de collaboration, consultation, intelligence collective, apprentissage, portfolio, projets et création culturelle, déployable en mode souverain, local, intranet ou public contrôlé. ``` Ce n’est pas : ```text id="not-positioning" un simple site web un simple CMS un simple dashboard Docker une app SaaS seulement un projet dépendant d’un seul VPS public ``` --- # 4. Objectif principal L’objectif principal est de transformer Konnaxion en système : ```text id="main-objective" portable reproductible privé par défaut sécurisé par défaut opérable sans expertise DevOps installable en local ou intranet extensible vers le web public lorsque nécessaire ``` Cela répond directement aux leçons du déploiement précédent : le VPS Namecheap a été compromis, avec conteneurs malveillants, persistence cron, miner, `/tmp/sshd`, tentative de backdoor sudo et secrets exposés. La nouvelle vision doit donc intégrer la sécurité dans le produit lui-même, pas seulement dans une procédure de déploiement. --- # 5. Publics cibles ## 5.1 Opérateur non technique Personne qui doit démarrer Konnaxion sans comprendre l’infrastructure. Exemples : ```text id="operator-persona" enseignant facilitateur responsable d’organisme coordinateur de projet animateur de consultation responsable de laboratoire citoyen ``` Besoin : ```text id="operator-need" brancher démarrer choisir le mode réseau ouvrir l’URL gérer backup/restore de base ``` ## 5.2 Administrateur technique léger Personne capable d’utiliser une interface d’administration, mais pas nécessairement de maintenir une stack complète. Besoin : ```text id="admin-need" voir l’état système changer le mode réseau ouvrir un tunnel temporaire faire un backup appliquer une mise à jour restaurer une instance consulter les logs ``` ## 5.3 Développeur Konnaxion Personne qui construit les capsules. Besoin : ```text id="developer-need" builder frontend/backend exécuter tests construire images Docker générer manifest signer capsule publier .kxcap valider sécurité ``` ## 5.4 Organisation hôte École, municipalité, OBNL, collectif, centre culturel, laboratoire, communauté ou équipe projet. Besoin : ```text id="org-need" contrôle local mode intranet démo privée données sous contrôle installation simple fonctionnement sans dépendre d’un SaaS externe ``` --- # 6. Problème à résoudre Le problème n’est pas seulement de “déployer Konnaxion”. Le problème est : ```text id="problem" Déployer une application complexe de manière fiable, sans exposer les services internes, sans dépendre d’un administrateur DevOps, sans recréer les failles du VPS compromis, et sans rendre l’installation trop complexe pour un contexte de démo ou intranet. ``` Konnaxion utilise déjà une stack complète : backend **Django 5.1 + Django REST Framework + Celery + Redis**, frontend **Next.js/React**, base **PostgreSQL** en production, et Redis comme broker/résultat Celery. Cette complexité doit être masquée derrière une expérience plug-and-play. --- # 7. Solution produit La solution cible est une architecture en quatre couches : ```text id="solution-layers" 1. Konnaxion Capsule Format portable signé contenant l’application et sa configuration déclarative. 2. Konnaxion Capsule Manager Interface locale qui importe, démarre, arrête, met à jour et surveille une instance. 3. Konnaxion Agent Service système privilégié, limité et audité, qui contrôle Docker, firewall, réseau et backups. 4. Konnaxion Runtime Stack Docker Compose isolée exécutant Traefik, Next.js, Django, PostgreSQL, Redis, Celery et Nginx/media. ``` --- # 8. Expérience utilisateur cible ## 8.1 Premier démarrage L’expérience idéale : ```text id="first-run" 1. Brancher la Konnaxion Box. 2. Ouvrir Konnaxion Capsule Manager. 3. Importer ou sélectionner une Konnaxion Capsule. 4. Choisir un profil réseau. 5. Créer ou générer le compte admin. 6. Cliquer Démarrer. 7. Obtenir une URL. ``` L’utilisateur ne doit pas configurer : ```text id="hidden-complexity" Docker Traefik PostgreSQL Redis Celery Nginx certificats ports internes .env migrations firewall systemd ``` ## 8.2 Écran principal attendu ```text id="main-screen" Instance: demo-001 État: running Profil réseau: intranet_private URL: https://konnaxion.local Sécurité: PASS Backup: activé [Ouvrir Konnaxion] [Changer profil réseau] [Créer backup] [Voir logs] [Arrêter] ``` --- # 9. Profils réseau produit Les profils réseau doivent remplacer la configuration manuelle. ```text id="network-profiles" local_only intranet_private private_tunnel public_temporary public_vps offline ``` Le profil par défaut doit être : ```env id="default-profile" KX_NETWORK_PROFILE=intranet_private KX_EXPOSURE_MODE=private KX_PUBLIC_MODE_ENABLED=false ``` Le mode public ne doit jamais être activé par défaut. --- # 10. Principes de sécurité produit ## 10.1 Private-by-default Konnaxion doit être privé par défaut. ```text id="private-default" Aucun service interne exposé. Aucun port dangereux ouvert. Aucun mode public sans action explicite. Aucun secret transporté dans la capsule. ``` ## 10.2 Deny-by-default Le manager doit refuser les configurations dangereuses. Ports toujours interdits publiquement : ```text id="blocked-ports" 3000 Next.js direct 5000 Django/Gunicorn interne 5432 PostgreSQL 6379 Redis 5555 Flower/dashboard 8000 Django dev/server direct Docker daemon TCP ``` Les documents de récupération demandent explicitement de ne pas exposer `3000`, `5555`, `5432`, `6379`, `8000` ni Docker daemon, et de limiter l’exposition publique à `80/443` via Traefik. ## 10.3 Security Gate bloquant Avant chaque démarrage, Konnaxion Capsule Manager doit valider : ```text id="security-gate" capsule_signature image_checksums manifest_schema secrets_present secrets_not_default firewall_enabled dangerous_ports_blocked postgres_not_public redis_not_public docker_socket_not_mounted no_privileged_containers no_host_network allowed_images_only admin_surface_private backup_configured ``` Un échec critique doit produire : ```text id="security-blocked" INSTANCE_STATE=security_blocked ``` et empêcher le démarrage. --- # 11. Architecture applicative visée Konnaxion v14 doit rester aligné sur sa stack existante : ```text id="canonical-stack" Frontend: Next.js / React / TypeScript Backend: Django + Django REST Framework Database: PostgreSQL Background jobs: Celery Broker/result backend: Redis Reverse proxy: Traefik Media/static service: Nginx Runtime cible: Docker Compose ``` La documentation actuelle confirme aussi l’existence de scripts, fichiers Docker Compose, settings Django, routes, modules backend et frontend, ainsi qu’une structure complète de projet Konnaxion. --- # 12. Domaines fonctionnels couverts Konnaxion doit conserver son identité modulaire. ## 12.1 Kollective Intelligence ```text id="domain-kollective" expertise réputation scores pondérés confiance vote intelligent historique d’évolution ``` ## 12.2 ethiKos ```text id="domain-ethikos" débats structurés positions arguments consultations civiques suivi d’impact ``` ## 12.3 KeenKonnect ```text id="domain-keenkonnect" projets collaboratifs ressources tâches messages équipes évaluations ``` ## 12.4 KonnectED ```text id="domain-konnected" ressources éducatives certifications évaluations portfolios progression forums co-création ``` ## 12.5 Kreative ```text id="domain-kreative" œuvres galeries archives traditions préservation culturelle expositions ``` Ces domaines sont présents dans les références fonctionnelles et schémas de données v14. --- # 13. Cas d’usage prioritaires ## 13.1 Démo locale ```text id="use-case-local-demo" Un utilisateur démarre Konnaxion sur une machine dédiée. L’application est accessible seulement sur la machine locale. Aucun service réseau n’est exposé. ``` ## 13.2 Intranet d’organisation ```text id="use-case-intranet" Une organisation branche une Konnaxion Box sur son réseau local. Les utilisateurs accèdent à Konnaxion via https://konnaxion.local. L’instance n’est pas accessible depuis Internet. ``` ## 13.3 Démo privée à distance ```text id="use-case-private-tunnel" Le responsable active un tunnel privé. Seules les personnes autorisées peuvent accéder à l’instance. Aucun port routeur n’est ouvert. ``` ## 13.4 Démo publique temporaire ```text id="use-case-public-temp" Le responsable crée un lien public temporaire. Le lien expire automatiquement. Le système revient ensuite en mode privé. ``` ## 13.5 VPS public contrôlé ```text id="use-case-public-vps" Une instance publique est déployée sur un VPS propre. Seuls 80/443 sont publics. SSH est limité. Les secrets sont générés ou rotés. ``` --- # 14. Hors scope Le produit cible ne doit pas viser immédiatement : ```text id="out-of-scope" Kubernetes multi-node orchestration haute disponibilité complète marketplace de plugins tiers SaaS multi-tenant public auto-hébergement non sécurisé configuration réseau libre sans garde-fous exposition publique permanente depuis un réseau résidentiel par défaut ``` Kubernetes et autres couches lourdes ne sont pas nécessaires pour le besoin actuel : Konnaxion dispose déjà d’une architecture Docker, Redis, Celery, Traefik et PostgreSQL suffisante pour le modèle capsule/appliance. --- # 15. MVP produit Le MVP doit livrer : ```text id="mvp-list" 1. Format .kxcap minimal 2. Manifest signé 3. Import capsule 4. Démarrage Docker Compose 5. Profils réseau local_only, intranet_private, public_temporary 6. Génération automatique des secrets 7. Security Gate bloquant 8. Interface de statut 9. Backup manuel 10. Logs visibles 11. Arrêt propre 12. Documentation opérateur ``` Ne pas inclure dans le MVP : ```text id="not-mvp" éditeur visuel complet marketplace cluster haute disponibilité gestion multi-organisation avancée synchronisation cloud mises à jour automatiques complexes ``` --- # 16. Critères de succès ## 16.1 Critères plug-and-play ```text id="success-plug-play" Une personne non DevOps peut démarrer une instance en moins de 10 minutes. Aucun fichier .env n’est modifié manuellement. Aucun port interne n’est choisi manuellement. Aucune commande Docker n’est nécessaire pour l’opérateur. ``` ## 16.2 Critères sécurité ```text id="success-security" Le mode par défaut est privé. PostgreSQL n’est jamais public. Redis n’est jamais public. Docker socket n’est jamais monté dans un conteneur. Les capsules non signées sont refusées. Les ports dangereux bloquent le démarrage. Les secrets sont générés localement. ``` ## 16.3 Critères opérationnels ```text id="success-ops" L’instance peut être démarrée, arrêtée, sauvegardée et restaurée. Les logs sont consultables. Les healthchecks sont visibles. Le système peut revenir à l’état privé après un mode public temporaire. ``` ## 16.4 Critères développeur ```text id="success-dev" Une capsule peut être buildée depuis le code source. Les images sont exportées. Le manifest est généré. La capsule est signée. La capsule est vérifiable avant import. ``` --- # 17. Décisions produit fixées ```text id="product-decisions" DECISION-01: Konnaxion devient une plateforme capsule/appliance, pas seulement une app VPS. DECISION-02: Le mode par défaut est privé. DECISION-03: La configuration manuelle doit être minimale. DECISION-04: La sécurité est intégrée au produit, pas seulement à la documentation. DECISION-05: La capsule ne contient jamais les secrets réels. DECISION-06: Konnaxion Capsule Manager ne doit pas exposer les services internes. DECISION-07: Konnaxion Agent exécute seulement des actions allowlistées. DECISION-08: Docker Compose est le runtime cible initial. DECISION-09: Traefik est le seul point d’entrée réseau. DECISION-10: Les modes publics doivent être explicites, limités et contrôlés. ``` --- # 18. Relation avec les documents existants Les documents existants restent utiles, mais ils sont reclassés. ## 18.1 Documentation technique v14 Rôle : ```text id="doc-role-v14" source de vérité sur les modules, modèles, routes, architecture applicative et domaines fonctionnels ``` Référence : documentation technique v14 et inventaire de code. ## 18.2 Runbooks de déploiement VPS Rôle : ```text id="doc-role-vps" historique opérationnel et source des leçons de sécurité ``` Ils ne représentent plus la cible finale du produit. Le déploiement Namecheap actuel/historique était hybride : backend Docker Compose, frontend Node/pnpm, Postgres Docker, Redis Docker et Traefik Docker. ## 18.3 Runbook frontend Rôle : ```text id="doc-role-frontend" référence pour le build Next.js et les contraintes mémoire ``` Le frontend nécessite notamment `NODE_OPTIONS="--max-old-space-size=4096"` dans le flux de build validé. ## 18.4 Workflow backend Rôle : ```text id="doc-role-backend" référence pour rebuild, migrations Django, services Docker et superuser ``` Le workflow backend documente les étapes Docker Compose, `makemigrations`, `migrate`, `ps` et `createsuperuser`. --- # 19. Résumé exécutif ```text id="executive-summary" Konnaxion doit évoluer vers une appliance portable et sécurisée. Le produit cible est une Konnaxion Capsule ouverte par Konnaxion Capsule Manager, exécutée par Konnaxion Agent, sur une Konnaxion Box ou un host compatible, avec runtime Docker Compose, Traefik comme seul point d’entrée, et des profils réseau prédéfinis. La priorité produit est plug-and-play + private-by-default. ``` --- # 20. Prochaine documentation Le prochain fichier recommandé est : ```text id="next-doc" DOC-02_Konnaxion_Capsule_Architecture.md ``` Objectif du DOC-02 : ```text id="doc02-objective" Décrire précisément les composants de la Konnaxion Capsule, la séparation capsule/instance, le cycle build/import/start/update/rollback, et les responsabilités du Manager, de l’Agent et du runtime Docker. ``` ================================================================================================ FILE: docs/DOC-02_Konnaxion_Capsule_Architecture.md AUTHORITY: reference CONTENT_ROLE: knowledge CONTENT_SHA256: ec7f2f524c76cb47e45d2313a62065c0709037df564423dec8a7b6ef924c8040 CONTENT_BYTES: 20838 ================================================================================================ # DOC-02 — Konnaxion Capsule Architecture ```yaml doc_id: DOC-02 title: Konnaxion Capsule Architecture project: Konnaxion app_version: v14 param_version: kx-param-2026.04.30 status: draft depends_on: - DOC-00_Konnaxion_Canonical_Variables.md related_docs: - DOC-03_Konnaxion_Capsule_Format.md - DOC-04_Konnaxion_Manager_Architecture.md - DOC-05_Konnaxion_Agent_Security_Model.md - DOC-06_Konnaxion_Network_Profiles.md - DOC-07_Konnaxion_Security_Gate.md - DOC-08_Konnaxion_Runtime_Docker_Compose.md ``` --- ## 1. Purpose This document defines the target architecture for the **Konnaxion Capsule** system. The goal is to package Konnaxion as a portable, signed, plug-and-play deployment unit that can be imported by the **Konnaxion Capsule Manager** and launched on a dedicated machine, intranet server, demo box, or VPS with minimal configuration. The architecture must support: ```text Local demo Private intranet Private tunnel Temporary public demo Public VPS deployment ``` The architecture must also be **private-by-default**, because the previous VPS incident showed that a compromised deployment environment can include malicious Docker containers, cron persistence, attempted sudo backdoors, `/tmp/sshd`, exposed secrets, and miner activity. --- ## 2. Canonical product model The Konnaxion Capsule architecture is based on the following product components: ```text Konnaxion Capsule Portable signed application bundle. Konnaxion Capsule Manager User-facing application that imports, installs, starts, stops, updates, and monitors capsules. Konnaxion Agent Local privileged service that performs controlled system actions on behalf of the Manager. Konnaxion Instance Installed runtime copy of a capsule with its own data, secrets, logs, media, and backups. Konnaxion Box Dedicated host machine or appliance running the Manager, Agent, Docker runtime, and instances. ``` The system must always separate: ```text Capsule = immutable app package Instance = mutable local runtime state ``` This distinction prevents secrets, database state, media files, and logs from being mixed into the portable capsule. --- ## 3. Existing Konnaxion application stack Konnaxion v14 uses the following stack: ```text Frontend: Next.js / React Backend: Django 5.1 + Django REST Framework Background jobs: Celery Broker/result backend: Redis Database: PostgreSQL Runtime: Docker / Docker Compose Reverse proxy: Traefik Media/static service: Nginx ``` The technical reference identifies Konnaxion as a Django + DRF backend, Next.js/React frontend, PostgreSQL persistence layer, and Redis-backed Celery infrastructure. The existing repository also contains Docker Compose production/local files, Traefik configuration, production Django containers, Celery worker/beat/flower containers, Postgres maintenance scripts, and frontend deployment tooling. --- ## 4. Target architecture overview ```text ┌─────────────────────────────────────────────────────────┐ │ Konnaxion Box │ │ Linux host / appliance / VPS / intranet machine │ └───────────────────────────┬─────────────────────────────┘ │ ┌───────────────────────────▼─────────────────────────────┐ │ Konnaxion Capsule Manager │ │ UI, lifecycle control, logs, backups, profiles │ └───────────────────────────┬─────────────────────────────┘ │ ┌───────────────────────────▼─────────────────────────────┐ │ Konnaxion Agent │ │ Controlled privileged service │ │ Docker, firewall, secrets, profiles, healthchecks │ └───────────────────────────┬─────────────────────────────┘ │ ┌───────────────────────────▼─────────────────────────────┐ │ Docker Compose Runtime │ │ Isolated networks, volumes, services, healthchecks │ └───────────────────────────┬─────────────────────────────┘ │ ┌───────────────────────────▼─────────────────────────────┐ │ Konnaxion Instance │ │ Traefik + Next.js + Django + Postgres + Redis + Celery │ └─────────────────────────────────────────────────────────┘ ``` The **Konnaxion Capsule** is not itself the running system. It is the signed source package used to create or update a **Konnaxion Instance**. --- ## 5. Capsule-to-instance lifecycle ```text .kxcap file ↓ Import ↓ Signature verification ↓ Manifest validation ↓ Image loading ↓ Secret generation ↓ Instance creation ↓ Network profile selection ↓ Docker Compose startup ↓ Migrations ↓ Healthcheck ↓ Ready ``` The lifecycle must be deterministic. The same capsule should produce the same service topology every time, except for generated secrets, generated instance IDs, local hostnames, and runtime data. --- ## 6. Capsule boundary A **Konnaxion Capsule** contains: ```text Application images Docker Compose template Manifest Network profiles Environment templates Migration commands Seed data Healthcheck definitions Checksums Signature ``` A capsule must not contain: ```text Real production secrets Real SSH keys Private keys Provider tokens Production database credentials Unencrypted production database dumps Mutable runtime logs Mutable runtime media Host-specific firewall state ``` Secrets such as `DJANGO_SECRET_KEY`, `POSTGRES_PASSWORD`, `DATABASE_URL`, API keys, private keys, tokens, and deployment credentials must be treated as sensitive and regenerated or rotated after compromise. --- ## 7. Instance boundary A **Konnaxion Instance** contains all mutable runtime state: ```text /opt/konnaxion/instances// ├── env/ ├── postgres/ ├── redis/ ├── media/ ├── logs/ ├── backups/ └── state/ ``` Instance data survives capsule updates. Capsules are replaceable. Instances are persistent. This allows: ```text Rollback to previous capsule Upgrade to new capsule Backup/restore instance data Multiple local demo instances Temporary public demos Intranet deployments ``` --- ## 8. Runtime service topology The canonical runtime topology is: ```text Traefik ├── / → frontend-next ├── /api/ → django-api ├── /admin/ → django-api └── /media/ → media-nginx Internal services ├── postgres ├── redis ├── celeryworker └── celerybeat Private/optional service └── flower ``` Canonical service names: ```text traefik frontend-next django-api postgres redis celeryworker celerybeat flower media-nginx kx-agent ``` The current deployment already uses routing where `/` maps to the Next.js frontend, `/api/` maps to Django, `/admin/` maps to Django admin, and `/media/` maps to media service handling. --- ## 9. Reverse proxy rule All client access must go through **Traefik**. Allowed external paths: ```text / /api/ /admin/ /media/ ``` Direct access to internal services is forbidden. ```text Forbidden direct public access: - Next.js port 3000 - Django/Gunicorn port 5000 or 8000 - PostgreSQL port 5432 - Redis port 6379 - Flower/dashboard port 5555 - Docker daemon TCP socket ``` The incident recovery notes explicitly identify `3000`, `5555`, `5432`, `6379`, `8000`, and Docker daemon ports as ports that must not be exposed publicly. Public traffic should reach only the reverse proxy on `80/443`. --- ## 10. Network profiles The architecture supports these canonical network profiles: ```text local_only intranet_private private_tunnel public_temporary public_vps offline ``` ### 10.1 local_only ```text Purpose: Demo on the same machine only. Exposure: localhost only. Public access: No. ``` ### 10.2 intranet_private ```text Purpose: LAN / school / organization / demo room. Exposure: Private network only. Public access: No. Default profile: Yes. ``` ### 10.3 private_tunnel ```text Purpose: Controlled remote demo for trusted users. Exposure: VPN or private tunnel only. Public access: No. ``` ### 10.4 public_temporary ```text Purpose: Short-lived external demo. Exposure: Temporary tunnel. Requirements: Expiration required. Authentication recommended. Automatic shutdown required. ``` ### 10.5 public_vps ```text Purpose: Real public deployment. Exposure: 80/443 through cloud firewall and local firewall. Requirements: Hardened SSH. Cloud firewall. UFW or equivalent. Backups/snapshots. ``` ### 10.6 offline ```text Purpose: No external network. Exposure: None. ``` The default must be: ```env KX_NETWORK_PROFILE=intranet_private KX_EXPOSURE_MODE=private KX_PUBLIC_MODE_ENABLED=false ``` --- ## 11. Security architecture Security must be enforced by architecture, not by user discipline. The system must be: ```text private-by-default deny-by-default signed-capsule-only least-privilege profile-driven rollback-capable secrets-generated-on-install ``` The **Konnaxion Capsule Manager** must never allow a user to accidentally expose internal services. The **Konnaxion Agent** must reject dangerous runtime configurations, including: ```text unknown images unsigned capsules privileged containers host network mode Docker socket mounts public PostgreSQL public Redis public dashboard ports public Next.js direct access public Django direct access ``` --- ## 12. Konnaxion Agent responsibility boundary The **Konnaxion Agent** is the only component allowed to perform privileged actions. It may: ```text verify capsule signatures load approved OCI images create Docker networks create Docker volumes generate secrets write instance env files apply approved network profiles start/stop approved Compose stacks run migrations run healthchecks create backups restore backups collect logs ``` It must not: ```text run arbitrary shell commands from the UI start arbitrary containers pull arbitrary images without approval mount arbitrary host paths mount /var/run/docker.sock into app containers enable privileged containers open arbitrary ports disable security checks ``` This is required because the previous incident involved malicious Docker containers and Docker-based persistence. --- ## 13. Manager responsibility boundary The **Konnaxion Capsule Manager** is the user-facing control layer. It provides: ```text Import capsule Start instance Stop instance Update instance Rollback instance Choose network profile Show URLs Show logs Show health Show security state Create backup Restore backup Create temporary public access Expire temporary public access ``` The Manager does not directly control Docker, firewall rules, or system services. It sends limited requests to the Agent. --- ## 14. Security Gate Before an instance can start, the Agent must run a blocking **Security Gate**. Required checks: ```text capsule_signature image_checksums manifest_schema secrets_present secrets_not_default firewall_enabled dangerous_ports_blocked postgres_not_public redis_not_public docker_socket_not_mounted no_privileged_containers no_host_network allowed_images_only admin_surface_private backup_configured ``` Allowed statuses: ```text PASS WARN FAIL_BLOCKING SKIPPED UNKNOWN ``` If any critical check returns `FAIL_BLOCKING`, the instance must not start. --- ## 15. Build architecture The developer-side build system is separate from the runtime Manager. ```text Konnaxion Capsule Builder ├── validate source tree ├── build frontend ├── build backend image ├── build supporting images ├── run tests ├── generate manifest ├── export OCI images ├── calculate checksums ├── sign capsule └── produce .kxcap ``` Canonical build command: ```bash kx capsule build \ --profile demo \ --version 2026.04.30-demo.1 \ --output konnaxion-v14-demo-2026.04.30.kxcap ``` The existing frontend runbook requires `NODE_OPTIONS="--max-old-space-size=4096"` before production Next.js builds to avoid heap out-of-memory failures on limited-memory servers. --- ## 16. Backend migration architecture The capsule runtime must support Django migrations as a controlled lifecycle step. Canonical migration step: ```text Start database Start Redis Start backend image in migration mode Run python manage.py migrate Start full stack Run healthchecks ``` The existing backend workflow uses Docker Compose to rebuild services, run `makemigrations`, apply `migrate`, verify container status, and optionally create a superuser. In production capsules, `makemigrations` should not run automatically. The capsule should already include migration files. Runtime should only run: ```bash python manage.py migrate ``` --- ## 17. Update and rollback architecture Capsules are immutable releases. ```text Instance demo-001 current_capsule -> konnaxion-v14-demo-2026.04.30.kxcap previous_capsule -> konnaxion-v14-demo-2026.04.20.kxcap ``` Update flow: ```text 1. Verify new capsule 2. Backup current instance 3. Stop application services 4. Keep database available if needed 5. Apply new images/config 6. Run migrations 7. Run healthcheck 8. Switch current capsule pointer 9. Start full stack 10. Mark update complete ``` Rollback flow: ```text 1. Stop failed instance 2. Restore previous capsule 3. Restore previous env/config if needed 4. Restore DB backup if migration is not backward-compatible 5. Start previous stack 6. Run healthcheck ``` --- ## 18. Storage architecture The host storage layout must follow: ```text /opt/konnaxion/ ├── capsules/ ├── instances/ ├── shared/ ├── releases/ ├── manager/ └── backups/ ``` Instance-specific storage: ```text /opt/konnaxion/instances// ├── env/ ├── postgres/ ├── redis/ ├── media/ ├── logs/ ├── backups/ └── state/ ``` Capsule files are read-only after import. Instance files are mutable. Backups must be instance-scoped. --- ## 19. Observability architecture The Manager must expose simple status information: ```text Instance state Network profile Public exposure status Service health Security Gate result Last backup Current capsule version Current app version Public URL if enabled Private URL if enabled ``` Canonical instance states: ```text created importing verifying ready starting running stopping stopped updating rolling_back degraded failed security_blocked ``` --- ## 20. User experience architecture The user-facing flow must remain minimal. Target first-run flow: ```text 1. Open Konnaxion Capsule Manager 2. Import .kxcap file 3. Choose mode: - Local only - Intranet private - Private tunnel - Public temporary 4. Create admin account or auto-generate one 5. Click Start 6. Open provided URL ``` The user must not manually configure: ```text Docker Compose Traefik Nginx PostgreSQL Redis Celery Django settings Next.js env files ports firewall secrets certificates systemd migrations ``` --- ## 21. Architecture decisions ### ADR-02-001 — Use Docker Compose, not Kubernetes Decision: ```text Use Docker Compose as the capsule runtime. ``` Reason: ```text Konnaxion already uses Docker Compose patterns. The target is plug-and-play local/intranet deployment. Kubernetes would add unnecessary operational complexity. ``` ### ADR-02-002 — Use Traefik as the single entrypoint Decision: ```text All HTTP/HTTPS traffic enters through Traefik. ``` Reason: ```text Traefik already exists in the current production deployment. It allows route-based separation for frontend, API, admin, and media. It prevents direct exposure of app internals. ``` ### ADR-02-003 — Keep capsules immutable Decision: ```text Capsules are immutable after build. ``` Reason: ```text Updates and rollback require predictable artifacts. Runtime state belongs to instances, not capsules. ``` ### ADR-02-004 — Generate secrets on install Decision: ```text Capsules contain templates only. Secrets are generated by the Agent during instance creation. ``` Reason: ```text Portable artifacts must not carry real secrets. Prior incident recovery requires secret rotation and no trust in old server state. ``` ### ADR-02-005 — Make public exposure explicit and temporary by default Decision: ```text Public temporary mode requires expiration. Permanent public mode requires public_vps profile. ``` Reason: ```text Konnaxion is intended to support private demos and intranet deployment. Public exposure should never happen accidentally. ``` --- ## 22. Non-goals This architecture does not aim to provide: ```text Multi-node orchestration Kubernetes cluster management Generic hosting for arbitrary apps Arbitrary Docker control panel Public cloud PaaS clone Automatic migration of compromised servers Secret recovery from old servers ``` The system is specifically for packaging, installing, running, updating, and securing Konnaxion instances. --- ## 23. Final target architecture ```text Konnaxion Capsule Builder ↓ produces signed .kxcap Konnaxion Capsule ↓ imported by Konnaxion Capsule Manager ↓ controlled through Konnaxion Agent ↓ manages Docker Compose Runtime ↓ runs Konnaxion Instance ├── Traefik ├── frontend-next ├── django-api ├── postgres ├── redis ├── celeryworker ├── celerybeat └── media-nginx ``` Default posture: ```text Network: intranet_private Exposure: private Public mode: disabled Firewall: deny-by-default Secrets: generated on install Capsules: signed only Internal ports: never public Rollback: supported Backups: enabled ``` --- ## 24. Summary The Konnaxion Capsule Architecture turns Konnaxion into a portable, signed, reproducible deployment unit. The architecture is designed around five rules: ```text 1. Plug-and-play for the user. 2. Private-by-default for safety. 3. Signed and verified capsules only. 4. Strong separation between capsule and instance. 5. Traefik-only public entrypoint with internal services isolated. ``` This gives Konnaxion a path toward local demos, intranet installations, temporary public demos, and VPS deployments without requiring the operator to manually configure Docker, firewall rules, secrets, reverse proxy routing, database services, Redis, Celery, or frontend build behavior. --- ## 25. Installed artifacts and optional composition The capsule architecture also defines an installed-artifact discovery boundary. The canonical contract is `DOC-23_Capsule_Installed_Artifact_and_Composition_Contract.md`. ```text Capsule / Agent owns installation, removal, version, dependency resolution, public entrypoints, installed registry, public-manifest discovery, and readiness projection Product owns business behavior and product UX kOA Spaces (composition_host) may compose admitted public product contributions koali-ui (library) provides shared public UI primitives/contracts; it is not a switchable product ``` A composition host is optional. The absence or removal of Spaces must not make a standalone product unhealthy. Likewise, rejecting an integrated UI contribution must not make a runtime/standalone-capable product broken. The installed registry is generation-based and must replace compile-time product lists in composition hosts. Capsule exposes discovery; it does not interpret the product's routes, navigation, surfaces, commands, inspectors, or presentation state. ================================================================================================ FILE: docs/DOC-03_Konnaxion_Capsule_Format.md AUTHORITY: reference CONTENT_ROLE: knowledge CONTENT_SHA256: f5b2634c1d3517296515524e7f7ff3a0b4e994e00bf9dccef31891ec319ab297 CONTENT_BYTES: 35302 ================================================================================================ --- doc_id: DOC-03 filename: DOC-03_Konnaxion_Capsule_Format.md project: Konnaxion app_version: v14 param_version: kx-param-2026.04.30 status: draft owner: Konnaxion Architecture created_at: 2026-04-30 updated_at: 2026-05-03 depends_on: - DOC-00_Konnaxion_Canonical_Variables.md - DOC-02_Konnaxion_Capsule_Architecture.md related_docs: - DOC-04_Konnaxion_Manager_Architecture.md - DOC-05_Konnaxion_Agent_Security_Model.md - DOC-06_Konnaxion_Network_Profiles.md - DOC-07_Konnaxion_Security_Gate.md - DOC-08_Konnaxion_Runtime_Docker_Compose.md - DOC-10_Konnaxion_Builder_CLI.md --- # DOC-03 — Konnaxion Capsule Format ## 1. Purpose This document defines the canonical file format for a **Konnaxion Capsule**. A Konnaxion Capsule is the portable, signed, immutable package used by **Konnaxion Capsule Manager** to create or update a **Konnaxion Instance** on a **Konnaxion Box**, local host, intranet server, or VPS. The capsule must support plug-and-play deployment while preserving the security model defined in DOC-00 and enforced by the **Konnaxion Agent**. ## 2. Canonical definition ```text Konnaxion Capsule = one portable .kxcap file = application runtime contract + container images + manifest + profiles + templates + checksums + signature = no real secrets = no real production database = no host-specific runtime state ``` The canonical extension is: ```text .kxcap ``` The canonical package name pattern is: ```text konnaxion-v14--.kxcap ``` Examples: ```text konnaxion-v14-demo-2026.04.30.kxcap konnaxion-v14-intranet-2026.04.30.kxcap konnaxion-v14-release-2026.04.30.kxcap ``` ## 3. Design rules The capsule format follows these rules: ```text 1. Immutable after build. 2. Signed before distribution. 3. Verified before import. 4. Deterministic where possible. 5. Private-by-default. 6. Deny-by-default networking. 7. No real secrets inside the capsule. 8. No production database dump inside the capsule unless encrypted and explicitly marked. 9. No direct public exposure of internal services. 10. No privileged containers unless explicitly approved by a future security review. 11. No runtime dependency on public package registries. 12. No runtime dependency on Docker image pulls. 13. No healthcheck dependency on tools absent from the selected image. 14. No public_vps runtime may silently fall back to 127.0.0.1 as its public host. ``` The capsule is not the installed instance. ```text Capsule = application artifact Instance = running environment, generated secrets, data, logs, media, backups ``` ## 4. High-level lifecycle ```text Developer machine / CI ↓ kx capsule build ↓ .kxcap generated ↓ kx capsule verify ↓ Capsule signed and distributed ↓ Konnaxion Capsule Manager imports capsule ↓ Konnaxion Agent validates Security Gate ↓ Instance is created or updated ``` ## 5. Archive container ### 5.1 Physical format The MVP format is: ```text tar archive + zstd compression ``` Canonical extension remains: ```text .kxcap ``` Implementation detail: ```text .kxcap = tar.zst with a Konnaxion manifest and signature layout ``` The extension must not be changed to `.tar.zst` for user-facing distribution. ### 5.2 Future-compatible alternatives Future versions may support: ```text OCI artifact SquashFS image encrypted capsule container multi-architecture capsule index ``` These are not part of the MVP unless specified in a later document. ## 6. Required root layout Every `.kxcap` file must contain this root structure: ```text .kxcap ├── manifest.yaml ├── docker-compose.capsule.yml ├── images/ ├── profiles/ ├── env-templates/ ├── migrations/ ├── seed-data/ ├── healthchecks/ ├── policies/ ├── metadata/ ├── checksums.txt └── signature.sig ``` The root entries are mandatory unless explicitly marked optional in this document. A capsule whose `images/` directory contains only placeholder files such as `README.json` is invalid for deployable runtime profiles. ## 7. Root file responsibilities | Path | Required | Purpose | |---|---:|---| | `manifest.yaml` | yes | Canonical machine-readable description of the capsule | | `docker-compose.capsule.yml` | yes | Runtime service definition consumed by Konnaxion Agent | | `images/` | yes | Offline-loadable OCI image archives | | `profiles/` | yes | Network exposure profiles | | `env-templates/` | yes | Secret-free environment templates | | `migrations/` | yes | Database and application migration runners | | `seed-data/` | optional | Demo or bootstrap data | | `healthchecks/` | yes | Startup and readiness probes | | `policies/` | yes | Security and runtime policy definitions | | `metadata/` | yes | Build metadata, SBOM, changelog, compatibility info | | `checksums.txt` | yes | Digest list for capsule contents | | `signature.sig` | yes | Signature over the manifest and checksums | ## 8. `manifest.yaml` `manifest.yaml` is the primary contract of the capsule. It must be valid YAML and must pass the manifest schema version declared in the file. ### 8.1 Required fields ```yaml schema_version: kxcap/v1 capsule_id: konnaxion-v14-demo-2026.04.30 capsule_version: 2026.04.30-demo.1 app_name: Konnaxion app_version: v14 channel: demo created_at: 2026-04-30T00:00:00Z builder_version: kx-builder-0.1.0 minimum_manager_version: kx-manager-0.1.0 minimum_agent_version: kx-agent-0.1.0 architecture: - linux/amd64 runtime: docker-compose required_ram_mb: 4096 recommended_ram_mb: 8192 default_network_profile: intranet_private default_exposure_mode: private ``` ### 8.2 Service declarations The manifest must declare every service the capsule expects to run. Canonical service names: ```yaml services: traefik: role: reverse_proxy image: traefik:v3.1 image_archive: images/traefik_v3.1_linux-amd64.oci.tar public_entrypoint: true internal: false frontend-next: role: frontend image: konnaxion/frontend-next:v14 image_archive: images/konnaxion-frontend-next_v14_linux-amd64.oci.tar internal_port: 3000 internal: true django-api: role: backend_api image: konnaxion/django-api:v14 image_archive: images/konnaxion-django-api_v14_linux-amd64.oci.tar internal_port: 5000 internal: true postgres: role: database image: postgres:16 image_archive: images/postgres_16_linux-amd64.oci.tar internal_port: 5432 internal: true persistent: true redis: role: broker image: redis:7 image_archive: images/redis_7_linux-amd64.oci.tar internal_port: 6379 internal: true persistent: true celeryworker: role: background_worker image: konnaxion/django-api:v14 image_archive: images/konnaxion-django-api_v14_linux-amd64.oci.tar internal: true celerybeat: role: scheduler image: konnaxion/django-api:v14 image_archive: images/konnaxion-django-api_v14_linux-amd64.oci.tar internal: true media-nginx: role: media_server image: nginx:stable image_archive: images/nginx_stable_linux-amd64.oci.tar internal_port: 80 internal: true ``` `flower` is optional and must be private-only if included. ```yaml flower: role: celery_monitoring image: konnaxion/django-api:v14 image_archive: images/konnaxion-django-api_v14_linux-amd64.oci.tar internal_port: 5555 internal: true enabled_by_default: false ``` ### 8.3 Route declarations The manifest must declare canonical routes: ```yaml routes: - path: / service: frontend-next upstream_port: 3000 - path: /api/ service: django-api upstream_port: 5000 - path: /admin/ service: django-api upstream_port: 5000 - path: /media/ service: media-nginx upstream_port: 80 ``` No capsule may route public traffic directly to `postgres`, `redis`, `celeryworker`, `celerybeat`, or `flower`. A route is considered infrastructure-reachable when Traefik forwards to the expected upstream. Application-level `4xx` responses from Django for `/api/`, `/admin/`, or `/media/` are not automatically infrastructure failures. Traefik’s own unmatched-router `404` is a failure. ### 8.4 Network profile declarations The manifest must list allowed profile files: ```yaml network_profiles: - id: local_only file: profiles/local_only.yaml default: false - id: intranet_private file: profiles/intranet_private.yaml default: true - id: private_tunnel file: profiles/private_tunnel.yaml default: false - id: public_temporary file: profiles/public_temporary.yaml default: false - id: public_vps file: profiles/public_vps.yaml default: false ``` Only one profile may have `default: true`. ### 8.5 Security declarations The manifest must include: ```yaml security: require_signed_capsule: true generate_secrets_on_install: true allow_unknown_images: false allow_privileged_containers: false allow_host_network: false allow_docker_socket_mount: false allow_public_database: false allow_public_redis: false allow_public_admin_dashboard: false default_exposure_mode: private ``` ### 8.6 Data declarations ```yaml data: postgres: persistent: true backup_required: true restore_supported: true redis: persistent: true backup_required: false restore_supported: false media: persistent: true backup_required: true restore_supported: true logs: persistent: true backup_required: false retention_days_default: 14 ``` ## 9. `docker-compose.capsule.yml` This file defines the runtime stack used by Konnaxion Agent. It must not be executed directly by end users unless in developer/debug mode. The Agent is responsible for injecting: ```text KX_INSTANCE_ID KX_NETWORK_PROFILE KX_EXPOSURE_MODE KX_HOST runtime env files volume paths profile-specific network bindings Traefik dynamic file-provider config ``` ### 9.1 Compose rules The compose file must obey: ```text 1. No `privileged: true`. 2. No `network_mode: host`. 3. No Docker socket mount. 4. No bind mount to `/`, `/etc`, `/root`, `/var/run`, `/tmp`, or `/dev/shm`. 5. No direct public port mapping for internal services. 6. Traefik is the only public entrypoint. 7. Postgres and Redis are internal only. 8. Flower is disabled by default or private only. 9. public_vps must use the configured public host, never 127.0.0.1. 10. Runtime healthchecks must use commands available inside the selected image. ``` ### 9.2 Canonical internal networks ```yaml networks: kx_edge: internal: false kx_internal: internal: true ``` Expected network placement: | Service | `kx_edge` | `kx_internal` | |---|---:|---:| | `traefik` | yes | yes | | `frontend-next` | no | yes | | `django-api` | no | yes | | `media-nginx` | no | yes | | `postgres` | no | yes | | `redis` | no | yes | | `celeryworker` | no | yes | | `celerybeat` | no | yes | | `flower` | no | yes | ### 9.3 Traefik file-provider runtime config The canonical generated runtime must use Traefik file-provider config for instance routes. Canonical generated file: ```text /opt/konnaxion/instances//state/traefik-dynamic.yml ``` Example for public VPS: ```yaml http: routers: kx-frontend: rule: "Host(`{{KX_HOST}}`) && PathPrefix(`/`)" entryPoints: - websecure tls: {} service: kx-frontend priority: 1 kx-api: rule: "Host(`{{KX_HOST}}`) && PathPrefix(`/api/`)" entryPoints: - websecure tls: {} service: kx-api priority: 100 kx-admin: rule: "Host(`{{KX_HOST}}`) && PathPrefix(`/admin/`)" entryPoints: - websecure tls: {} service: kx-api priority: 100 kx-media: rule: "Host(`{{KX_HOST}}`) && PathPrefix(`/media/`)" entryPoints: - websecure tls: {} service: kx-media priority: 100 services: kx-frontend: loadBalancer: servers: - url: "http://kx-{{INSTANCE_ID}}-frontend-next:3000" kx-api: loadBalancer: servers: - url: "http://kx-{{INSTANCE_ID}}-django-api:5000" kx-media: loadBalancer: servers: - url: "http://kx-{{INSTANCE_ID}}-media-nginx:80" ``` Docker labels may be emitted as metadata, but file-provider config is canonical for generated instance routing. Docker labels alone are not sufficient. ## 10. `images/` The `images/` directory contains OCI-compatible image archives. Canonical layout: ```text images/ ├── konnaxion-frontend-next_v14_linux-amd64.oci.tar ├── konnaxion-django-api_v14_linux-amd64.oci.tar ├── traefik_v3.1_linux-amd64.oci.tar ├── nginx_stable_linux-amd64.oci.tar ├── postgres_16_linux-amd64.oci.tar └── redis_7_linux-amd64.oci.tar ``` The Agent imports these images using an allowlist derived from `manifest.yaml`. No image may be loaded if: ```text 1. It is not declared in manifest.yaml. 2. Its archive is missing from images/. 3. Its digest does not match checksums.txt. 4. Its signature or provenance policy fails. 5. Its name collides with an existing unknown local image unless explicitly approved. ``` A capsule is invalid if: ```text images/ contains only README.json images/ is empty manifest.yaml declares an image_archive that does not exist checksums.txt omits an image_archive a required runtime service has neither a declared image_archive nor an approved external-pull policy ``` ### 10.1 Frontend image requirements The `frontend-next` runtime image must be self-contained. It must include: ```text package.json node_modules/ .next/ public/ next.config.* env.mjs ``` It must not require runtime network access to install dependencies. The canonical runtime command is: ```text node node_modules/next/dist/bin/next start -H 0.0.0.0 -p 3000 ``` The frontend image must not use runtime `pnpm start` if that requires Corepack to download `pnpm`. ### 10.2 Django image requirements The `django-api` runtime image must contain the actual application source tree used for the build. The Builder must prevent polluted or incorrect Docker build contexts. A built `django-api` image is invalid if application files are overwritten by migration files, virtualenv files, cache files, or generated artifacts. The runtime must start the backend on: ```text 0.0.0.0:5000 ``` ### 10.3 Support image requirements Support images may be based on upstream images, but the capsule must still include their offline-loadable archives unless the selected profile explicitly allows controlled image pulls. Canonical support images for MVP: ```text traefik:v3.1 nginx:stable postgres:16 redis:7 ``` ## 11. `profiles/` Network profile files define how the instance may be exposed. Canonical profiles: ```text profiles/local_only.yaml profiles/intranet_private.yaml profiles/private_tunnel.yaml profiles/public_temporary.yaml profiles/public_vps.yaml ``` ### 11.1 `local_only.yaml` ```yaml profile_id: local_only exposure_mode: private bind: - interface: loopback ports: - 443 allow_lan: false allow_wan: false requires_expiration: false ``` ### 11.2 `intranet_private.yaml` ```yaml profile_id: intranet_private exposure_mode: lan bind: - interface: lan ports: - 443 allow_lan: true allow_wan: false requires_expiration: false ``` ### 11.3 `private_tunnel.yaml` ```yaml profile_id: private_tunnel exposure_mode: vpn provider_options: - tailscale allow_lan: false allow_wan: false requires_expiration: false ``` ### 11.4 `public_temporary.yaml` ```yaml profile_id: public_temporary exposure_mode: temporary_tunnel provider_options: - cloudflare_tunnel - tailscale_funnel allow_lan: false allow_wan: true requires_expiration: true max_duration_hours: 8 require_auth: true ``` ### 11.5 `public_vps.yaml` ```yaml profile_id: public_vps exposure_mode: public bind: - interface: public ports: - 80 - 443 allow_lan: true allow_wan: true requires_expiration: false requires_security_review: true requires_public_host: true ``` For `public_vps`, the Manager must provide a canonical public host. The Agent must reject or fail configuration if the host is empty. Valid examples: ```text demo.example.com 138.197.174.76.sslip.io ``` Invalid generated public VPS host values: ```text 127.0.0.1 localhost 0.0.0.0 ``` ## 12. `env-templates/` Environment templates define required runtime variables without storing real secrets. Canonical files: ```text env-templates/django.env.template env-templates/postgres.env.template env-templates/redis.env.template env-templates/frontend.env.template env-templates/kx.env.template ``` ### 12.1 Django template ```env DJANGO_SETTINGS_MODULE=config.settings.production DJANGO_SECRET_KEY={{GENERATED_ON_INSTALL}} DJANGO_DEBUG=False DJANGO_ALLOWED_HOSTS={{GENERATED_ALLOWED_HOSTS}} DJANGO_CSRF_TRUSTED_ORIGINS={{GENERATED_CSRF_TRUSTED_ORIGINS}} DJANGO_ADMIN_URL=admin/ USE_DOCKER=yes DATABASE_URL=postgres://konnaxion:{{POSTGRES_PASSWORD}}@postgres:5432/konnaxion REDIS_URL=redis://redis:6379/0 CELERY_BROKER_URL=redis://redis:6379/0 SENTRY_DSN={{OPTIONAL_SENTRY_DSN}} ``` For `public_vps`, generated `DJANGO_ALLOWED_HOSTS` must include: ```text 127.0.0.1 localhost {{KX_HOST}} django-api kx-{{INSTANCE_ID}}-django-api ``` For `public_vps`, generated `DJANGO_CSRF_TRUSTED_ORIGINS` must include: ```text https://{{KX_HOST}} http://{{KX_HOST}} ``` ### 12.2 Postgres template ```env POSTGRES_HOST=postgres POSTGRES_PORT=5432 POSTGRES_DB=konnaxion POSTGRES_USER=konnaxion POSTGRES_PASSWORD={{GENERATED_ON_INSTALL}} ``` ### 12.3 Redis template ```env REDIS_HOST=redis REDIS_PORT=6379 REDIS_URL=redis://redis:6379/0 ``` ### 12.4 Frontend template ```env NEXT_PUBLIC_API_BASE={{KX_BASE_URL}}/api NEXT_PUBLIC_BACKEND_BASE={{KX_BASE_URL}} NEXT_TELEMETRY_DISABLED=1 NODE_OPTIONS=--max-old-space-size=4096 ``` For `public_vps`, `KX_BASE_URL` must resolve to: ```text https://{{KX_HOST}} ``` It must not resolve to `https://127.0.0.1`. ### 12.5 Konnaxion runtime template ```env KX_INSTANCE_ID={{INSTANCE_ID}} KX_CAPSULE_ID={{CAPSULE_ID}} KX_CAPSULE_VERSION={{CAPSULE_VERSION}} KX_APP_VERSION=v14 KX_PARAM_VERSION=kx-param-2026.04.30 KX_NETWORK_PROFILE={{NETWORK_PROFILE}} KX_EXPOSURE_MODE={{EXPOSURE_MODE}} KX_PUBLIC_MODE_ENABLED=false KX_PUBLIC_MODE_EXPIRES_AT= KX_HOST={{GENERATED_FROM_NETWORK_PROFILE}} KX_REQUIRE_SIGNED_CAPSULE=true KX_GENERATE_SECRETS_ON_INSTALL=true KX_ALLOW_UNKNOWN_IMAGES=false KX_ALLOW_PRIVILEGED_CONTAINERS=false KX_ALLOW_DOCKER_SOCKET_MOUNT=false KX_ALLOW_HOST_NETWORK=false KX_BACKUP_ENABLED=true KX_BACKUP_RETENTION_DAYS=14 ``` For `public_vps`, generated values must include: ```env KX_NETWORK_PROFILE=public_vps KX_EXPOSURE_MODE=public KX_PUBLIC_MODE_ENABLED=true KX_HOST={{PUBLIC_HOST}} ``` ## 13. `migrations/` The `migrations/` directory contains controlled runtime migration entrypoints. Canonical layout: ```text migrations/ ├── migrate.sh ├── collectstatic.sh ├── create_initial_admin.sh ├── seed_demo_data.sh └── migration-policy.yaml ``` ### 13.1 Migration policy ```yaml migration_policy: run_database_migrations_on_first_start: true run_database_migrations_on_update: true require_backup_before_update_migration: true allow_destructive_migrations: false allow_manual_override: false ``` ### 13.2 Required migration behavior The Agent must: ```text 1. Create or verify database connectivity. 2. Run Django migrations. 3. Collect static files if required. 4. Load seed data only if the selected channel/profile allows it. 5. Refuse destructive migrations unless explicitly approved by a future migration policy. ``` ## 14. `seed-data/` Seed data is optional. Canonical layout: ```text seed-data/ ├── demo-users.json ├── demo-content.json ├── demo-projects.json └── seed-policy.yaml ``` Seed data must be clearly marked: ```yaml seed_policy: channel: demo contains_personal_data: false safe_for_public_demo: true requires_user_confirmation: false can_run_on_existing_instance: false ``` No production personal data may be included in seed files. ## 15. `healthchecks/` The `healthchecks/` directory declares readiness and runtime checks. Canonical file: ```text healthchecks/checks.yaml ``` Example: ```yaml checks: - id: frontend_ready type: http url: http://frontend-next:3000/ expected_status_any: - 200 - 301 - 302 - 308 required: true - id: django_socket_ready type: tcp host: django-api port: 5000 required: true - id: django_route_reachable type: http url: http://django-api:5000/api/ expected_status_any: - 200 - 400 - 401 - 403 - 404 required: true - id: postgres_ready type: tcp host: postgres port: 5432 required: true - id: redis_ready type: tcp host: redis port: 6379 required: true - id: public_gateway_ready type: http url: '{{KX_BASE_URL}}/' expected_status_any: - 200 - 301 - 302 - 308 required: true ``` ### 15.1 Healthcheck tool rules Healthchecks must not depend on absent tools. Examples of fragile healthchecks: ```text wget inside an image that does not include wget curl inside an image that does not include curl shell pipelines that assume bash in an sh-only image ``` Canonical Django runtime healthcheck: ```text python -c "import socket; sock=socket.create_connection(('127.0.0.1',5000),5); sock.close()" ``` The Django healthcheck validates that Gunicorn/Uvicorn is listening. Public HTTP route validation is a separate Traefik route check. ### 15.2 Route check classification Route checks must distinguish: ```text Traefik unmatched-router 404 = FAIL Frontend / returns 2xx/3xx = PASS Django /api/ returns Django 4xx = PASS for infrastructure reachability Django /admin/ returns Django 4xx = PASS for infrastructure reachability Django 5xx = FAIL Connection refused/timeout = FAIL ``` A Django `404` or `400` with Uvicorn/Django headers proves the route reached Django. It is not equivalent to Traefik’s default `404 page not found`. ## 16. `policies/` The `policies/` directory contains validation policies enforced before import and before start. Canonical files: ```text policies/security-policy.yaml policies/network-policy.yaml policies/runtime-policy.yaml policies/backup-policy.yaml ``` ### 16.1 Security policy ```yaml security_policy: require_signature: true require_checksums: true block_unknown_images: true block_missing_image_archives: true block_privileged_containers: true block_host_network: true block_docker_socket_mount: true block_public_database: true block_public_redis: true block_public_flower: true block_shell_hooks: true ``` ### 16.2 Network policy ```yaml network_policy: allowed_public_ports: - 80 - 443 allowed_lan_ports: - 443 blocked_ports: - 3000 - 5000 - 5432 - 5555 - 6379 - 8000 public_mode_requires_expiration: false public_vps_requires_public_host: true ``` ### 16.3 Runtime policy ```yaml runtime_policy: allowed_runtime: docker-compose allow_kubernetes: false allow_serverless: false allow_custom_shell_commands: false allow_arbitrary_compose_override: false require_offline_runtime_images: true ``` ## 17. `metadata/` Canonical layout: ```text metadata/ ├── build-info.yaml ├── sbom.spdx.json ├── changelog.md ├── compatibility.yaml ├── release-notes.md └── provenance.json ``` ### 17.1 `build-info.yaml` ```yaml build: built_at: 2026-04-30T00:00:00Z built_by: kx-builder source_repo: Konnaxion source_ref: main source_commit: '' dirty_worktree: false ci_run_id: '' ``` ### 17.2 `compatibility.yaml` ```yaml compatibility: minimum_manager_version: kx-manager-0.1.0 minimum_agent_version: kx-agent-0.1.0 supported_platforms: - linux/amd64 minimum_ram_mb: 4096 recommended_ram_mb: 8192 minimum_disk_free_gb: 20 ``` ### 17.3 `provenance.json` `provenance.json` must identify: ```text source commit builder version image tags image digests image archive filenames build platform timestamp signing key identity or key fingerprint ``` ## 18. `checksums.txt` `checksums.txt` must contain a digest for every file except `signature.sig`. Canonical format: ```text sha256 manifest.yaml sha256 docker-compose.capsule.yml sha256 images/konnaxion-frontend-next_v14_linux-amd64.oci.tar sha256 images/konnaxion-django-api_v14_linux-amd64.oci.tar sha256 images/traefik_v3.1_linux-amd64.oci.tar sha256 images/nginx_stable_linux-amd64.oci.tar sha256 images/postgres_16_linux-amd64.oci.tar sha256 images/redis_7_linux-amd64.oci.tar ``` The Agent must refuse import if: ```text 1. checksums.txt is missing. 2. a listed file is missing. 3. an unlisted file exists, unless allowed by schema. 4. any digest mismatch occurs. 5. a required image archive is missing. 6. images/ contains only placeholder files. ``` ## 19. `signature.sig` `signature.sig` signs: ```text manifest.yaml checksums.txt metadata/provenance.json ``` The signature does not replace file checksums. Both are required. Initial signing approach: ```text Ed25519 detached signature ``` Future signing approaches may include: ```text Sigstore/cosign hardware-backed signing key organization-level release signing ``` The Manager must show signature status before import: ```text Capsule signature: valid Signer: Konnaxion Release Key Capsule ID: konnaxion-v14-demo-2026.04.30 Capsule version: 2026.04.30-demo.1 ``` ## 20. Forbidden capsule contents A `.kxcap` file must not contain: ```text real DJANGO_SECRET_KEY real POSTGRES_PASSWORD real DATABASE_URL with password SSH private keys API keys provider tokens Git tokens private certificates raw production database dump old server crontabs old systemd service files from compromised hosts /tmp contents /dev/shm contents unknown Docker volumes local .venv or virtualenv content node_modules from the developer workstation Docker build cache test reports coverage reports ``` If a forbidden item is detected, the Agent must return: ```text FAIL_BLOCKING ``` ## 21. Install-time generated material The following must be generated on install, not packaged inside the capsule: ```text DJANGO_SECRET_KEY POSTGRES_PASSWORD KX_INSTANCE_ID if not provided initial admin password or invite token local TLS material if using local/intranet profile runtime env files instance-specific Traefik dynamic config backup encryption key if enabled ``` ## 22. Instance output after import After import and start, the Manager/Agent creates: ```text /opt/konnaxion/instances// ├── env/ │ ├── django.env │ ├── postgres.env │ ├── redis.env │ ├── frontend.env │ └── kx.env ├── postgres/ ├── redis/ ├── media/ ├── logs/ ├── backups/ ├── state/ │ ├── docker-compose.runtime.yml │ └── traefik-dynamic.yml └── runtime/ ``` The capsule remains stored separately: ```text /opt/konnaxion/capsules/.kxcap ``` Extracted capsule contents remain stored separately: ```text /opt/konnaxion/shared/capsules// ``` ## 23. Validation flow Before import: ```text 1. Verify physical archive format. 2. Read manifest.yaml. 3. Validate manifest schema. 4. Verify checksums.txt. 5. Verify signature.sig. 6. Validate service allowlist. 7. Validate image allowlist. 8. Validate required image archives exist. 9. Validate image archive checksums. 10. Validate profiles. 11. Validate security policies. 12. Confirm compatibility with Manager and Agent versions. ``` Before start: ```text 1. Generate missing secrets. 2. Render env templates. 3. Render network profile. 4. Validate public host for public_vps. 5. Create internal Docker networks. 6. Create persistent volumes. 7. Load allowed images. 8. Apply firewall/profile rules. 9. Render Traefik dynamic config. 10. Run Security Gate. 11. Run migrations. 12. Start services. 13. Run healthchecks. ``` ## 24. Security Gate required checks Every capsule must support the following Security Gate checks: ```text capsule_signature image_checksums image_archives_present manifest_schema secrets_present secrets_not_default firewall_enabled dangerous_ports_blocked postgres_not_public redis_not_public docker_socket_not_mounted no_privileged_containers no_host_network allowed_images_only admin_surface_private backup_configured public_host_valid runtime_routes_valid ``` Status values: ```text PASS WARN FAIL_BLOCKING SKIPPED UNKNOWN ``` Any of these must block startup if they fail: ```text capsule_signature image_checksums image_archives_present manifest_schema dangerous_ports_blocked postgres_not_public redis_not_public docker_socket_not_mounted no_privileged_containers no_host_network allowed_images_only public_host_valid ``` ## 25. Update semantics A capsule update must never modify a running instance blindly. Required update flow: ```text 1. Import new capsule. 2. Verify new capsule. 3. Compare compatibility. 4. Backup current instance database and media. 5. Create update transaction. 6. Stop affected services. 7. Switch images/config. 8. Run migrations. 9. Start services. 10. Run healthchecks. 11. Mark update complete. ``` If healthchecks fail: ```text 1. Stop new services. 2. Restore previous capsule reference. 3. Restore previous runtime configuration. 4. Restart old services. 5. Mark update as failed. 6. Preserve logs for inspection. ``` ## 26. Rollback metadata Each capsule import must record rollback metadata: ```yaml rollback: previous_capsule_id: konnaxion-v14-demo-2026.04.20 previous_capsule_version: 2026.04.20-demo.1 backup_id: backup-demo-001-20260430-170000 migration_state_before: '' migration_state_after: '' ``` Database rollback is only allowed if a compatible backup exists. ## 27. Developer build command Canonical command: ```bash kx capsule build \ --channel demo \ --app-version v14 \ --profile intranet_private \ --output konnaxion-v14-demo-2026.04.30.kxcap ``` Public VPS demo command: ```bash kx capsule build \ --channel demo \ --app-version v14 \ --profile public_vps \ --output konnaxion-v14-demo-2026.04.30.kxcap ``` Expected builder phases: ```text 1. verify clean source tree 2. create clean backend Docker build context 3. create clean frontend Docker build context 4. install dependencies 5. run backend tests 6. run frontend typecheck 7. build frontend 8. build backend image 9. build frontend image 10. build support images 11. export OCI images into images/ 12. generate manifest 13. verify image archives exist 14. generate checksums 15. generate SBOM/provenance 16. sign capsule 17. verify final capsule ``` The Builder must fail if required image archives are missing. It must not produce a deployable-looking capsule containing only `images/README.json`. ## 28. Manager import command Canonical command: ```bash kx capsule import konnaxion-v14-demo-2026.04.30.kxcap ``` Canonical start command: ```bash kx instance start demo-001 --network intranet_private ``` Canonical verification command: ```bash kx security check demo-001 ``` For Droplet/VPS deployment, the Manager must reach the private Droplet Agent through SSH-local HTTP unless a real non-loopback `remote_agent_url` is explicitly configured: ```text Manager on Windows -> ssh root@ -> curl http://127.0.0.1:8765/v1/... -> Droplet Agent ``` The Manager must not require a temporary localhost tunnel for normal Droplet deploy. ## 29. MVP scope The MVP capsule format includes: ```text .kxcap tar.zst archive manifest.yaml Docker Compose runtime OCI image archives network profiles secret-free env templates migrations healthchecks checksums signature Security Gate policies Traefik file-provider runtime config public_vps host propagation ``` The MVP does not include: ```text multi-node clustering Kubernetes runtime automatic cloud provisioning embedded production data third-party app marketplace arbitrary plugin system full remote fleet management ``` ## 30. Acceptance criteria A capsule is valid only if: ```text 1. It imports on a clean Konnaxion Box. 2. It starts in local_only mode with no network exposure. 3. It starts in intranet_private mode with only HTTPS exposed to LAN. 4. It starts in public_vps mode with a configured public host. 5. It refuses public_vps mode if host is missing or loopback-only. 6. It refuses to expose Postgres publicly. 7. It refuses to expose Redis publicly. 8. It refuses to expose Next.js direct port 3000 publicly. 9. It refuses Docker socket mounts. 10. It generates fresh secrets on install. 11. It renders DJANGO_ALLOWED_HOSTS from the selected network profile. 12. It renders NEXT_PUBLIC_API_BASE from the selected network profile. 13. It renders Traefik dynamic routes for the selected host. 14. It runs database migrations successfully. 15. It passes healthchecks. 16. It can be backed up. 17. It can be stopped and restarted. 18. It can be updated with rollback metadata. 19. It contains required OCI image archives. 20. It fails verification when required image archives are missing. ``` ## 31. Open decisions These are intentionally not finalized in DOC-03: ```text 1. Exact signing implementation: raw Ed25519 vs cosign/Sigstore. 2. Exact local TLS strategy for intranet mode. 3. Whether `.kxcap` should support encryption at rest in MVP. 4. Whether seed data should be split by module. 5. Whether frontend build occurs only at capsule-build time or may be host-rebuilt in developer mode. 6. Whether Konnaxion Box should support rootless Docker in MVP. 7. Whether support images must always be embedded or may use a signed/pinned external registry policy. 8. Whether public_vps should require a real DNS domain or allow sslip.io/nip.io style demo hosts. ``` These decisions belong in: ```text DOC-05_Konnaxion_Agent_Security_Model.md DOC-06_Konnaxion_Network_Profiles.md DOC-07_Konnaxion_Security_Gate.md DOC-10_Konnaxion_Builder_CLI.md DOC-11_Konnaxion_Box_Appliance_Image.md ``` ## 32. Summary The Konnaxion Capsule format defines a secure, portable, plug-and-play package for deploying Konnaxion without exposing the user to Docker, Traefik, env files, database setup, firewall rules, or manual migrations. The capsule is immutable and signed. The instance is generated locally. Secrets are created at install time. Network exposure is controlled by predefined profiles. Internal services remain private. Public mode is never the default. For VPS deployment, the capsule must include offline-loadable image archives, the Agent must generate correct public runtime configuration, and healthchecks must distinguish infrastructure failure from application-level route responses. Canonical target: ```text Konnaxion Capsule ↓ Konnaxion Capsule Manager ↓ Konnaxion Agent ↓ Security Gate ↓ Docker Compose Runtime ↓ Konnaxion Instance ``` ================================================================================================ FILE: docs/DOC-04_Konnaxion_Manager_Architecture.md AUTHORITY: reference CONTENT_ROLE: knowledge CONTENT_SHA256: 98b477b85903cfb8f072289acfea95f951332db5c44bd4f46db83e2d38342c19 CONTENT_BYTES: 23172 ================================================================================================ --- doc_id: DOC-04 title: Konnaxion Manager Architecture project: Konnaxion app_version: v14 param_version: kx-param-2026.04.30 status: draft depends_on: - DOC-00_Konnaxion_Canonical_Variables.md - DOC-02_Konnaxion_Capsule_Architecture.md - DOC-03_Konnaxion_Capsule_Format.md - DOC-05_Konnaxion_Agent_Security_Model.md - DOC-06_Konnaxion_Network_Profiles.md - DOC-07_Konnaxion_Security_Gate.md --- # DOC-04 — Konnaxion Manager Architecture ## 1. Purpose `DOC-04_Konnaxion_Manager_Architecture.md` defines the architecture of the **Konnaxion Capsule Manager**. The Konnaxion Capsule Manager is the user-facing control layer responsible for turning a signed `.kxcap` file into a running **Konnaxion Instance** with minimal configuration. It must provide a plug-and-play experience while enforcing security controls by default. The Manager does **not** replace Konnaxion. It manages Konnaxion. ```text Konnaxion Capsule Manager = import capsule + verify capsule + create instance + generate secrets + apply network profile + start/stop/update Konnaxion + show URLs, health, logs, backup status + enforce safe defaults ``` --- ## 2. Canonical Product Position The Manager is part of the larger appliance model. ```text Konnaxion Box └── Konnaxion Capsule Manager └── Konnaxion Agent └── Docker Compose Runtime └── Konnaxion Instance ``` The Manager is the local operator interface. The Agent is the privileged execution layer. Docker Compose is the runtime layer. Konnaxion is the application layer. --- ## 3. Design Goals The Manager must satisfy the following goals. ### 3.1 Plug-and-play first The user should not manually configure: ```text Docker Compose Traefik Nginx PostgreSQL Redis Celery Django env files Next.js env files firewall rules certificates ports systemd services migrations ``` The normal path should be: ```text 1. Open Konnaxion Capsule Manager 2. Import .kxcap 3. Choose network profile 4. Click Start 5. Open Konnaxion URL ``` ### 3.2 Private-by-default The default mode must be private. ```env KX_NETWORK_PROFILE=intranet_private KX_EXPOSURE_MODE=private KX_PUBLIC_MODE_ENABLED=false ``` The Manager must never default to public exposure. ### 3.3 Security as a gate, not a warning Security validation must run before the instance starts. If a critical rule fails, the Manager must block startup. ```text Security Gate result: FAIL_BLOCKING Action: do not start instance ``` ### 3.4 Zero manual secrets The Manager must generate secrets locally during instance creation. The capsule must contain templates only. The Manager must never import real production secrets from a `.kxcap`. ### 3.5 Reproducible instances Given the same capsule and the same profile, the Manager must produce a predictable instance layout. Runtime data must remain outside the capsule. ```text Capsule = immutable package Instance = mutable state ``` --- ## 4. Non-Goals The Manager is not: ```text a general Docker GUI a replacement for Docker Compose a Kubernetes orchestrator a cloud hosting platform a public control panel a remote admin panel exposed to the web a tool for running arbitrary containers a secrets vault for unrelated services ``` The Manager should not allow users to run arbitrary Docker images, arbitrary shell commands, arbitrary port mappings, or arbitrary host mounts. --- ## 5. High-Level Architecture ```text ┌──────────────────────────────────────────────┐ │ User / Operator │ └──────────────────────┬───────────────────────┘ │ ▼ ┌──────────────────────────────────────────────┐ │ Konnaxion Capsule Manager UI │ │ Desktop UI or local-only web UI │ └──────────────────────┬───────────────────────┘ │ Local API ▼ ┌──────────────────────────────────────────────┐ │ Konnaxion Agent │ │ Privileged service with restricted actions │ └──────────────────────┬───────────────────────┘ │ ┌──────────────┼────────────────┐ ▼ ▼ ▼ ┌─────────────┐ ┌─────────────┐ ┌──────────────┐ │ Docker │ │ Firewall │ │ Filesystem │ │ Compose │ │ / Network │ │ / Backups │ └──────┬──────┘ └─────────────┘ └──────────────┘ │ ▼ ┌──────────────────────────────────────────────┐ │ Konnaxion Runtime │ │ Traefik + Next.js + Django + Postgres + Redis│ └──────────────────────────────────────────────┘ ``` --- ## 6. Internal Components ### 6.1 Manager UI Canonical name: ```text Konnaxion Capsule Manager ``` Possible implementation: ```text Tauri + React or local-only web UI served on 127.0.0.1 ``` Recommended target: ```text Tauri + React frontend Rust or Go local backend bridge ``` Responsibilities: ```text display installed instances import capsules show health state show security state show current network profile start/stop instances initiate backups initiate restores initiate updates show logs show URLs request profile changes ``` The UI must not directly call Docker or manipulate firewall rules. All privileged actions must go through the Konnaxion Agent. --- ### 6.2 Konnaxion Agent Canonical name: ```text Konnaxion Agent ``` The Agent is a local privileged service. It exposes a restricted local API to the Manager UI. It performs only allowlisted operations. Allowed operations: ```text capsule.verify capsule.import instance.create instance.start instance.stop instance.status instance.logs instance.backup instance.restore instance.update instance.rollback security.check network.set_profile ``` Forbidden operations: ```text run arbitrary shell command run arbitrary Docker image run arbitrary Docker Compose file mount arbitrary host path bind arbitrary host port enable privileged containers mount Docker socket into a container enable host network mode disable Security Gate disable signature validation ``` --- ### 6.3 Capsule Importer The Capsule Importer is responsible for reading `.kxcap` files. Pipeline: ```text 1. Receive .kxcap path 2. Verify file exists 3. Verify extension is .kxcap 4. Unpack to temporary quarantine path 5. Validate manifest schema 6. Verify checksums 7. Verify signature 8. Validate service allowlist 9. Validate network policy 10. Move capsule to /opt/konnaxion/capsules/ ``` Canonical storage path: ```text /opt/konnaxion/capsules/.kxcap ``` The importer must not start any service. Import and start are separate actions. --- ### 6.4 Instance Controller The Instance Controller creates and manages `Konnaxion Instance` directories. Canonical path: ```text /opt/konnaxion/instances// ``` Canonical structure: ```text /opt/konnaxion/instances// ├── env/ ├── postgres/ ├── redis/ ├── media/ ├── logs/ ├── backups/ ├── state/ └── compose/ ``` Responsibilities: ```text create instance directory generate instance ID link capsule to instance generate secrets render env files from templates render docker-compose from profile prepare volumes run migrations create initial admin flow track lifecycle state ``` --- ### 6.5 Network Profile Controller The Network Profile Controller applies one of the canonical network profiles. Canonical profiles: ```text local_only intranet_private private_tunnel public_temporary public_vps offline ``` Responsibilities: ```text select profile render Traefik config configure local firewall configure bind addresses configure allowed ports configure tunnel if enabled set public/private URLs enforce blocked ports ``` The Manager must never expose internal services directly. Always internal: ```text frontend-next direct port django-api direct port postgres redis celeryworker celerybeat flower unless private docker daemon ``` --- ### 6.6 Security Gate The Security Gate is a blocking validation layer. It must run before: ```text instance.start network.set_profile instance.update public_temporary enablement public_vps enablement ``` Required checks: ```text capsule_signature image_checksums manifest_schema secrets_present secrets_not_default firewall_enabled dangerous_ports_blocked postgres_not_public redis_not_public docker_socket_not_mounted no_privileged_containers no_host_network allowed_images_only admin_surface_private backup_configured ``` Canonical result values: ```text PASS WARN FAIL_BLOCKING SKIPPED UNKNOWN ``` If any critical check returns `FAIL_BLOCKING`, startup is refused. --- ### 6.7 Runtime Adapter The Runtime Adapter is the abstraction between the Agent and Docker Compose. Initial runtime: ```text Docker Compose ``` Runtime commands are generated, not user-written. The Manager should own the runtime files under: ```text /opt/konnaxion/instances//compose/ ``` The generated compose must include only canonical services: ```text traefik frontend-next django-api postgres redis celeryworker celerybeat flower media-nginx ``` The Runtime Adapter must reject: ```text unknown services unknown images privileged: true network_mode: host ports exposing postgres ports exposing redis ports exposing django directly ports exposing frontend directly volumes mounting /, /etc, /root, /var/run/docker.sock ``` --- ### 6.8 Backup Controller The Backup Controller manages backup and restore. Backup scope: ```text PostgreSQL dump media files instance env metadata without leaking secrets in logs capsule reference profile reference manager state ``` Backups must not include: ```text Docker images already stored in capsule temporary files runtime sockets raw logs with secrets unverified external files ``` Canonical path: ```text /opt/konnaxion/instances//backups/ ``` Default retention: ```env KX_BACKUP_ENABLED=true KX_BACKUP_RETENTION_DAYS=14 ``` --- ### 6.9 Update and Rollback Controller Each capsule is immutable. Update flow: ```text 1. Verify new capsule 2. Backup current instance 3. Stage new runtime config 4. Run compatibility checks 5. Apply migrations 6. Start new version 7. Run healthchecks 8. Mark new capsule as current ``` Rollback flow: ```text 1. Stop failed runtime 2. Restore previous compose configuration 3. Restore previous capsule reference 4. Restore backup if required 5. Start previous version 6. Run healthchecks ``` The Manager must keep at least one rollback point by default. --- ## 7. Manager UI Screens ### 7.1 Home Screen Required information: ```text Instance name Instance state Network profile Exposure mode Primary URL Security state Backup state App version Capsule version ``` Example: ```text Konnaxion Demo Status: Running Network: Intranet Private URL: https://konnaxion.local Security: PASS Backups: Enabled App Version: v14 Capsule: konnaxion-v14-demo-2026.04.30 ``` Actions: ```text Open Konnaxion Start Stop Restart Backup View Logs Security Check Change Network Profile Update ``` --- ### 7.2 Capsule Import Screen Fields: ```text Capsule file Capsule ID Capsule version App version Signature status Required RAM Recommended RAM Included services Supported profiles ``` Actions: ```text Verify Import Cancel ``` Startup is not allowed from this screen until verification passes. --- ### 7.3 Network Profile Screen The user chooses only from predefined profiles. Options: ```text Local Only Intranet Private Private Tunnel Public Temporary Public VPS Offline ``` The screen must show consequences clearly. Example: ```text Profile: Intranet Private Accessible from: local network only Internet exposure: disabled Allowed public ports: none Allowed LAN ports: 443 Database exposure: blocked Redis exposure: blocked ``` --- ### 7.4 Security Screen Required checklist: ```text Capsule signature Image checksums Secrets Firewall Dangerous ports Postgres exposure Redis exposure Docker socket Privileged containers Host network Unknown images Admin surface Backup configuration ``` Each check must show one canonical status: ```text PASS WARN FAIL_BLOCKING SKIPPED UNKNOWN ``` --- ### 7.5 Logs Screen The Logs screen must support: ```text traefik logs frontend-next logs django-api logs postgres logs redis logs celeryworker logs celerybeat logs flower logs manager logs agent logs ``` Logs must redact secrets. Never display full values of: ```text DJANGO_SECRET_KEY POSTGRES_PASSWORD DATABASE_URL API keys tokens private keys session secrets ``` --- ### 7.6 Backup and Restore Screen Required actions: ```text Create Backup Restore Backup Download Backup Delete Backup Verify Backup ``` Required metadata: ```text Backup ID Created at App version Capsule version Database size Media size Profile at backup time Restore compatibility status ``` --- ### 7.7 Update Screen Required information: ```text Current capsule New capsule Compatibility result Migration required Backup required Rollback point available Expected downtime Security check result ``` Required actions: ```text Verify Update Apply Update Rollback Cancel ``` --- ## 8. Lifecycle States Canonical lifecycle states: ```text created importing verifying ready starting running stopping stopped updating rolling_back degraded failed security_blocked ``` State transitions: ```text created -> verifying -> ready ready -> starting -> running running -> stopping -> stopped running -> updating -> running running -> updating -> rolling_back -> running ready -> security_blocked starting -> failed running -> degraded ``` The UI must always show the current state. --- ## 9. Local API Contract The UI communicates with the Agent through a local API. The API must be local-only. Allowed binding: ```text 127.0.0.1 ``` Forbidden binding: ```text 0.0.0.0 public interface LAN interface by default ``` Recommended transport: ```text Unix socket on Linux Named pipe on Windows localhost HTTPS only if needed ``` Canonical endpoints: ```text GET /v1/instances POST /v1/capsules/verify POST /v1/capsules/import POST /v1/instances GET /v1/instances/{INSTANCE_ID} POST /v1/instances/{INSTANCE_ID}/start POST /v1/instances/{INSTANCE_ID}/stop POST /v1/instances/{INSTANCE_ID}/restart GET /v1/instances/{INSTANCE_ID}/logs POST /v1/instances/{INSTANCE_ID}/backup POST /v1/instances/{INSTANCE_ID}/restore POST /v1/instances/{INSTANCE_ID}/update POST /v1/instances/{INSTANCE_ID}/rollback POST /v1/instances/{INSTANCE_ID}/security-check POST /v1/instances/{INSTANCE_ID}/network-profile ``` Every write operation must be authenticated locally. The UI and Agent should use a locally generated pairing token or OS-level permissions. --- ## 10. Configuration Model Manager configuration path: ```text /opt/konnaxion/manager/config.yaml ``` Example: ```yaml manager: version: "0.1.0" bind: "127.0.0.1" log_level: "INFO" security: require_signed_capsule: true allow_unknown_images: false allow_privileged_containers: false allow_host_network: false allow_docker_socket_mount: false defaults: network_profile: "intranet_private" exposure_mode: "private" backup_enabled: true backup_retention_days: 14 paths: root: "/opt/konnaxion" capsules: "/opt/konnaxion/capsules" instances: "/opt/konnaxion/instances" backups: "/opt/konnaxion/backups" ``` Instance state path: ```text /opt/konnaxion/instances//state/instance.yaml ``` Example: ```yaml instance_id: "demo-001" capsule_id: "konnaxion-v14-demo-2026.04.30" capsule_version: "2026.04.30-demo.1" app_version: "v14" network_profile: "intranet_private" exposure_mode: "private" state: "running" primary_url: "https://konnaxion.local" created_at: "2026-04-30T00:00:00Z" updated_at: "2026-04-30T00:00:00Z" ``` --- ## 11. Environment Variables The Manager and Agent use `KX_*` variables. Required: ```env KX_INSTANCE_ID=demo-001 KX_CAPSULE_ID=konnaxion-v14-demo-2026.04.30 KX_CAPSULE_VERSION=2026.04.30-demo.1 KX_APP_VERSION=v14 KX_PARAM_VERSION=kx-param-2026.04.30 KX_NETWORK_PROFILE=intranet_private KX_EXPOSURE_MODE=private KX_PUBLIC_MODE_ENABLED=false KX_PUBLIC_MODE_EXPIRES_AT= KX_REQUIRE_SIGNED_CAPSULE=true KX_GENERATE_SECRETS_ON_INSTALL=true KX_ALLOW_UNKNOWN_IMAGES=false KX_ALLOW_PRIVILEGED_CONTAINERS=false KX_ALLOW_DOCKER_SOCKET_MOUNT=false KX_ALLOW_HOST_NETWORK=false KX_BACKUP_ENABLED=true KX_BACKUP_RETENTION_DAYS=14 ``` --- ## 12. Service Boundaries ### 12.1 Manager UI boundary Can: ```text display state request operations show results ``` Cannot: ```text directly run Docker directly modify firewall directly write secrets directly edit compose files directly expose ports ``` ### 12.2 Agent boundary Can: ```text execute allowlisted operations manage instance directories render env files render compose files call Docker Compose configure approved network rules run backups run healthchecks ``` Cannot: ```text accept arbitrary shell commands accept arbitrary Docker commands run unsigned capsules skip security checks mount Docker socket into Konnaxion containers ``` ### 12.3 Runtime boundary Can: ```text run canonical Konnaxion services use private Docker networks persist data in instance volumes ``` Cannot: ```text open unmanaged public ports run unknown containers share host root filesystem depend on secrets embedded in capsule ``` --- ## 13. Security Defaults Default values: ```yaml default_network_profile: intranet_private default_exposure_mode: private public_mode_enabled: false require_signed_capsule: true allow_unknown_images: false allow_privileged_containers: false allow_host_network: false allow_docker_socket_mount: false backup_enabled: true ``` Always blocked: ```text 3000/tcp 5000/tcp 5432/tcp 6379/tcp 5555/tcp 8000/tcp Docker daemon TCP ``` Allowed only through Traefik: ```text / /api/ /admin/ /media/ ``` --- ## 14. Error Model Canonical error classes: ```text CAPSULE_INVALID CAPSULE_SIGNATURE_FAILED CAPSULE_CHECKSUM_FAILED MANIFEST_INVALID IMAGE_NOT_ALLOWED SERVICE_NOT_ALLOWED PORT_NOT_ALLOWED SECRET_GENERATION_FAILED FIREWALL_CONFIG_FAILED SECURITY_GATE_FAILED INSTANCE_ALREADY_EXISTS INSTANCE_NOT_FOUND RUNTIME_START_FAILED RUNTIME_HEALTHCHECK_FAILED BACKUP_FAILED RESTORE_FAILED UPDATE_FAILED ROLLBACK_FAILED ``` Every error must include: ```text error_code human_message technical_message suggested_action blocking timestamp ``` Example: ```yaml error_code: "PORT_NOT_ALLOWED" human_message: "This profile cannot expose PostgreSQL." technical_message: "Service postgres attempted to bind host port 5432." suggested_action: "Remove the port binding or choose an approved network profile." blocking: true timestamp: "2026-04-30T00:00:00Z" ``` --- ## 15. Observability The Manager must expose a local health summary. Required health categories: ```text manager agent docker traefik frontend-next django-api postgres redis celeryworker celerybeat media-nginx backup security network ``` Example status values: ```text healthy degraded unhealthy unknown stopped ``` The Manager must show enough information to troubleshoot without revealing secrets. --- ## 16. Implementation Recommendation Recommended technology stack: ```text Manager UI: Tauri + React + TypeScript Agent: Rust or Go Runtime: Docker Compose Reverse proxy: Traefik Local storage: YAML state files + SQLite optional Packaging: signed installers + .kxcap capsules ``` Why this choice: ```text Tauri keeps the desktop app lighter than Electron. React aligns with Konnaxion frontend skills. Rust or Go is suitable for a small privileged service. Docker Compose matches the existing Konnaxion deployment model. Traefik is already part of the production routing model. ``` Do not introduce Kubernetes in the MVP. --- ## 17. MVP Scope The first implementation of the Manager should include: ```text capsule verify capsule import instance create instance start instance stop instance status logs network profile: local_only network profile: intranet_private network profile: public_temporary security check backup restore ``` MVP may defer: ```text multi-instance management remote fleet management plugin system automatic OS imaging public VPS provisioning advanced RBAC full GUI theme customization ``` --- ## 18. Acceptance Criteria DOC-04 is implemented correctly when: ```text A user can import a signed .kxcap file. A user can create a Konnaxion Instance without editing env files. Secrets are generated automatically. The default network profile is intranet_private. The Manager refuses to start if security checks fail. Postgres is never public. Redis is never public. Next.js direct port is never public. Django direct port is never public. Docker socket is never mounted into containers. The user receives a working Konnaxion URL. The user can stop, restart, backup and restore the instance. ``` --- ## 19. Open Decisions The following decisions remain open: ```text Should the first Manager UI be Tauri desktop or local web UI? Should the Agent be written in Rust or Go? Should local secrets be stored in OS keychain or protected env files? Should public_temporary use Cloudflare Tunnel, Tailscale Funnel, or both? Should the appliance image be based on Ubuntu Server or Debian? Should the first release support Windows hosts or Linux hosts only? ``` Default recommendation for MVP: ```text Linux host first Ubuntu Server LTS first Docker Compose runtime Local web UI first if speed matters Tauri UI second if product polish matters Cloudflare Tunnel optional Tailscale private tunnel optional ``` --- ## 20. Summary The Konnaxion Capsule Manager is the plug-and-play control surface for Konnaxion. It must hide infrastructure complexity while enforcing strict security defaults. The correct architecture is: ```text Manager UI -> local Agent -> verified capsule -> generated instance -> Docker Compose runtime -> Traefik-only exposure -> private-by-default network profile ``` The Manager must make the safe path easy and the unsafe path impossible by default. ================================================================================================ FILE: docs/DOC-05_Konnaxion_Agent_Security_Model.md AUTHORITY: reference CONTENT_ROLE: knowledge CONTENT_SHA256: a32a77f3a197fa638debb551363e5f833227eab22cd8f7a8adc8c23f364c1b0c CONTENT_BYTES: 29941 ================================================================================================ --- doc_id: DOC-05 title: Konnaxion Agent Security Model project: Konnaxion app_version: v14 param_version: kx-param-2026.04.30 status: draft owner: Konnaxion Architecture last_updated: 2026-04-30 depends_on: - DOC-00_Konnaxion_Canonical_Variables.md - DOC-02_Konnaxion_Capsule_Architecture.md - DOC-03_Konnaxion_Capsule_Format.md - DOC-04_Konnaxion_Manager_Architecture.md - DOC-06_Konnaxion_Network_Profiles.md - DOC-07_Konnaxion_Security_Gate.md --- # DOC-05 — Konnaxion Agent Security Model ## 1. Purpose This document defines the security model for **Konnaxion Agent**, the privileged local service used by **Konnaxion Capsule Manager** to install, verify, configure, start, stop, update, and monitor **Konnaxion Instances**. The Agent exists because Konnaxion needs controlled access to privileged host operations: - create local directories under `/opt/konnaxion` - verify and import `.kxcap` capsules - load approved Docker/OCI images - generate secrets - create Docker networks and volumes - apply network profiles - enforce firewall rules - start and stop the Konnaxion runtime - run health checks and security checks - backup, restore, update, and rollback instances The Agent must make Konnaxion plug-and-play without giving the UI, user, or capsule unlimited system control. Konnaxion’s runtime stack includes a Next.js frontend, Django + DRF backend, PostgreSQL, Celery, Redis, Traefik, and media/static serving; therefore the Agent controls multiple services and must enforce safe network exposure by default. This stack is defined canonically in `DOC-00_Konnaxion_Canonical_Variables.md` and implemented by the runtime model in `DOC-08_Konnaxion_Runtime_Docker_Compose.md`. --- ## 2. Security rationale The Agent security model is based on the 2026-04 incident recovery lessons. The previous VPS was compromised during deployment. Observed compromise indicators included malicious Docker image `negoroo/amco:123`, containers `amco_*`, a miner process, `/tmp/sshd`, `/dev/shm/*`, deploy-user crontab persistence, `pakchoi` user creation attempts, and `/etc/sudoers.d/99-pakchoi`. The recovery notes explicitly state that the server should not be trusted long-term and that the correct fix is a clean rebuild, no disk clone, rotated secrets, SSH keys only, firewall hardening, and public exposure limited to `22`, `80`, and `443`. The Agent must therefore be designed as a **security boundary**, not merely a deployment helper. --- ## 3. Canonical component relationship ```text Konnaxion Capsule Manager ↓ local authenticated API Konnaxion Agent ↓ allowlisted privileged operations Host OS / firewall / Docker Engine ↓ controlled runtime Konnaxion Instance ``` The Manager is the user-facing interface. The Agent is the local privileged service. The Capsule is the portable application bundle. The Instance is the installed runtime with data, secrets, logs, backups, and state. --- ## 4. Primary rule The Agent must be: ```text private-by-default deny-by-default allowlist-driven signed-capsule-only least-privilege-oriented auditable rollback-safe ``` The Agent must not behave like a general-purpose remote shell, Docker dashboard, or root automation tool. --- ## 5. Non-goals The Agent is not: ```text a generic Docker manager a replacement for Portainer a remote administration tool a shell execution service a general CI/CD runner a Kubernetes orchestrator a public API server a user management system for Konnaxion itself ``` The Agent manages only **Konnaxion-approved operations**. --- ## 6. Trust boundaries ## 6.1 Trusted The following may be trusted after verification: ```text Konnaxion Agent binary installed from trusted source Konnaxion Capsule Manager binary installed from trusted source signed .kxcap files with valid signature host OS after clean install allowlisted Docker/OCI images with matching checksums locally generated secrets ``` ## 6.2 Partially trusted The following are partially trusted: ```text local administrator network environment Docker Engine host firewall imported media files restored database dumps ``` ## 6.3 Untrusted by default The following must be treated as untrusted: ```text unsigned capsules unknown Docker images old VPS disk images old Docker volumes old crontabs old authorized_keys old sudoers entries old /tmp and /dev/shm content logs copied from compromised machines .env files from compromised machines any user-provided shell command ``` Backups must not preserve malware. Recovery notes state that safe backups should include Postgres dumps, media/uploads, and configuration templates, but should not restore whole old disks, `/tmp`, `/dev/shm`, old crontabs, unknown systemd services, old authorized keys, old sudoers files, or unverified Docker volumes. --- ## 7. Privilege model ## 7.1 Two-process model The Manager must not run permanently as root/admin. Canonical model: ```text Konnaxion Capsule Manager - normal user process - no direct Docker socket access - no direct firewall control - no shell command execution Konnaxion Agent - local service - privileged only where needed - exposes narrow local API - validates every operation ``` ## 7.2 Agent privilege scope The Agent may perform these privileged operations: ```text create /opt/konnaxion directories set file ownership and permissions install or update systemd service files owned by Konnaxion apply firewall rules for approved network profiles create Docker networks create Docker volumes load allowlisted OCI images run approved Docker Compose projects read approved container logs stop/start approved Konnaxion services create and restore approved backups rotate generated secrets run Security Gate checks ``` The Agent must not allow: ```text arbitrary shell execution arbitrary Docker image execution arbitrary docker-compose.yml execution mounting host root filesystem into containers mounting /var/run/docker.sock into application containers privileged containers host network mode arbitrary port publishing arbitrary systemd unit creation arbitrary sudoers modification editing SSH server configuration without explicit approved operation ``` --- ## 8. User and group model ## 8.1 Canonical users Recommended host-level users: ```text kx-agent system service user for Konnaxion Agent kx-data non-login owner for instance data ops optional human maintenance user ``` Legacy names such as `deploy` may exist on old VPS deployments, but the capsule architecture should avoid relying on a broad `deploy` user with Docker control. ## 8.2 Docker group rule The Agent model must avoid placing normal users in the `docker` group. The recovery notes warn that the previous breach involved malicious Docker containers and cron persistence. They explicitly recommend avoiding `sudo usermod -aG docker deploy`, because Docker group access effectively grants root-level power. Canonical rule: ```text Normal user accounts MUST NOT be members of the docker group. Konnaxion Capsule Manager MUST NOT access Docker directly. Only Konnaxion Agent may control Docker, and only through allowlisted operations. ``` --- ## 9. Local API model The Agent exposes a local API to the Manager. ## 9.1 Binding The Agent API must bind only to local interfaces: ```text 127.0.0.1 ::1 Unix domain socket ``` The Agent API must never bind to: ```text 0.0.0.0 public IP LAN IP by default Tailscale IP by default ``` ## 9.2 Authentication Every Manager-to-Agent request must be authenticated. Acceptable mechanisms: ```text Unix socket with strict filesystem permissions local token generated at install time OS keychain-backed token mutual local certificate pair ``` The Agent must reject unauthenticated requests. ## 9.3 Authorization Every request must pass an operation allowlist. Example categories: ```text capsule.import capsule.verify instance.create instance.start instance.stop instance.status instance.logs instance.backup instance.restore instance.update instance.rollback network.set_profile security.check secrets.rotate ``` The API must not include: ```text shell.exec docker.run docker.compose.raw firewall.raw systemctl.raw file.write_anywhere ``` --- ## 10. Capsule verification Before importing or running a capsule, the Agent must verify: ```text capsule file extension is .kxcap manifest exists manifest schema is valid capsule version is supported APP_VERSION is compatible PARAM_VERSION is compatible signature is valid checksums match OCI images match manifest profiles are valid services are allowlisted ports are allowlisted volumes are allowlisted no secrets are embedded ``` A capsule must be rejected if it attempts to: ```text run privileged containers mount Docker socket use host network publish blocked ports mount host root directories override Agent policies include unknown service names include unknown images include real secrets disable Security Gate disable audit logging ``` --- ## 11. Docker runtime restrictions ## 11.1 Allowed services The Agent may only start the canonical Konnaxion service set: ```text traefik frontend-next django-api postgres redis celeryworker celerybeat flower media-nginx ``` `flower` is allowed only when private or explicitly protected. ## 11.2 Container restrictions All application containers must use: ```text restart policy approved by profile non-root user where practical read-only filesystem where practical explicit volumes only explicit networks only no privileged mode no host network no Docker socket mount no broad host mounts limited capabilities healthcheck required ``` ## 11.3 Unknown containers The Agent must detect unknown containers attached to Konnaxion networks or using Konnaxion names. Result: ```text Security Gate status: FAIL_BLOCKING Instance state: security_blocked ``` --- ## 12. Network security model ## 12.1 Public entrypoint rule Traefik is the only public entrypoint. Canonical routing: ```text / -> frontend-next /api/ -> django-api /admin/ -> django-api /media/ -> media-nginx ``` The existing deployment guide confirms the intended routing pattern: root to Next.js, `/api/` to Django, `/admin/` to Django admin, and `/media/` to the media service. ## 12.2 Ports always blocked from public exposure The Agent must never expose these ports publicly: ```text 3000 Next.js direct 5000 Django/Gunicorn internal 5432 PostgreSQL 6379 Redis 5555 Flower/dashboard 8000 Django dev server Docker daemon TCP ports ``` The recovery guide explicitly warns that public users should reach only Traefik on `80/443`, not frontend direct on `3000`, dashboard/admin on `5555`, Postgres on `5432`, Redis on `6379`, or Django/Gunicorn on `8000`. ## 12.3 Network profiles The Agent may apply only canonical network profiles: ```text local_only intranet_private private_tunnel public_temporary public_vps offline ``` Default profile: ```env KX_NETWORK_PROFILE=intranet_private KX_EXPOSURE_MODE=private KX_PUBLIC_MODE_ENABLED=false ``` ## 12.4 Public temporary mode If public temporary mode is enabled: ```text expiration is mandatory auth is mandatory where supported tunnel must close automatically public exposure must be logged rollback to private mode must be automatic ``` Required variables: ```env KX_PUBLIC_MODE_ENABLED=true KX_PUBLIC_MODE_EXPIRES_AT= ``` If `KX_PUBLIC_MODE_ENABLED=true` and `KX_PUBLIC_MODE_EXPIRES_AT` is empty, Security Gate must return: ```text FAIL_BLOCKING ``` --- ## 13. Firewall control The Agent may manage firewall rules only through approved profiles. ## 13.1 Deny-by-default baseline ```text deny incoming allow outgoing allow local loopback allow approved profile ports only ``` ## 13.2 Approved exposure by profile | Profile | Allowed exposure | | ------------------ | --------------------------------- | | `offline` | no external exposure | | `local_only` | localhost only | | `intranet_private` | LAN `443`, optional `80` redirect | | `private_tunnel` | tunnel/VPN only | | `public_temporary` | temporary tunnel endpoint | | `public_vps` | `80/443`, SSH restricted | ## 13.3 SSH policy The Agent should not expose SSH automatically for appliance/demo modes. If SSH is enabled: ```text key-only no root login no password login restricted source IP or VPN ``` --- ## 14. Secrets model ## 14.1 Capsule secrets rule Capsules must not contain real secrets. Forbidden inside `.kxcap`: ```text DJANGO_SECRET_KEY POSTGRES_PASSWORD DATABASE_URL with password SSH private keys API tokens provider credentials Django admin password Sentry DSN if private email provider password storage provider secret ``` The deployment/security notes identify these as sensitive values that must not be pasted into logs/chats and must be rotated if exposed. ## 14.2 Secret generation The Agent generates secrets on install: ```text DJANGO_SECRET_KEY POSTGRES_PASSWORD initial admin password or one-time setup token internal service tokens local Manager-Agent token backup encryption key if enabled ``` ## 14.3 Secret storage Secrets must be stored under the instance environment directory: ```text /opt/konnaxion/instances//env/ ``` Required permissions: ```text owner: kx-agent or root group: kx-agent mode: 0600 for secret files mode: 0700 for env directory ``` ## 14.4 Secret rotation The Agent must support: ```text kx instance rotate-secrets ``` At minimum, rotation must cover: ```text DJANGO_SECRET_KEY POSTGRES_PASSWORD Manager-Agent local token initial admin setup token ``` Rotation must trigger: ```text backup before rotation service restart healthcheck audit event ``` --- ## 15. File system model ## 15.1 Canonical paths ```text /opt/konnaxion/ ├── capsules/ ├── instances/ ├── shared/ ├── releases/ ├── manager/ └── backups/ ``` Instance path: ```text /opt/konnaxion/instances// ├── env/ ├── postgres/ ├── redis/ ├── media/ ├── logs/ ├── backups/ └── state/ ``` ## 15.2 Path restrictions The Agent may write only under: ```text /opt/konnaxion /etc/systemd/system/konnaxion-agent.service approved firewall configuration locations approved log directory ``` The Agent must not write arbitrary files under: ```text /etc/sudoers.d /root /home/* /tmp for persistent scripts /dev/shm /usr/bin /usr/local/bin except approved installed binaries ``` ## 15.3 Temporary files Temporary files must be: ```text created under Agent-owned temp directory not executable by default removed after operation never used as persistence ``` --- ## 16. Security Gate integration Before starting or updating an instance, the Agent must run Security Gate. ## 16.1 Required checks ```text capsule_signature image_checksums manifest_schema secrets_present secrets_not_default firewall_enabled dangerous_ports_blocked postgres_not_public redis_not_public docker_socket_not_mounted no_privileged_containers no_host_network allowed_images_only admin_surface_private backup_configured unknown_containers_absent unknown_cron_absent suspicious_tmp_absent unexpected_sudoers_absent ``` ## 16.2 Status values The Agent must return only canonical Security Gate statuses: ```text PASS WARN FAIL_BLOCKING SKIPPED UNKNOWN ``` ## 16.3 Blocking conditions The following always return `FAIL_BLOCKING`: ```text unsigned capsule invalid checksum unknown image privileged container Docker socket mounted host network mode public Postgres public Redis public Docker daemon public frontend direct port public Flower/dashboard without protection missing generated secrets default passwords unknown Konnaxion-like containers known malware indicators ``` Known malware indicators include names or patterns from the previous incident: ```text amco_* negoroo/amco supportxmr rx/0 /tmp/sshd pakchoi /dev/shm executable files unexpected crontabs unexpected sudoers files ``` The incident recovery notes specifically instruct checking for these indicators after deployment and during cleanup. --- ## 17. Audit logging The Agent must log every privileged action. ## 17.1 Audit event fields ```yaml event_id: string timestamp: ISO8601 instance_id: string actor: local_user | manager | system operation: string request_id: string result: PASS | WARN | FAIL | DENIED network_profile: string exposure_mode: string capsule_id: string capsule_version: string details_redacted: object ``` ## 17.2 Never log Audit logs must never include: ```text DJANGO_SECRET_KEY POSTGRES_PASSWORD DATABASE_URL with password API keys tokens private keys admin passwords backup encryption keys ``` ## 17.3 Required logged actions ```text capsule import capsule verification instance create instance start instance stop instance update instance rollback network profile change public temporary mode enable public temporary mode expire secret generation secret rotation backup backup verification backup test-restore restore pre-restore backup pre-update backup Security Gate failure unknown container detection firewall rule application ``` --- ## 18. Backup, restore and rollback security This section defines the Agent-side security rules for backup, restore and rollback. The detailed backup format, retention policy and operator workflows are defined in `DOC-09_Konnaxion_Backup_Restore_Rollback.md`. The Agent must treat backup/restore as privileged security-sensitive operations, not as simple file copy operations. ## 18.1 Approved backup operations The Agent may perform only these backup operations: ```text create verified backup sets create pre-update backups create pre-restore backups create manual backups list backups for a known Konnaxion Instance verify backup manifests and checksums test-restore a backup into a temporary local_only instance export a backup only through an approved backup/export path expire backups according to canonical retention policy quarantine failed or suspicious backups ``` The Agent must not allow raw filesystem backup jobs requested by the UI or capsule. ## 18.2 Approved backup contents Approved backup contents: ```text PostgreSQL logical dump media/uploads archive instance metadata capsule reference metadata network profile snapshot Security Gate report healthcheck result safe configuration templates redacted manifest copy checksums backup manifest ``` The backup protects **application data**, not the host operating system. ## 18.3 Backup exclusions Backups must exclude: ```text host system files entire disk images Docker daemon state Docker socket old crontabs old systemd services /tmp /dev/shm authorized_keys sudoers files unknown Docker volumes malware scan positives private keys plaintext secrets raw .env files containing secrets ``` If any excluded content is detected in a backup plan or backup set, the Agent must return: ```text FAIL_BLOCKING ``` and refuse to promote the backup to verified status. ## 18.4 Approved restore operations The Agent may perform only these restore operations: ```text restore PostgreSQL from a verified dump restore media/uploads from a verified archive restore into a new Konnaxion Instance restore into an existing Konnaxion Instance after pre-restore backup restore database-only restore media-only run migrations after restore when required run Security Gate after restore run healthchecks after restore ``` Preferred restore target for risky operations: ```text new instance + local_only profile ``` This avoids overwriting a working instance before the restored state is verified. ## 18.5 Forbidden restore operations The Agent must never restore: ```text old disk image old Docker daemon state old system users old crontabs old sudoers files old authorized_keys old /tmp old /dev/shm unknown containers unknown Docker volumes unverified binaries unverified systemd units malware cleanup quarantine folders ``` The Agent must restore only approved Konnaxion application state: ```text database media metadata safe generated configuration ``` ## 18.6 Restore policy Before restore, the Agent must: ```text verify backup metadata verify backup checksums scan for forbidden paths scan for leaked secrets verify target instance state create a pre-restore backup unless impossible stop affected services restore approved data only run migrations if required run Security Gate restart services run healthcheck log the operation ``` A restore is successful only if: ```text backup verification passes restore operation completes Security Gate returns PASS or allowed WARN healthcheck passes dangerous ports remain blocked Postgres remains internal Redis remains internal Docker socket remains unmounted ``` ## 18.7 Backup and restore API boundary The Manager may request high-level operations such as: ```text backup this instance verify this backup restore this backup restore this backup into a new instance rollback this instance ``` The Manager must not request low-level operations such as: ```text dump arbitrary path restore arbitrary path run arbitrary pg_restore command write arbitrary file execute arbitrary shell script mount arbitrary Docker volume ``` The Agent owns the implementation details and must enforce the policy regardless of UI behavior. --- ## 19. Update and rollback security ## 19.1 Immutable capsule rule Capsules are immutable after import. Updates use a new capsule: ```text current -> konnaxion-v14-demo-2026.04.30 next -> konnaxion-v14-demo-2026.05.05 ``` The Agent must never patch an imported `.kxcap` in place. ## 19.2 Approved rollback operations The Agent may perform only these rollback operations: ```text capsule rollback data rollback from verified backup full instance rollback from verified backup and previous capsule reference automatic rollback after failed update manual rollback requested by Manager ``` Default rule: ```text capsule rollback first data rollback only when schema/data changes require it ``` The Agent must not automatically roll back data unless the update process marked the database or media as changed. ## 19.3 Update sequence Canonical update sequence: ```text 1. Verify new capsule signature. 2. Verify new capsule checksums. 3. Create pre-update backup. 4. Load only allowlisted images. 5. Create staged runtime. 6. Run migrations if required. 7. Run healthchecks. 8. Run Security Gate. 9. Switch current capsule pointer only after validation. 10. Stop old runtime. 11. Log update result. ``` If validation fails before the capsule pointer switch, the Agent must discard the staged runtime and keep the current instance unchanged. ## 19.4 Rollback sequence Canonical rollback sequence: ```text 1. Stop failed runtime. 2. Restore previous capsule pointer. 3. Restore compatible DB backup only if required. 4. Restore media only if required. 5. Start previous runtime. 6. Run migrations only if compatible and required. 7. Run healthchecks. 8. Run Security Gate. 9. Log rollback result. ``` If rollback fails, the Agent must: ```text disable public exposure switch to safest private profile available mark instance security_blocked or failed keep services stopped if integrity is unknown preserve logs and rollback metadata ``` --- ## 20. Agent API — canonical operations The Agent API must expose only high-level operations. ```text GET /v1/status GET /v1/instances GET /v1/instances/ POST /v1/capsules/import POST /v1/capsules/verify POST /v1/instances/create POST /v1/instances//start POST /v1/instances//stop POST /v1/instances//restart POST /v1/instances//update POST /v1/instances//rollback POST /v1/instances//network-profile POST /v1/instances//security-check POST /v1/instances//rotate-secrets POST /v1/instances//backup GET /v1/instances//backups POST /v1/instances//restore POST /v1/instances/restore-new POST /v1/backups//verify POST /v1/backups//test-restore GET /v1/instances//logs GET /v1/instances//health ``` These endpoints are logical API operations. They do not imply public HTTP exposure. The Agent API must remain local-only. Forbidden API patterns: ```text POST /shell POST /exec POST /docker/run POST /docker/raw POST /firewall/raw POST /systemctl/raw POST /files/write POST /files/read-arbitrary POST /backup/raw-path POST /restore/raw-path POST /postgres/raw ``` The Agent must not expose raw Docker, raw firewall, raw systemd, raw file, raw PostgreSQL, or shell execution primitives. --- ## 21. Runtime health checks The Agent must verify: ```text Traefik responds on approved entrypoint frontend-next responds behind Traefik django-api responds behind Traefik /api/ health endpoint responds /admin/ is reachable only through approved route Postgres reachable only from internal network Redis reachable only from internal network Celery worker is running Celery beat is running if enabled media-nginx serves expected media route no blocked ports are externally reachable ``` The frontend runbook confirms that the current Next.js service runs on port `3000` locally and must be validated through both local service checks and public domain checks; in the capsule model, this direct port must remain internal behind Traefik. --- ## 22. Failure behavior ## 22.1 Fail closed If the Agent cannot determine whether a configuration is safe, it must fail closed. Examples: ```text firewall status unknown -> FAIL_BLOCKING capsule signature unknown -> FAIL_BLOCKING Docker socket mount unknown -> FAIL_BLOCKING public port state unknown -> FAIL_BLOCKING ``` ## 22.2 Degraded mode The Agent may allow `degraded` state only when: ```text network remains private data remains safe no dangerous port is exposed no unknown container is running failure is recoverable ``` ## 22.3 Security blocked state When a blocking security issue exists: ```text KX_INSTANCE_STATE=security_blocked ``` The Manager must display: ```text Instance blocked by Security Gate. No public exposure has been enabled. Review security check details. ``` --- ## 23. Configuration variables Agent-specific variables use the `KX_` prefix. ```env KX_AGENT_ENABLED=true KX_AGENT_BIND=unix:///run/konnaxion-agent.sock KX_AGENT_LOG_LEVEL=INFO KX_AGENT_AUDIT_LOG=/opt/konnaxion/manager/logs/audit.log KX_REQUIRE_SIGNED_CAPSULE=true KX_ALLOW_UNKNOWN_IMAGES=false KX_ALLOW_PRIVILEGED_CONTAINERS=false KX_ALLOW_DOCKER_SOCKET_MOUNT=false KX_ALLOW_HOST_NETWORK=false KX_DEFAULT_NETWORK_PROFILE=intranet_private KX_PUBLIC_MODE_ENABLED=false KX_PUBLIC_MODE_EXPIRES_AT= KX_BACKUP_ENABLED=true KX_BACKUP_RETENTION_DAYS=14 KX_SECURITY_GATE_REQUIRED=true ``` --- ## 24. Minimal systemd unit concept The production implementation may use a system service similar to: ```ini [Unit] Description=Konnaxion Agent After=network-online.target docker.service Wants=network-online.target [Service] Type=simple User=root Group=root ExecStart=/opt/konnaxion/manager/bin/konnaxion-agent Restart=on-failure RestartSec=5 NoNewPrivileges=true PrivateTmp=true ProtectSystem=full ProtectHome=true ReadWritePaths=/opt/konnaxion /run /var/log/konnaxion EnvironmentFile=-/opt/konnaxion/manager/agent.env [Install] WantedBy=multi-user.target ``` The final unit must be reviewed before production. If rootless Docker is adopted, the service user and permissions should be reduced accordingly. --- ## 25. Acceptance criteria The Agent security model is implemented correctly when: ```text Manager cannot run Docker directly. Manager cannot execute arbitrary shell commands. Agent API is local-only. Agent rejects unsigned capsules. Agent rejects unknown images. Agent rejects dangerous ports. Agent rejects privileged containers. Agent rejects Docker socket mounts. Agent rejects host network mode. Agent generates secrets locally. Agent never stores real secrets inside .kxcap. Agent applies deny-by-default network profile. Agent defaults to intranet_private or local_only. Agent requires expiration for public_temporary. Agent blocks startup if Security Gate fails. Agent logs all privileged operations. Agent supports backup before update. Agent supports pre-restore backup before destructive restore. Agent verifies backups before restore. Agent rejects backups containing forbidden paths or leaked secrets. Agent supports restore into a new local_only instance. Agent supports rollback after failed update. Agent disables public exposure when rollback fails. Agent detects known compromise indicators. ``` --- ## 26. Implementation priority ### Phase 1 — Minimum secure Agent ```text local-only API capsule signature verification manifest validation secret generation Docker Compose allowlist network profile enforcement dangerous port blocking Security Gate basic checks audit log start/stop/status ``` ### Phase 2 — Appliance-grade Agent ```text firewall profile automation backup/restore update/rollback public temporary mode expiration unknown container detection suspicious persistence checks Manager UI integration local token rotation ``` ### Phase 3 — Hardened enterprise/demo box ```text rootless Docker evaluation signed Agent updates backup encryption remote health reporting policy export tamper detection hardware appliance image ``` --- ## 27. Final rule The Konnaxion Agent exists to make Konnaxion plug-and-play **without making it unsafe**. The Agent must make the secure path the default path: ```text private by default minimal configuration no dangerous ports no arbitrary Docker control no embedded secrets signed capsules only Security Gate before runtime automatic rollback where possible ``` If a configuration is convenient but unsafe, the Agent must reject it. ================================================================================================ FILE: docs/DOC-06_Konnaxion_Network_Profiles.md AUTHORITY: reference CONTENT_ROLE: knowledge CONTENT_SHA256: 3629ebc4e880a46312236e03c43d61b9bad8cc0accac2393fe4298dffab03df9 CONTENT_BYTES: 48379 ================================================================================================ doc_id: DOC-06 title: Konnaxion Network Profiles project: Konnaxion app_version: v14 param_version: kx-param-2026.04.30 status: draft depends_on: - DOC-00_Konnaxion_Canonical_Variables.md - DOC-04_Konnaxion_Manager_Architecture.md - DOC-05_Konnaxion_Agent_Security_Model.md - DOC-07_Konnaxion_Security_Gate.md - DOC-08_Konnaxion_Runtime_Docker_Compose.md owner: Konnaxion Architecture last_updated: 2026-05-05 default_network_profile: intranet_private default_exposure_mode: private ``` # DOC-06 — Konnaxion Network Profiles ## 1. Purpose This document defines the canonical network profiles used by the **Konnaxion Capsule Manager** and enforced by the **Konnaxion Agent**. The goal is to make Konnaxion deployable as a plug-and-play capsule while keeping network exposure predictable, minimal, and secure. Konnaxion must be **private-by-default**. The user should not manually configure Docker ports, Traefik routers, Redis exposure, PostgreSQL exposure, Django binding, Next.js binding, firewall rules, or reverse proxy labels. The user chooses a network profile. The Manager and Agent apply the correct network policy. --- ## 2. Grounding Konnaxion v14 uses a **Next.js frontend**, **Django + DRF backend**, **PostgreSQL**, **Celery + Redis**, and Docker-oriented deployment infrastructure. The canonical runtime model is defined in `DOC-00_Konnaxion_Canonical_Variables.md` and `DOC-08_Konnaxion_Runtime_Docker_Compose.md`. The canonical production topology includes Traefik as the only HTTP(S) entrypoint, with routing from `/` to `frontend-next`, `/api/` and `/admin/` to `django-api`, and `/media/` to `media-nginx`. The security baseline is: ```text Public users reach only Traefik on 80/443. Internal services remain private on Docker networks. Docker socket is not mounted. Traefik routing uses file-provider dynamic configuration, not Docker socket labels. ``` Public users must not reach ports such as `3000`, `5000`, `5555`, `5432`, `6379`, `8000`, or Docker daemon ports. For public VPS deployments, the selected public runtime hostname must be propagated consistently to: ```text KX_HOST KX_HOST_ALIASES DJANGO_ALLOWED_HOSTS DJANGO_CSRF_TRUSTED_ORIGINS CSRF_TRUSTED_ORIGINS CORS_ALLOWED_ORIGINS NEXT_PUBLIC_API_BASE NEXT_PUBLIC_BACKEND_BASE Traefik Host(...) rules ``` A public domain that resolves to the VPS but returns Traefik’s plain `404 page not found` is a routing failure. It means the Traefik Host rule does not include the public domain. --- ## 3. Canonical Profiles The only valid values for `KX_NETWORK_PROFILE` are: ```text offline local_only intranet_private private_tunnel public_temporary public_vps ``` Default: ```env KX_NETWORK_PROFILE=intranet_private KX_EXPOSURE_MODE=private KX_PUBLIC_MODE_ENABLED=false ``` Public mode is never the default. --- ## 4. Canonical Exposure Modes The only valid values for `KX_EXPOSURE_MODE` are: ```text private lan vpn temporary_tunnel public ``` Profile-to-exposure mapping: ```text offline -> private local_only -> private intranet_private -> lan private_tunnel -> vpn public_temporary -> temporary_tunnel public_vps -> public ``` The Agent must reject invalid profile/exposure combinations. --- ## 5. Profile Summary Matrix | Profile | Variable | Intended use | Public internet | LAN | VPN/Tunnel | Default | | ---------------- | ------------------ | ------------------------ | --------------- | -------- | ---------- | ------- | | Offline | `offline` | Fully isolated demo/test | no | no | no | no | | Local only | `local_only` | Demo on same machine | no | no | no | no | | Intranet private | `intranet_private` | LAN/institution demo | no | yes | no | yes | | Private tunnel | `private_tunnel` | Trusted remote users | no | optional | yes | no | | Public temporary | `public_temporary` | External demo link | limited | optional | tunnel | no | | Public VPS | `public_vps` | Real public deployment | yes | n/a | optional | no | --- ## 6. Shared Runtime Topology All network profiles use the same internal service model. ```text Client ↓ Traefik ├── / -> frontend-next ├── /api/ -> django-api ├── /admin/ -> django-api └── /media/ -> media-nginx Internal only: ├── postgres ├── redis ├── celeryworker ├── celerybeat └── flower ``` Only Traefik is allowed to be an external entrypoint. Direct access to `frontend-next`, `django-api`, `postgres`, `redis`, `celeryworker`, `celerybeat`, `flower`, or Docker daemon is forbidden unless a future document explicitly defines an admin-only maintenance channel. --- ## 7. Global Forbidden Exposure The following ports must never be exposed to the public internet: ```text 3000/tcp Next.js direct access 5000/tcp Django/Gunicorn internal service 5555/tcp Flower or dashboard surface 5432/tcp PostgreSQL 6379/tcp Redis 8000/tcp Django dev/server direct 2375/tcp Docker daemon TCP without TLS 2376/tcp Docker daemon TCP with TLS ``` The following services must always remain internal: ```text postgres redis celeryworker celerybeat flower django-api direct port frontend-next direct port Docker socket ``` The Docker socket must never be mounted into an application container or into Traefik. ```yaml forbidden_mounts: - /var/run/docker.sock - /run/docker.sock ``` Traefik must use a file-provider dynamic configuration generated by the Agent. --- ## 8. Canonical Runtime Networks The Agent-generated Compose runtime must define three networks: ```text kx-public external entrypoint network for Traefik only kx-private internal HTTP application network kx-data internal data network ``` Required network behavior: ```text traefik -> kx-public, kx-private frontend-next -> kx-private django-api -> kx-private, kx-data media-nginx -> kx-private postgres -> kx-data redis -> kx-data celeryworker -> kx-private, kx-data celerybeat -> kx-private, kx-data flower -> kx-private, kx-data when enabled ``` `kx-private` and `kx-data` must be internal Docker networks. --- ## 9. Profile: `offline` ### 9.1 Purpose `offline` is for isolated demos, testing, forensic inspection, or training where Konnaxion should not be reachable from any other device. ### 9.2 Exposure ```env KX_NETWORK_PROFILE=offline KX_EXPOSURE_MODE=private KX_PUBLIC_MODE_ENABLED=false KX_HOST=127.0.0.1 KX_HOST_ALIASES= ``` Allowed inbound: ```text none ``` Allowed bind addresses: ```text 127.0.0.1 only ``` Network policy: ```text No LAN exposure No public exposure No tunnel exposure No router port forwarding No external DNS dependency ``` ### 9.3 URL ```text https://localhost ``` Optional fallback: ```text http://localhost ``` ### 9.4 Firewall Policy ```text deny incoming allow outgoing only if required for updates no inbound exception required ``` ### 9.5 Security Gate Requirements Required `PASS` checks: ```text capsule_signature image_checksums manifest_schema secrets_present secrets_not_default postgres_not_public redis_not_public docker_socket_not_mounted no_privileged_containers no_host_network dangerous_ports_blocked ``` --- ## 10. Profile: `local_only` ### 10.1 Purpose `local_only` is for demos on the same machine where Konnaxion is opened from the host browser. This profile is useful for developer machines, trade show laptops, and pre-demo validation. ### 10.2 Exposure ```env KX_NETWORK_PROFILE=local_only KX_EXPOSURE_MODE=private KX_PUBLIC_MODE_ENABLED=false KX_HOST=127.0.0.1 KX_HOST_ALIASES=localhost,konnaxion.localhost ``` Allowed inbound: ```text 127.0.0.1:443 127.0.0.1:80 optional redirect only ``` Forbidden: ```text 0.0.0.0:3000 0.0.0.0:5000 0.0.0.0:5555 0.0.0.0:5432 0.0.0.0:6379 0.0.0.0:8000 ``` ### 10.3 URL Primary: ```text https://localhost ``` Optional named local URL: ```text https://konnaxion.localhost ``` ### 10.4 TLS Strategy Allowed: ```text self-signed local certificate locally trusted development certificate HTTP fallback for controlled local-only demo ``` Let’s Encrypt must not be used for `.local` or other non-public hostnames. ### 10.5 Manager UI Label ```text Local only Accessible only from this computer. Recommended for testing and private demos. ``` --- ## 11. Profile: `intranet_private` ### 11.1 Purpose `intranet_private` is the default profile. It is used when a Konnaxion Box is plugged into a trusted private LAN such as: ```text school network community organization network office LAN demo room LAN local lab network ``` ### 11.2 Exposure ```env KX_NETWORK_PROFILE=intranet_private KX_EXPOSURE_MODE=lan KX_PUBLIC_MODE_ENABLED=false KX_HOST= KX_HOST_ALIASES= ``` Allowed inbound: ```text LAN:443/tcp LAN:80/tcp optional redirect only ``` Forbidden inbound: ```text Internet:any LAN:3000 LAN:5000 LAN:5555 LAN:5432 LAN:6379 LAN:8000 Docker daemon ``` ### 11.3 Allowed Source Ranges Allowed private source ranges: ```text 10.0.0.0/8 172.16.0.0/12 192.168.0.0/16 fd00::/8 fe80::/10 ``` The Manager may detect the active LAN subnet and restrict access to that subnet only. Example: ```env KX_ALLOWED_LAN_CIDR=192.168.1.0/24 ``` ### 11.4 URL Preferred: ```text https://konnaxion.local ``` Fallback: ```text https:// ``` Optional organization-specific hostname: ```text https://konnaxion.intranet https://konnaxion.school.lan ``` ### 11.5 TLS Strategy Allowed: ```text self-signed local CA locally trusted intranet certificate organization-provided certificate HTTP only if explicitly accepted for temporary LAN demo ``` Not allowed: ```text Let’s Encrypt for .local public DNS requirement by default ``` ### 11.6 Firewall Policy The Konnaxion Agent must apply: ```text deny incoming by default allow 443/tcp from KX_ALLOWED_LAN_CIDR allow 80/tcp from KX_ALLOWED_LAN_CIDR only if redirect is enabled deny 3000/tcp deny 5000/tcp deny 5555/tcp deny 5432/tcp deny 6379/tcp deny 8000/tcp deny Docker daemon ports ``` ### 11.7 Manager UI Label ```text Intranet private Accessible from this local network only. Recommended default. ``` ### 11.8 Security Gate Requirements Required `PASS` checks: ```text firewall_enabled lan_scope_detected public_ip_not_exposed dangerous_ports_blocked postgres_not_public redis_not_public docker_socket_not_mounted admin_surface_private ``` --- ## 12. Profile: `private_tunnel` ### 12.1 Purpose `private_tunnel` is for remote access by trusted users without opening router ports. Examples: ```text Tailscale WireGuard ZeroTier organization VPN ``` ### 12.2 Exposure ```env KX_NETWORK_PROFILE=private_tunnel KX_EXPOSURE_MODE=vpn KX_PUBLIC_MODE_ENABLED=false KX_HOST= KX_HOST_ALIASES= ``` Allowed inbound: ```text VPN/tunnel interface:443/tcp VPN/tunnel interface:80/tcp optional redirect only ``` Forbidden: ```text public internet direct access router port forwarding public 3000 public 5000 public 5555 public 5432 public 6379 public 8000 ``` ### 12.3 URL Example: ```text https://konnaxion-demo..ts.net ``` Generic: ```text https:// ``` ### 12.4 Required Variables ```env KX_NETWORK_PROFILE=private_tunnel KX_EXPOSURE_MODE=vpn KX_TUNNEL_PROVIDER=tailscale KX_TUNNEL_HOST= KX_PUBLIC_MODE_ENABLED=false KX_HOST= KX_HOST_ALIASES= ``` ### 12.5 Firewall Policy ```text deny incoming by default allow 443/tcp only on tunnel interface allow 80/tcp only on tunnel interface if redirect enabled deny 443/tcp on public interface deny 80/tcp on public interface unless explicitly required deny all dangerous ports on all interfaces ``` ### 12.6 Manager UI Label ```text Private tunnel Accessible only to approved tunnel/VPN users. No router port forwarding required. ``` --- ## 13. Profile: `public_temporary` ### 13.1 Purpose `public_temporary` is for short-lived external demos. It allows a public link without converting the Konnaxion Box into a permanent public server. Examples: ```text client demo investor demo partner walkthrough remote presentation ``` ### 13.2 Exposure ```env KX_NETWORK_PROFILE=public_temporary KX_EXPOSURE_MODE=temporary_tunnel KX_PUBLIC_MODE_ENABLED=true KX_HOST= KX_HOST_ALIASES= ``` Required: ```env KX_PUBLIC_MODE_DURATION_HOURS=<1|2|4|8> KX_PUBLIC_MODE_EXPIRES_AT= ``` The Manager must refuse this profile if `KX_PUBLIC_MODE_EXPIRES_AT` is empty. ### 13.3 Allowed Public Entry Allowed: ```text 443/tcp through managed tunnel ``` Optional: ```text 80/tcp only for provider-managed HTTPS redirect ``` Forbidden: ```text direct router port forwarding by default permanent public exposure public SSH public Postgres public Redis public Flower public Docker public Next.js direct public Django direct ``` ### 13.4 Auth Requirement At least one of the following must be enabled: ```text tunnel provider access policy one-time demo password basic auth at proxy layer email allowlist temporary invite token ``` Default: ```env KX_PUBLIC_TEMPORARY_AUTH_REQUIRED=true ``` ### 13.5 Expiration When the expiration time is reached, the Manager must: ```text close tunnel revoke temporary URL remove temporary auth tokens return KX_PUBLIC_MODE_ENABLED=false return profile to intranet_private or local_only write audit log entry ``` ### 13.6 Manager UI Label ```text Public temporary demo Creates a time-limited public link. Requires authentication. Automatically expires. ``` ### 13.7 Security Gate Requirements Required `PASS` checks: ```text public_mode_expiration_present public_mode_auth_enabled tunnel_provider_configured direct_public_ports_blocked dangerous_ports_blocked admin_surface_private_or_auth_protected postgres_not_public redis_not_public docker_socket_not_mounted ``` Blocking failure if: ```text KX_PUBLIC_MODE_EXPIRES_AT is empty KX_PUBLIC_TEMPORARY_AUTH_REQUIRED=false public 3000 detected public 5000 detected public 5555 detected public 5432 detected public 6379 detected public Docker daemon detected ``` --- ## 14. Profile: `public_vps` ### 14.1 Purpose `public_vps` is for a real public production deployment. This profile is not the default and should not be used for demo boxes unless the host has been hardened as a public server. ### 14.2 Exposure ```env KX_NETWORK_PROFILE=public_vps KX_EXPOSURE_MODE=public KX_PUBLIC_MODE_ENABLED=true KX_PUBLIC_MODE_EXPIRES_AT= KX_HOST= KX_HOST_ALIASES= ``` Allowed public inbound: ```text 80/tcp 443/tcp ``` SSH: ```text 22/tcp only from admin IP or VPN ``` Forbidden public inbound: ```text 3000/tcp 5000/tcp 5555/tcp 5432/tcp 6379/tcp 8000/tcp Docker daemon TCP ports ``` The production baseline is: ```text Expose only 22, 80, and 443. Restrict SSH to administrator IP or VPN where possible. Do not expose Next.js direct. Do not expose Django/Gunicorn direct. Do not expose Flower/dashboard. Do not expose Postgres. Do not expose Redis. Do not expose Docker daemon. ``` ### 14.3 Host Requirement `public_vps` requires a non-empty public host. The host must not be: ```text 127.0.0.1 localhost konnaxion.local ``` Allowed examples: ```text konnaxion.com www.konnaxion.com demo.konnaxion.com 138.197.174.76.sslip.io ``` `sslip.io` or equivalent public wildcard DNS may be used for development or demo VPS deployments when no production domain is available. The canonical public runtime host is `KX_HOST`. Optional additional public names must be stored in `KX_HOST_ALIASES`. Example: ```env KX_HOST=konnxion.com KX_HOST_ALIASES=www.konnxion.com,138.197.174.76.sslip.io ``` The Agent must normalize all host values by removing schemes, paths, userinfo, trailing slashes, empty values, and duplicates. Valid: ```text konnxion.com www.konnxion.com 138.197.174.76.sslip.io ``` Invalid: ```text https://konnxion.com/api/ user:pass@konnxion.com 127.0.0.1 localhost ``` For `public_vps`, `KX_PUBLIC_MODE_EXPIRES_AT` must not be required. Expiration is required only for `public_temporary`. ### 14.4 URL Example: ```text https://konnxion.com https://www.konnxion.com https://138.197.174.76.sslip.io ``` The canonical public URL shown by the Manager should use `KX_HOST`. Aliases may be shown as secondary diagnostic URLs. ### 14.5 TLS Strategy Use public certificate automation only for valid public DNS names. Allowed: ```text Let’s Encrypt for valid public domain provider-managed certificate organization-managed certificate temporary self-signed certificate for controlled VPS demo only ``` Forbidden: ```text Let’s Encrypt for .local self-signed certificate for public production ``` When multiple public hostnames are configured, certificate automation must either cover all names or clearly indicate which names are covered. ### 14.6 Firewall Policy Cloud firewall: ```text allow 80/tcp from anywhere allow 443/tcp from anywhere allow 22/tcp only from admin IP or VPN deny everything else ``` Host firewall: ```text deny incoming by default allow 80/tcp allow 443/tcp allow 22/tcp only from admin IP or VPN deny dangerous ports ``` ### 14.7 Manager UI Label ```text Public VPS Permanent public web deployment. Requires hardened server and restricted SSH. ``` ### 14.8 Droplet/VPS Agent Transport For a public VPS or Droplet target, the Konnaxion Agent should remain private on the VPS loopback interface: ```text 127.0.0.1:8765 ``` The Manager must not require a local tunnel such as: ```text 127.0.0.1: -> 127.0.0.1:8765 ``` Canonical Manager-to-Agent transport for private VPS Agent: ```text Manager on operator machine -> SSH -> curl http://127.0.0.1:8765/v1/... on the VPS -> Konnaxion Agent ``` The Manager must use SSH-local Agent calls when: ```text target_mode=droplet remote_agent_url is empty remote_agent_url is localhost/127.0.0.1 and represents a local tunnel workaround ``` Direct HTTP to `remote_agent_url` is allowed only when the operator explicitly configures a real non-loopback Agent endpoint. The Agent API must remain private unless a future document defines a hardened authenticated remote Agent endpoint. ### 14.9 Durable Custom Domain Rule For `public_vps`, the Manager and Agent must keep two concepts separate: ```text Public runtime host: KX_HOST / host / domain / public_host / droplet_domain Example: konnxion.com SSH target: droplet_host / target_host Example: 138.197.174.76 ``` The public runtime host is what Traefik, Django, and frontend URLs must use. The SSH target is only for SSH/SCP/SSH-local curl transport. The Agent must not silently replace a selected custom domain with the Droplet IP or with an old `sslip.io` fallback. The Manager must send `host` to the Agent during both: ```text /instances/create /network/set-profile ``` `/network/set-profile` must persist the host change by regenerating: ```text /opt/konnaxion/instances//env/kx.env /opt/konnaxion/instances//env/django.env /opt/konnaxion/instances//env/frontend.env /opt/konnaxion/instances//state/docker-compose.runtime.yml /opt/konnaxion/instances//state/traefik-dynamic.yml ``` `/network/set-profile` must not be validation-only. It must preserve generated secrets while rewriting host-derived values. Preserve: ```text DJANGO_SECRET_KEY POSTGRES_PASSWORD DATABASE_URL password component other generated secrets ``` Rewrite: ```text KX_HOST KX_HOST_ALIASES KX_NETWORK_PROFILE KX_EXPOSURE_MODE KX_PUBLIC_MODE_ENABLED KX_PUBLIC_MODE_EXPIRES_AT DJANGO_ALLOWED_HOSTS DJANGO_CSRF_TRUSTED_ORIGINS CSRF_TRUSTED_ORIGINS CORS_ALLOWED_ORIGINS NEXT_PUBLIC_API_BASE NEXT_PUBLIC_BACKEND_BASE Traefik Host(...) rules ``` --- ## 15. Traefik Routing Contract All profiles must use this canonical route map: ```text / -> frontend-next /api/ -> django-api /admin/ -> django-api /media/ -> media-nginx ``` No profile may expose: ```text http://:3000 http://:5000 http://:5555 http://:5432 http://:6379 http://:8000 ``` The frontend may be reachable internally at: ```text frontend-next:3000 kx--frontend-next:3000 ``` The Django API may be reachable internally at: ```text django-api:5000 kx--django-api:5000 ``` PostgreSQL and Redis must be reachable only through Docker private networks. The Agent must render every public router using the same host rule built from: ```text KX_HOST KX_HOST_ALIASES ``` Example for a custom domain with aliases: ```text (Host(`konnxion.com`) || Host(`www.konnxion.com`) || Host(`138.197.174.76.sslip.io`)) && PathPrefix(`/api/`) ``` For public VPS, a Traefik plain response of: ```text 404 page not found ``` for `https:///` or `https:///api/` is a blocking routing failure. It means Traefik did not match the public Host header. --- ## 16. Traefik File-Provider Contract The Agent-generated runtime must use Traefik file-provider dynamic configuration. Required Traefik static command: ```yaml command: - --providers.file.filename=/etc/traefik/dynamic/traefik-dynamic.yml - --providers.file.watch=true - --entrypoints.web.address=:80 - --entrypoints.websecure.address=:443 - --entrypoints.web.http.redirections.entrypoint.to=websecure - --entrypoints.web.http.redirections.entrypoint.scheme=https - --api.dashboard=false ``` Required mount: ```yaml volumes: - /opt/konnaxion/instances//state/traefik-dynamic.yml:/etc/traefik/dynamic/traefik-dynamic.yml:ro ``` Forbidden: ```text Docker socket mount Traefik Docker provider as required runtime dependency Public routing implemented only through Docker labels ``` Docker labels may exist for inspection or tests, but they must not be required for production routing. Canonical dynamic config shape: ```yaml http: routers: kx-frontend: rule: "(Host(``) || Host(``)) && PathPrefix(`/`)" entryPoints: - websecure tls: {} service: frontend-next priority: 10 kx-api: rule: "(Host(``) || Host(``)) && PathPrefix(`/api/`)" entryPoints: - websecure tls: {} service: django-api priority: 100 kx-admin: rule: "(Host(``) || Host(``)) && PathPrefix(`/admin/`)" entryPoints: - websecure tls: {} service: django-api priority: 100 kx-media: rule: "(Host(``) || Host(``)) && PathPrefix(`/media/`)" entryPoints: - websecure tls: {} service: media-nginx priority: 100 services: frontend-next: loadBalancer: servers: - url: "http://frontend-next:3000" django-api: loadBalancer: servers: - url: "http://django-api:5000" media-nginx: loadBalancer: servers: - url: "http://media-nginx:80" ``` The example above is schematic. The Agent must expand aliases into valid Traefik syntax. If there is only one host, render: ```text Host(``) ``` If there are multiple hosts, render: ```text (Host(``) || Host(``) || Host(``)) ``` All routers must use the same host rule. --- ## 17. Hostname Policy ### 17.1 Local Hostnames Allowed for `local_only`: ```text localhost 127.0.0.1 konnaxion.localhost ``` ### 17.2 Intranet Hostnames Allowed for `intranet_private`: ```text konnaxion.local konnaxion.lan custom organization LAN hostname LAN IP fallback ``` ### 17.3 Tunnel Hostnames Allowed for `private_tunnel`: ```text provider-generated private hostname tailnet hostname organization VPN DNS name ``` ### 17.4 Public Hostnames Allowed for `public_temporary`: ```text temporary tunnel hostname controlled demo subdomain ``` Allowed for `public_vps`: ```text valid public DNS hostname public wildcard DNS development hostname such as .sslip.io ``` Examples: ```text konnaxion.com www.konnaxion.com demo.konnaxion.com 138.197.174.76.sslip.io ``` ### 17.5 Alias Policy `KX_HOST_ALIASES` may contain additional public names that should route to the same instance. Examples: ```text www.konnaxion.com 138.197.174.76.sslip.io demo.konnaxion.com ``` Aliases must not include: ```text empty values duplicate values URL schemes paths userinfo localhost values for public_vps 127.0.0.1 for public_vps ``` The Agent must deduplicate aliases and must not include `KX_HOST` again in `KX_HOST_ALIASES`. --- ## 18. Profile Payload Contract ### 18.1 Manager-to-Agent Payload The Manager must normalize all UI/public-host fields into the Agent field named: ```text host ``` Accepted Manager-side source fields: ```text domain droplet_domain public_host public_url url host kx_host KX_HOST droplet_host target_host ``` Normalization order: ```text host = domain or droplet_domain or public_host or public_url or url or host or kx_host or KX_HOST or droplet_host or target_host ``` The Manager must prefer operator-facing public domain fields before the Droplet IP. The Manager must keep these meanings distinct: ```text host / public_host / domain / droplet_domain: public runtime host, e.g. konnxion.com droplet_host / target_host: SSH target, e.g. 138.197.174.76 ``` The Manager must not send unsupported fields to the Agent profile endpoint. Do not send: ```text domain public_host droplet_domain public_url url ``` unless the Agent schema explicitly supports them. For `public_vps`, the Manager must send: ```json { "instance_id": "demo-001", "network_profile": "public_vps", "exposure_mode": "public", "host": "konnxion.com", "host_aliases": [ "www.konnxion.com", "138.197.174.76.sslip.io" ], "public_mode_enabled": true, "public_mode_expires_at": null } ``` If the Agent schema does not yet support `host_aliases`, the Manager must still send `host` and the Agent may derive aliases from known Droplet metadata. ### 18.2 Agent Schema The Agent network profile request must accept: ```text instance_id network_profile exposure_mode host host_aliases public_mode_enabled public_mode_expires_at ``` `host_aliases` may be optional. The Agent must reject unknown extra fields unless the API contract is intentionally extended. ### 18.3 Public VPS Validation For `public_vps`, the Agent must reject: ```text empty host localhost 127.0.0.1 .local hostnames ``` unless explicitly running a local-only test fixture. For `public_vps`, the Agent must not require `public_mode_expires_at`. Expiration is required only for: ```text network_profile=public_temporary exposure_mode=temporary_tunnel ``` ### 18.4 Instance Creation Payload For `public_vps`, the Manager must send `host` during instance creation, not only during a later network-profile update. Required `/instances/create` behavior: ```json { "instance_id": "demo-001", "capsule_id": "konnaxion-v14-demo-2026.04.30", "network_profile": "public_vps", "exposure_mode": "public", "host": "konnxion.com", "generate_secrets": true } ``` This prevents first-rendered env and Traefik files from freezing an old fallback host. --- ## 19. Environment Output Contract When a profile is applied, the Agent must generate environment values for backend, frontend, and runtime metadata. ### 19.1 Runtime ```env KX_NETWORK_PROFILE= KX_EXPOSURE_MODE= KX_PUBLIC_MODE_ENABLED= KX_PUBLIC_MODE_EXPIRES_AT= KX_HOST= KX_HOST_ALIASES= KX_ALLOWED_LAN_CIDR= KX_TUNNEL_PROVIDER= KX_TUNNEL_HOST= ``` For `public_vps`: ```env KX_NETWORK_PROFILE=public_vps KX_EXPOSURE_MODE=public KX_PUBLIC_MODE_ENABLED=true KX_PUBLIC_MODE_EXPIRES_AT= KX_HOST=konnxion.com KX_HOST_ALIASES=www.konnxion.com,138.197.174.76.sslip.io ``` `KX_HOST` must not be `127.0.0.1` for `public_vps`. ### 19.2 Django ```env DJANGO_ALLOWED_HOSTS= DJANGO_CSRF_TRUSTED_ORIGINS= CSRF_TRUSTED_ORIGINS= CORS_ALLOWED_ORIGINS= ``` For `public_vps`, `DJANGO_ALLOWED_HOSTS` must include: ```text 127.0.0.1 localhost django-api kx--django-api ``` For `public_vps`, CSRF/CORS trusted origins must include: ```text https:// http:// https:// http:// ``` Example: ```env DJANGO_ALLOWED_HOSTS=127.0.0.1,localhost,konnxion.com,www.konnxion.com,138.197.174.76.sslip.io,django-api,kx-demo-001-django-api DJANGO_CSRF_TRUSTED_ORIGINS=https://konnxion.com,http://konnxion.com,https://www.konnxion.com,http://www.konnxion.com,https://138.197.174.76.sslip.io,http://138.197.174.76.sslip.io CSRF_TRUSTED_ORIGINS=https://konnxion.com,http://konnxion.com,https://www.konnxion.com,http://www.konnxion.com,https://138.197.174.76.sslip.io,http://138.197.174.76.sslip.io CORS_ALLOWED_ORIGINS=https://konnxion.com,http://konnxion.com,https://www.konnxion.com,http://www.konnxion.com,https://138.197.174.76.sslip.io,http://138.197.174.76.sslip.io ``` ### 19.3 Frontend ```env NEXT_PUBLIC_API_BASE=https:///api NEXT_PUBLIC_BACKEND_BASE=https:// NEXT_TELEMETRY_DISABLED=1 ``` The frontend must use canonical `KX_HOST`, not an arbitrary alias. Because Next.js may bake public environment values at build time, a profile change that modifies public frontend URLs requires one of: ```text frontend image rebuild runtime configuration injection strategy frontend environment file regenerated before build/export ``` For the Konnaxion capsule runtime, the accepted durable behavior is: ```text Agent regenerates frontend.env before runtime start. Frontend runtime reads the generated runtime configuration. ``` ### 19.4 Secret Preservation When the profile host changes, the Agent must update host-derived values without rotating secrets. Preserve existing values for: ```text DJANGO_SECRET_KEY POSTGRES_PASSWORD DATABASE_URL password component other generated secrets ``` Regenerate or update values for: ```text KX_HOST KX_HOST_ALIASES DJANGO_ALLOWED_HOSTS DJANGO_CSRF_TRUSTED_ORIGINS CSRF_TRUSTED_ORIGINS CORS_ALLOWED_ORIGINS NEXT_PUBLIC_API_BASE NEXT_PUBLIC_BACKEND_BASE Traefik Host() rules ``` --- ## 20. Runtime Healthcheck Contract Healthchecks must not rely on tools missing from stock runtime images. ### 20.1 Django Django healthcheck must not require `wget`. Preferred check: ```yaml healthcheck: test: - CMD-SHELL - python -c "import socket; sock=socket.create_connection(('127.0.0.1',5000),5); sock.close()" interval: 30s timeout: 5s retries: 10 ``` The Django API route `/api/health/` may exist in future, but Compose health must not depend on it unless the image reliably contains a client tool and the route is guaranteed. ### 20.2 Media Nginx For stock `nginx:stable`, healthcheck should use a command available in the image. Allowed: ```yaml healthcheck: test: - CMD-SHELL - nginx -t >/dev/null 2>&1 interval: 30s timeout: 5s retries: 5 ``` Do not use `wget` unless the selected media image includes `wget`. ### 20.3 Frontend Frontend readiness may be validated by container status and Traefik route test. Allowed internal check: ```text node-based HTTP probe ``` Forbidden: ```text runtime Corepack download runtime pnpm download network dependency to start Next.js ``` ### 20.4 Public Host Route Checks For `public_vps`, external checks must include the canonical host and configured aliases. Canonical host checks: ```text https:/// https:///api/ https:///admin/ https:///media/ ``` Alias checks when aliases exist: ```text https:/// https:///api/ ``` A Django application `404` from `/api/` may be acceptable if the path does not exist. A Traefik plain `404 page not found` is not acceptable for `public_vps`. --- ## 21. Frontend Runtime Image Contract The production frontend image must not require network access to start. The runtime layer must include: ```text package.json node_modules .next public next.config.* env.mjs ``` The runtime command must not be: ```text pnpm start corepack pnpm start ``` Canonical runtime command: ```text node node_modules/next/dist/bin/next start -H 0.0.0.0 -p 3000 ``` Required environment: ```env NODE_ENV=production PORT=3000 HOSTNAME=0.0.0.0 NEXT_TELEMETRY_DISABLED=1 ``` --- ## 22. Profile Switching Rules Allowed transitions: ```text offline -> local_only offline -> intranet_private local_only -> intranet_private intranet_private -> private_tunnel intranet_private -> public_temporary private_tunnel -> intranet_private public_temporary -> intranet_private public_vps -> public_vps ``` Restricted transitions: ```text any -> public_vps ``` `public_vps` requires explicit operator confirmation and a successful hardening check. Automatic transition: ```text public_temporary -> intranet_private ``` This happens when `KX_PUBLIC_MODE_EXPIRES_AT` is reached. When switching host or profile, the Agent must regenerate runtime files. The change is not complete until the following are consistent: ```text kx.env django.env frontend.env docker-compose.runtime.yml traefik-dynamic.yml Security Gate result ``` --- ## 23. Backup, Restore and Rollback Network Behavior Backup, restore and rollback workflows are defined in `DOC-09_Konnaxion_Backup_Restore_Rollback.md`, but network behavior is governed by this document. The network profile selected during restore must never weaken the Security Gate. Default restore target: ```env KX_RESTORE_DEFAULT_NETWORK_PROFILE=local_only ``` The safest restore target is `local_only` because it allows validation before LAN, tunnel, or public exposure. ### 23.1 Restore Behavior by Profile | Target profile | Restore behavior | | ------------------ | ---------------------------------------------------------------------------------------------------------- | | `offline` | Allowed only for isolated validation. No network exposure. | | `local_only` | Default and safest restore target. Used for restore tests and high-risk recovery. | | `intranet_private` | Allowed after Security Gate `PASS`; exposes Traefik to LAN only. | | `private_tunnel` | Allowed only after tunnel configuration is validated. No router port forwarding. | | `public_temporary` | Must not auto-enable public access after restore. Requires explicit operator action, auth, and expiration. | | `public_vps` | Requires explicit approval, hardened firewall, SSH hardening, backups enabled, and Security Gate `PASS`. | ### 23.2 Restore Into New Instance A restore into a new instance must default to: ```env KX_NETWORK_PROFILE=local_only KX_EXPOSURE_MODE=private KX_PUBLIC_MODE_ENABLED=false ``` The operator may switch the restored instance to `intranet_private`, `private_tunnel`, `public_temporary`, or `public_vps` only after: ```text backup verification passed restore preflight passed restore postflight passed Security Gate passed healthchecks passed dangerous ports remain blocked ``` ### 23.3 Restore Into Existing Instance A restore into an existing instance must preserve the current network profile only if the profile is still valid and safe. If the current profile is unsafe, unknown, expired, or incompatible, the Agent must fall back to: ```env KX_NETWORK_PROFILE=local_only KX_EXPOSURE_MODE=private KX_PUBLIC_MODE_ENABLED=false ``` ### 23.4 Public Temporary Restore Rule A restored instance must never automatically reopen a previous `public_temporary` URL. If the backup manifest contains: ```env KX_NETWORK_PROFILE=public_temporary KX_PUBLIC_MODE_ENABLED=true ``` the restored instance must start as: ```env KX_NETWORK_PROFILE=local_only KX_EXPOSURE_MODE=private KX_PUBLIC_MODE_ENABLED=false KX_PUBLIC_MODE_EXPIRES_AT= ``` The operator may create a new temporary public URL only through the Manager UI or canonical CLI, with authentication and expiration. ### 23.5 Public VPS Restore Rule A restored `public_vps` instance must not become public until the following checks pass: ```text firewall_enabled dangerous_ports_blocked postgres_not_public redis_not_public docker_socket_not_mounted admin_surface_private ssh_restricted root_ssh_disabled password_ssh_disabled backups_enabled public_host_present public_host_not_localhost traefik_host_rules_contain_kx_host ``` If any check fails, the instance must remain in `local_only` or `intranet_private`. ### 23.6 Rollback Network Rule Rollback must not increase exposure. Allowed automatic rollback transitions: ```text public_temporary -> intranet_private private_tunnel -> intranet_private public_vps -> public_vps only if Security Gate PASS any profile -> local_only ``` Forbidden automatic rollback transitions: ```text local_only -> public_temporary intranet_private -> public_temporary private_tunnel -> public_temporary any profile -> public_vps ``` ### 23.7 Backup Metadata for Network Profiles Every backup manifest must record the active network profile as metadata: ```yaml network: kx_network_profile: intranet_private kx_exposure_mode: private kx_public_mode_enabled: false kx_public_mode_expires_at: null kx_host: konnaxion.local kx_host_aliases: [] ``` This metadata is used to propose a restore profile, but it must not override current Security Gate policy. ### 23.8 Manager UX Requirement During restore, the Manager must show: ```text Backup source profile: Restore target profile: Public exposure after restore: disabled by default ``` For `public_temporary` and `public_vps`, the Manager must require explicit confirmation before any public exposure is enabled. --- ## 24. Security Gate Integration Before applying any profile, the Manager must call: ```bash kx security check --profile ``` The profile may be applied only if all blocking checks return `PASS`. Canonical blocking checks: ```text capsule_signature image_checksums manifest_schema secrets_present secrets_not_default firewall_enabled dangerous_ports_blocked postgres_not_public redis_not_public docker_socket_not_mounted no_privileged_containers no_host_network allowed_images_only admin_surface_private runtime_env_host_matches_profile traefik_dynamic_host_matches_profile frontend_public_env_matches_profile ``` Additional checks for `public_temporary`: ```text public_mode_expiration_present public_mode_auth_enabled tunnel_provider_configured ``` Additional checks for `public_vps`: ```text public_host_present public_host_not_localhost public_host_not_loopback ssh_restricted root_ssh_disabled password_ssh_disabled cloud_firewall_present_or_acknowledged backups_enabled django_allowed_hosts_contains_kx_host django_allowed_hosts_contains_kx_host_aliases frontend_public_urls_match_kx_host traefik_host_rules_contain_kx_host traefik_host_rules_contain_kx_host_aliases ``` Blocking failure if `public_vps` generates: ```text KX_HOST=127.0.0.1 KX_HOST=localhost DJANGO_ALLOWED_HOSTS without public host NEXT_PUBLIC_API_BASE=https://127.0.0.1/api Traefik Host(`127.0.0.1`) Traefik dynamic config missing KX_HOST Docker socket mount public direct 3000/5000/5432/6379/5555/8000 ``` Blocking failure if a custom domain is selected but only the fallback `sslip.io` hostname appears in Traefik Host rules. --- ## 25. Manager UX Contract The user must not see raw Docker or firewall details during normal operation. The user sees: ```text Mode réseau: - Local seulement - Intranet privé - Tunnel privé - Public temporaire - Public VPS ``` The user sees the result: ```text Current mode: Intranet private Access URL: https://konnaxion.local Internet exposure: Disabled Security status: OK ``` Advanced details may be available under: ```text Security details Network diagnostics Logs ``` For `public_vps`, the Manager must clearly show: ```text Public host: Public URL: https:// Public aliases: Agent transport: SSH-local private Agent Published ports: 80/443 only SSH: operator-managed ``` The Manager must not confuse the public runtime host with the SSH target. Example: ```text Public host: konnxion.com Public aliases: www.konnxion.com, 138.197.174.76.sslip.io SSH target: 138.197.174.76 ``` --- ## 26. Agent Implementation Contract The Konnaxion Agent is responsible for applying profile rules. Allowed actions: ```text create Docker networks start/stop allowed services bind Traefik to approved interfaces generate Traefik file-provider dynamic config generate profile-specific environment files configure tunnel provider close expired tunnel run Security Gate checks write audit logs ``` Forbidden actions: ```text run arbitrary shell commands from capsule manifest start unknown containers pull unsigned images mount Docker socket into containers enable privileged containers bind forbidden ports open public router ports automatically disable firewall silently replace public_vps host with 127.0.0.1 silently replace selected custom domain with Droplet IP silently keep stale Traefik Host rules after network profile change ``` When applying a profile, the Agent must persist runtime changes. Required persistent outputs: ```text env/kx.env env/django.env env/frontend.env state/docker-compose.runtime.yml state/traefik-dynamic.yml ``` A successful `network.set_profile` action must return enough metadata to diagnose what changed: ```text instance_id network_profile exposure_mode host host_aliases public_mode_enabled public_mode_expires_at env files written compose file path traefik dynamic file path ``` --- ## 27. Manager Implementation Contract For Droplet/VPS deployments, the Manager must: ```text keep remote Agent private on 127.0.0.1:8765 use SSH-local curl for Agent API calls copy capsule artifacts over SSH/SCP normalize domain/public_host/droplet_host to Agent host not require a temporary local tunnel not call http://127.0.0.1:/v1 as the permanent transport ``` The following Agent calls must use the same Droplet transport: ```text health agent info capsule import instance create/update network set-profile security check instance start logs/status ``` For Droplet/VPS deployments, the Manager must keep these fields distinct: ```text domain / public_host / droplet_domain / host: public runtime host droplet_host / target_host: SSH/SCP target ``` The Manager must send `host` to: ```text /instances/create /network/set-profile ``` The Manager should send or derive aliases for: ```text www. .sslip.io ``` when these are known and valid. --- ## 28. Audit Log Requirements Every profile change must create an audit event. Canonical event fields: ```yaml event_type: network_profile_changed instance_id: old_profile: new_profile: host: host_aliases: - - exposure_mode: public_mode_enabled: public_mode_expires_at: actor: timestamp: security_gate_result: runtime_files_regenerated: ``` Public temporary expiration must create: ```yaml event_type: public_temporary_expired instance_id: previous_profile: public_temporary new_profile: intranet_private timestamp: ``` Public VPS host changes must create: ```yaml event_type: public_vps_host_changed instance_id: old_host: new_host: old_aliases: - new_aliases: - timestamp: runtime_files_regenerated: true ``` --- ## 29. Acceptance Tests ### 29.1 `local_only` Expected: ```text curl -k https://localhost/ returns 200 or redirect LAN device cannot reach Konnaxion public internet cannot reach Konnaxion ports 3000/5000/5432/6379/5555 are not externally reachable ``` ### 29.2 `intranet_private` Expected: ```text LAN device can reach https://konnaxion.local or https:// public internet cannot reach Konnaxion router has no required port forwarding Postgres is not reachable from LAN Redis is not reachable from LAN Flower is not reachable from LAN unless explicitly protected and enabled ``` ### 29.3 `private_tunnel` Expected: ```text approved tunnel user can reach Konnaxion non-approved user cannot reach Konnaxion no public router port is open dangerous ports are blocked ``` ### 29.4 `public_temporary` Expected: ```text public demo URL works authentication is required expiration is set after expiration URL no longer works profile returns to intranet_private or local_only dangerous ports remain blocked ``` ### 29.5 `public_vps` Expected: ```text https://public-host/ returns 200 or redirect https://public-host/api/ reaches Django, even if the exact path returns application 404 https://public-host/admin/ reaches Django admin https://public-host/media/ reaches media service or controlled 404 ports 3000/5000/5555/5432/6379/8000 are not public SSH is key-only and restricted where possible Traefik listens on 80/443 Traefik dynamic config contains Host(``) Traefik dynamic config contains Host(``) when aliases are configured Django ALLOWED_HOSTS includes Django ALLOWED_HOSTS includes aliases when aliases are configured frontend public API base uses https:///api Agent remains private on 127.0.0.1:8765 ``` Infrastructure success criteria: ```text frontend-next container is up django-api container is healthy postgres container is healthy redis container is healthy celeryworker is running celerybeat is running traefik is running ``` Host-rule diagnostic checks: ```bash curl -k -i -H 'Host: ' https://127.0.0.1/ curl -k -i -H 'Host: ' https://127.0.0.1/api/ curl -k -i -H 'Host: ' https://127.0.0.1/ curl -k -i -H 'Host: ' https://127.0.0.1/api/ ``` Local DNS bypass checks: ```bash curl -k -i --resolve :443: https:/// curl -k -i --resolve :443: https:///api/ ``` Expected failure classification: ```text curl: could not resolve host -> DNS problem Traefik plain "404 page not found" -> Traefik Host rule problem Django/Uvicorn 404 -> application route exists through proxy; infrastructure routing is working Next.js HTML response -> frontend route is working ``` --- ## 30. Non-Goals This document does not define: ```text Docker Compose service implementation Capsule file format Agent privilege model Backup/restore archive format Backup retention policy Database restore procedure GUI screen design beyond network-profile requirements Cloud provider provisioning Full threat model ``` Those are defined in separate documents. --- ## 31. Final Rule Konnaxion networking must be: ```text private by default deny by default Traefik-only at the edge Traefik file-provider routing, no Docker socket temporary public access only with expiration no public database no public Redis no public Docker no public Next.js direct port no public Django direct port public_vps must use a real public host public_vps must not generate localhost-only runtime env public_vps must propagate KX_HOST to Traefik, Django, and frontend env public_vps must propagate KX_HOST_ALIASES to Traefik and Django when configured network.set_profile must regenerate runtime files and must not be validation-only Manager must preserve the distinction between public runtime host and SSH target ``` If a profile requires exposing an internal service directly, the profile is invalid. ================================================================================================ FILE: docs/DOC-07_Konnaxion_Security_Gate.md AUTHORITY: reference CONTENT_ROLE: knowledge CONTENT_SHA256: d751f2c2947a8af18ef36125e3b1cc539ab3a182ed4dfd595895c6eb3e5c975a CONTENT_BYTES: 19071 ================================================================================================ --- doc_id: DOC-07 title: Konnaxion Security Gate project: Konnaxion app_version: v14 param_version: kx-param-2026.04.30 status: draft depends_on: - DOC-00_Konnaxion_Canonical_Variables.md - DOC-03_Konnaxion_Capsule_Format.md - DOC-04_Konnaxion_Manager_Architecture.md - DOC-05_Konnaxion_Agent_Security_Model.md - DOC-06_Konnaxion_Network_Profiles.md --- # DOC-07 — Konnaxion Security Gate ## 1. Purpose The **Konnaxion Security Gate** is the mandatory safety checkpoint executed by the **Konnaxion Capsule Manager** and **Konnaxion Agent** before a **Konnaxion Instance** can start, update, expose itself on a network, import a capsule, or enable a temporary public tunnel. The Security Gate exists to make unsafe deployment states difficult or impossible. It validates: ```text Capsule integrity Manifest validity Image integrity Runtime policy Secrets policy Network exposure Firewall state Container isolation Backup readiness Update/rollback safety ``` The Security Gate is **blocking by design**. If a critical rule fails, the instance must not start. --- ## 2. Design Principle ```text Default security posture: private-by-default deny-by-default signed-capsules-only dangerous-ports-blocked no-secrets-in-capsule no-public-internals ``` The manager must never ask the user to manually configure Docker, ports, firewall, Traefik, Redis, Postgres, or secrets during normal plug-and-play usage. The user chooses a safe network profile. The Security Gate enforces the rest. --- ## 3. Scope The Security Gate applies to these operations: | Operation | Gate Required | |---|---:| | Import `.kxcap` capsule | yes | | Create new `Konnaxion Instance` | yes | | Start instance | yes | | Change `KX_NETWORK_PROFILE` | yes | | Enable `KX_PUBLIC_MODE_ENABLED=true` | yes | | Update instance to new capsule | yes | | Restore backup | yes | | Run migrations | yes | | Expose tunnel | yes | | Switch to `public_vps` profile | yes | The Security Gate is not optional. --- ## 4. Canonical Status Values Each check returns exactly one status. | Status | Meaning | Blocks start? | |---|---|---:| | `PASS` | Check passed | no | | `WARN` | Risk detected but not fatal for current profile | no | | `FAIL_BLOCKING` | Critical rule failed | yes | | `SKIPPED` | Not applicable for current profile | no | | `UNKNOWN` | Could not verify state | yes, unless explicitly allowlisted | Default rule: ```text UNKNOWN = FAIL_BLOCKING ``` Exception: a check may return `UNKNOWN` as non-blocking only if the manifest explicitly marks it as optional for the current profile. --- ## 5. Security Gate Execution Points ### 5.1 Import-time gate Executed before accepting a `.kxcap`. Checks: ```text capsule_signature capsule_checksums manifest_schema manifest_version allowed_services_only allowed_images_only no_embedded_runtime_secrets ``` ### 5.2 Install-time gate Executed before creating an instance. Checks: ```text host_requirements required_directories instance_id_valid secrets_generation_policy volume_policy backup_policy ``` ### 5.3 Start-time gate Executed before launching containers. Checks: ```text secrets_present secrets_not_default docker_available container_policy network_policy firewall_policy dangerous_ports_blocked ``` ### 5.4 Exposure-change gate Executed before switching network profile or enabling public access. Checks: ```text network_profile_valid exposure_mode_valid public_mode_expiry_required public_mode_auth_required allowed_public_ports dangerous_ports_blocked admin_surface_private ``` ### 5.5 Update-time gate Executed before applying a new capsule. Checks: ```text backup_before_update new_capsule_signature new_capsule_checksums migration_plan_present rollback_target_present healthcheck_plan_present ``` --- ## 6. Mandatory Check List These are the canonical Security Gate checks. ```text capsule_signature capsule_checksums manifest_schema manifest_version allowed_services_only allowed_images_only no_embedded_runtime_secrets host_requirements required_directories instance_id_valid docker_available agent_permission_model filesystem_permissions secrets_present secrets_not_default secrets_generated_locally secrets_file_permissions no_secrets_in_logs container_policy no_privileged_containers no_host_network docker_socket_not_mounted read_only_root_where_possible restricted_capabilities no_unknown_containers network_profile_valid exposure_mode_valid allowed_public_ports dangerous_ports_blocked postgres_not_public redis_not_public frontend_direct_not_public django_direct_not_public flower_not_public admin_surface_private firewall_enabled firewall_deny_default firewall_profile_matches_network_profile backup_configured backup_before_update rollback_target_present healthchecks_defined healthchecks_passing ``` --- ## 7. Blocking Rules The following conditions always produce `FAIL_BLOCKING`. ### 7.1 Capsule Integrity ```text Invalid capsule signature Missing signature Checksum mismatch Unknown manifest schema Unsupported capsule version Unknown image not declared in manifest Image digest mismatch ``` ### 7.2 Secrets ```text DJANGO_SECRET_KEY missing DJANGO_SECRET_KEY is default/demo value POSTGRES_PASSWORD missing POSTGRES_PASSWORD is default/demo value DATABASE_URL points outside the instance without explicit allowlist Any private key bundled in the capsule Any full .env file with real secrets bundled in the capsule ``` ### 7.3 Container Policy ```text privileged: true network_mode: host Docker socket mounted into any container Unknown container attached to Konnaxion network Unknown image running under Konnaxion instance Host root filesystem mounted Container attempts to bind dangerous public ports ``` ### 7.4 Network Exposure ```text Postgres exposed publicly Redis exposed publicly Next.js direct port exposed publicly Django/Gunicorn direct port exposed publicly Flower/dashboard exposed publicly Docker daemon exposed over TCP Public mode enabled without expiry Public temporary mode enabled without auth ``` ### 7.5 Firewall ```text Firewall disabled in intranet_private, private_tunnel, public_temporary, or public_vps Firewall permits dangerous public ports Firewall does not match selected network profile Inbound default policy is allow ``` ### 7.6 Update Safety ```text Update requested without backup Migration plan missing Rollback target missing Healthcheck plan missing New capsule fails signature/checksum validation ``` --- ## 8. Canonical Dangerous Ports These ports must never be exposed publicly. | Port | Service | Rule | |---:|---|---| | `3000` | `frontend-next` direct | never public | | `5000` | `django-api` / Gunicorn | never public | | `5432` | `postgres` | never public | | `6379` | `redis` | never public | | `5555` | `flower` / dashboard | never public | | `8000` | Django dev/server direct | never public | | Docker TCP | Docker daemon | never public | Only the reverse proxy may be exposed. ```text Allowed public entrypoint: Traefik on 443 Traefik on 80 only for HTTP-to-HTTPS redirect or certificate challenge ``` --- ## 9. Network Profile Rules ### 9.1 `local_only` | Rule | Expected | |---|---| | Public access | disabled | | LAN access | disabled | | Bind address | `127.0.0.1` | | Allowed ports | local loopback only | | Public tunnel | disabled | | Firewall required | recommended | Blocking: ```text Any non-loopback bind without explicit profile change Any public tunnel Any exposed internal service ``` ### 9.2 `intranet_private` | Rule | Expected | |---|---| | Public access | disabled | | LAN access | enabled | | Bind address | LAN interface only | | Allowed ports | `443`, optional `80` redirect | | Public tunnel | disabled | | Firewall required | yes | Blocking: ```text WAN exposure detected Router port-forward detected or declared Postgres/Redis/Django/Next direct exposed ``` ### 9.3 `private_tunnel` | Rule | Expected | |---|---| | Public access | disabled | | VPN access | enabled | | Allowed provider | Tailscale or approved equivalent | | Router port-forward | none | | Public tunnel | disabled unless profile changed | | Firewall required | yes | Blocking: ```text Open public inbound port Unapproved tunnel provider Tunnel without ACL/auth Internal service reachable outside tunnel ``` ### 9.4 `public_temporary` | Rule | Expected | |---|---| | Public access | temporary | | Expiry | required | | Auth | required | | Allowed ports | provider tunnel or `443` | | Max duration | `KX_PUBLIC_MODE_DURATION_HOURS <= 8` | | Firewall required | yes | Blocking: ```text Missing expiry Missing auth Duration exceeds policy Direct public exposure of internal service ``` ### 9.5 `public_vps` | Rule | Expected | |---|---| | Public access | enabled | | Allowed ports | `80`, `443`, restricted `22` | | Reverse proxy | required | | Cloud firewall | recommended | | Local firewall | required | | Password SSH | forbidden | | Root SSH | forbidden | Blocking: ```text Password SSH enabled Root SSH enabled Dangerous public ports open Firewall disabled No reverse proxy ``` --- ## 10. Required Manifest Security Section Every `.kxcap` manifest must include a `security` section. ```yaml security: require_signed_capsule: true generate_secrets_on_install: true allow_unknown_images: false allow_privileged_containers: false allow_host_network: false allow_docker_socket_mount: false allow_public_internals: false require_firewall: true default_network_profile: intranet_private default_exposure_mode: private public_mode: enabled_by_default: false require_expiration: true require_auth: true max_duration_hours: 8 blocked_ports: - 3000 - 5000 - 5432 - 6379 - 5555 - 8000 ``` If the section is missing, the Security Gate returns: ```text manifest_schema = FAIL_BLOCKING ``` --- ## 11. Security Gate Report Schema The Security Gate must produce a machine-readable report. ```yaml security_gate_report: report_version: 1 generated_at: "2026-04-30T00:00:00Z" instance_id: "demo-001" capsule_id: "konnaxion-v14-demo-2026.04.30" capsule_version: "2026.04.30-demo.1" app_version: "v14" network_profile: "intranet_private" exposure_mode: "private" overall_status: "PASS" blocking_count: 0 warning_count: 0 checks: - id: "capsule_signature" status: "PASS" severity: "critical" message: "Capsule signature is valid." remediation: "" - id: "postgres_not_public" status: "PASS" severity: "critical" message: "PostgreSQL is reachable only inside the Docker network." remediation: "" - id: "firewall_enabled" status: "PASS" severity: "critical" message: "Firewall is active and matches intranet_private profile." remediation: "" ``` Allowed `overall_status` values: ```text PASS WARN FAIL_BLOCKING ``` Rule: ```text If any check has status FAIL_BLOCKING, overall_status = FAIL_BLOCKING. If no blocking checks exist but one or more WARN checks exist, overall_status = WARN. If all required checks pass or are skipped correctly, overall_status = PASS. ``` --- ## 12. Severity Levels | Severity | Meaning | |---|---| | `critical` | Must block if failed | | `high` | Usually blocks outside `local_only` | | `medium` | Warning unless profile requires blocking | | `low` | Informational or hygiene warning | Examples: | Check | Severity | |---|---| | `capsule_signature` | `critical` | | `postgres_not_public` | `critical` | | `docker_socket_not_mounted` | `critical` | | `firewall_enabled` | `critical` outside `local_only` | | `backup_configured` | `high` | | `healthchecks_passing` | `high` | | `no_secrets_in_logs` | `medium` | | `read_only_root_where_possible` | `medium` | --- ## 13. CLI Commands The canonical CLI is `kx`. ```bash kx security check demo-001 kx security check demo-001 --profile intranet_private kx security report demo-001 --format yaml kx security report demo-001 --format json kx security explain demo-001 postgres_not_public ``` Start must implicitly run the gate: ```bash kx instance start demo-001 --network intranet_private ``` Equivalent internal flow: ```text 1. kx security check demo-001 --profile intranet_private 2. if PASS or allowed WARN: continue 3. if FAIL_BLOCKING: refuse start 4. start instance 5. run healthchecks 6. emit final security report ``` --- ## 14. UI Requirements The Konnaxion Capsule Manager must expose a simple security view. ### 14.1 Healthy state ```text Security: OK Network profile: Intranet privé Exposure: Private Public access: Disabled [Open Konnaxion] [View Security Report] [Backup] [Stop] ``` ### 14.2 Warning state ```text Security: Warning Issue: Backup retention is shorter than recommended. Konnaxion can start, but this should be corrected. [Start Anyway] [Fix Backup Settings] [View Details] ``` ### 14.3 Blocking state ```text Security: Blocked Issue: PostgreSQL is exposed outside the internal Docker network. Konnaxion cannot start until this is fixed. [Fix Automatically] [View Details] [Export Report] ``` The UI must not offer a normal “ignore and start” button for `FAIL_BLOCKING`. --- ## 15. Auto-Fix Policy Some checks may support automatic remediation. | Check | Auto-fix allowed | |---|---:| | `firewall_enabled` | yes | | `dangerous_ports_blocked` | yes | | `secrets_present` | yes, if missing and instance not initialized | | `secrets_not_default` | yes, rotate with confirmation | | `backup_configured` | yes | | `postgres_not_public` | yes, if caused by generated compose config | | `redis_not_public` | yes, if caused by generated compose config | | `capsule_signature` | no | | `image_checksums` | no | | `unknown_image` | no | | `docker_socket_not_mounted` | yes, if caused by generated config | | `unknown_container` | no, requires operator review | Auto-fix must create an audit entry. ```yaml audit_event: event_type: "security_autofix" check_id: "dangerous_ports_blocked" instance_id: "demo-001" action: "Removed public binding for port 5432." actor: "kx-agent" result: "success" ``` --- ## 16. Audit Log Every Security Gate run must be logged. Canonical path: ```text /opt/konnaxion/instances//logs/security-gate.log ``` Machine-readable report path: ```text /opt/konnaxion/instances//state/security-gate-report.yaml ``` Audit fields: ```yaml audit: event_id: "sec_20260430_000001" event_type: "security_gate_run" generated_at: "2026-04-30T00:00:00Z" instance_id: "demo-001" profile: "intranet_private" result: "PASS" blocking_count: 0 warning_count: 0 ``` Do not log secret values. Allowed: ```text DJANGO_SECRET_KEY present: yes POSTGRES_PASSWORD present: yes ``` Forbidden: ```text DJANGO_SECRET_KEY=actual_value POSTGRES_PASSWORD=actual_value DATABASE_URL=postgres://user:password@... ``` --- ## 17. Canonical Error Codes | Code | Meaning | |---|---| | `KXSEC-001` | Capsule signature invalid | | `KXSEC-002` | Capsule checksum mismatch | | `KXSEC-003` | Manifest schema invalid | | `KXSEC-010` | Secret missing | | `KXSEC-011` | Default or weak secret | | `KXSEC-020` | Dangerous public port exposed | | `KXSEC-021` | Database exposed | | `KXSEC-022` | Redis exposed | | `KXSEC-023` | Docker socket exposed | | `KXSEC-024` | Privileged container requested | | `KXSEC-025` | Host network requested | | `KXSEC-030` | Firewall disabled | | `KXSEC-031` | Firewall profile mismatch | | `KXSEC-040` | Public mode expiry missing | | `KXSEC-041` | Public mode auth missing | | `KXSEC-050` | Backup missing before update | | `KXSEC-051` | Rollback target missing | | `KXSEC-060` | Unknown container detected | | `KXSEC-061` | Unknown image detected | --- ## 18. Example Blocking Report ```yaml security_gate_report: report_version: 1 instance_id: "demo-001" network_profile: "intranet_private" exposure_mode: "private" overall_status: "FAIL_BLOCKING" blocking_count: 2 warning_count: 0 checks: - id: "postgres_not_public" code: "KXSEC-021" status: "FAIL_BLOCKING" severity: "critical" message: "PostgreSQL is bound to 0.0.0.0:5432." remediation: "Remove the public port binding and keep Postgres on the internal Docker network only." - id: "dangerous_ports_blocked" code: "KXSEC-020" status: "FAIL_BLOCKING" severity: "critical" message: "Dangerous public port detected: 5432." remediation: "Apply the intranet_private firewall profile." ``` --- ## 19. Example Passing Report ```yaml security_gate_report: report_version: 1 instance_id: "demo-001" network_profile: "intranet_private" exposure_mode: "private" overall_status: "PASS" blocking_count: 0 warning_count: 0 checks: - id: "capsule_signature" status: "PASS" severity: "critical" - id: "allowed_public_ports" status: "PASS" severity: "critical" - id: "postgres_not_public" status: "PASS" severity: "critical" - id: "redis_not_public" status: "PASS" severity: "critical" - id: "docker_socket_not_mounted" status: "PASS" severity: "critical" - id: "firewall_enabled" status: "PASS" severity: "critical" ``` --- ## 20. Implementation Notes The Security Gate should be implemented in the **Konnaxion Agent**, not only in the UI. Reason: ```text The UI can be bypassed. The Agent controls privileged operations. Therefore the Agent must enforce the policy. ``` The UI may display and explain the report, but the Agent owns enforcement. Recommended internal modules: ```text kx-agent/security/gate kx-agent/security/checks/capsule kx-agent/security/checks/secrets kx-agent/security/checks/network kx-agent/security/checks/firewall kx-agent/security/checks/docker kx-agent/security/checks/backup kx-agent/security/reporting ``` --- ## 21. Non-Goals DOC-07 does not define: ```text The full `.kxcap` file format The full Konnaxion Agent permission model The full network profile implementation The backup storage engine The UI design system The incident response runbook ``` Those are covered by neighboring documents. --- ## 22. Acceptance Criteria DOC-07 is implemented when: ```text A capsule cannot be imported without signature/checksum validation. A Konnaxion Instance cannot start if a critical check fails. Postgres and Redis cannot be exposed publicly by generated config. Docker socket cannot be mounted by generated config. Privileged containers are rejected. Host networking is rejected. Public temporary mode requires auth and expiry. Every start produces a security report. Every update requires backup and rollback target. The UI clearly shows PASS/WARN/FAIL_BLOCKING. The Agent enforces the policy even if the UI is bypassed. ``` --- ## 23. Canonical Summary ```text DOC-07 defines the Security Gate: a blocking validation layer enforced by Konnaxion Agent before import, install, start, update, restore, network profile changes, or public exposure. Default outcome: safe private deployment. Unsafe outcome: blocked before launch. ``` ================================================================================================ FILE: docs/DOC-08_Konnaxion_Runtime_Docker_Compose.md AUTHORITY: reference CONTENT_ROLE: knowledge CONTENT_SHA256: 81182fd86c03a49d26f90bd0fc95635b1a7a899c8a28d8a777e2bd587e0864b2 CONTENT_BYTES: 41438 ================================================================================================ # DOC-08 — Konnaxion Runtime Docker Compose ```yaml doc_id: DOC-08 filename: DOC-08_Konnaxion_Runtime_Docker_Compose.md project: Konnaxion app_version: v14 param_version: kx-param-2026.04.30 status: draft depends_on: - DOC-00_Konnaxion_Canonical_Variables.md - DOC-03_Konnaxion_Capsule_Format.md - DOC-04_Konnaxion_Manager_Architecture.md - DOC-05_Konnaxion_Agent_Security_Model.md - DOC-06_Konnaxion_Network_Profiles.md - DOC-07_Konnaxion_Security_Gate.md ``` ## 1. Purpose This document defines the canonical **Docker Compose runtime** for a `Konnaxion Instance`. It describes: ```text - canonical Docker services - container names - networks - volumes - ports - healthchecks - runtime environment variables - startup order - security constraints - compose profiles - operational commands ``` This document does **not** define the capsule format itself. The capsule format is defined in `DOC-03_Konnaxion_Capsule_Format.md`. This document does **not** define the graphical manager. The manager is defined in `DOC-04_Konnaxion_Manager_Architecture.md`. --- ## 2. Runtime decision The target runtime for a Konnaxion Instance is: ```text Docker Compose ``` Konnaxion v14 already uses a Docker-compatible production stack around Django, PostgreSQL, Redis, Celery, Traefik, Flower, and Nginx/media. The legacy VPS kept the frontend as a separate Node/pnpm host service on port `3000`. For the capsule/appliance model, the frontend must be containerized. Canonical target: ```text Traefik ├── frontend-next ├── django-api └── media-nginx Internal services ├── postgres ├── redis ├── celeryworker ├── celerybeat └── flower, optional/private only ``` Kubernetes is out of scope for the plug-and-play runtime. The runtime must not require: ```text - public Docker socket access - Docker provider labels in Traefik - host-level frontend systemd service - public port 3000 - public port 5000 - runtime pnpm/Corepack download ``` --- ## 3. Runtime goals The Docker Compose runtime must satisfy these goals: ```text 1. Start Konnaxion with one controlled command. 2. Keep all internal services off the public network. 3. Expose only Traefik. 4. Support local, intranet, tunnel, and VPS profiles. 5. Generate secrets at install time, not capsule build time. 6. Preserve instance data outside the capsule. 7. Support backup, restore, update, and rollback. 8. Be readable and debuggable by an operator. 9. Be enforceable by Konnaxion Agent. 10. Work with a private Droplet Agent reachable only through SSH-local curl. 11. Use Traefik file-provider dynamic config, not Docker socket labels. 12. Persist public host changes durably when `/network/set-profile` is called. 13. Support custom public domains and aliases without manual runtime edits. ``` --- ## 4. Canonical service names All Compose files must use these service names. | Service | Canonical name | Required | Public port allowed | | -------------------- | --------------- | -------: | ------------------: | | Reverse proxy | `traefik` | yes | yes, `80/443` | | Frontend | `frontend-next` | yes | no | | Backend API | `django-api` | yes | no | | Database | `postgres` | yes | no | | Redis broker | `redis` | yes | no | | Celery worker | `celeryworker` | yes | no | | Celery beat | `celerybeat` | yes | no | | Media/static service | `media-nginx` | yes | no | | Celery dashboard | `flower` | optional | no | | Runtime init job | `kx-init` | optional | no | | Migration job | `kx-migrate` | optional | no | Do not use alternate names such as: ```text backend api web next frontend db cache worker beat nginx ``` unless they are aliases inside comments only. --- ## 5. Canonical routing Traefik is the only HTTP entrypoint. ```text https:/// -> frontend-next https:///api/ -> django-api https:///admin/ -> django-api https:///media/ -> media-nginx ``` Routing is rendered by the Agent into a Traefik file-provider dynamic config. The runtime must not depend on Docker labels for routing, because the Docker socket is not mounted into Traefik. Canonical rendered file: ```text /opt/konnaxion/instances//state/traefik-dynamic.yml ``` Mounted inside Traefik as: ```text /etc/traefik/dynamic/traefik-dynamic.yml ``` Traefik static args must include: ```text --providers.file.filename=/etc/traefik/dynamic/traefik-dynamic.yml --providers.file.watch=true --entrypoints.web.address=:80 --entrypoints.websecure.address=:443 --entrypoints.web.http.redirections.entrypoint.to=websecure --entrypoints.web.http.redirections.entrypoint.scheme=https --api.dashboard=false ``` ### 5.1 Host rule contract For every HTTP router, the Agent must render a host rule from: ```text KX_HOST KX_HOST_ALIASES ``` `KX_HOST` is the canonical runtime host. `KX_HOST_ALIASES` is optional and contains comma-separated additional public hostnames that should route to the same instance. Example: ```env KX_HOST=konnxion.com KX_HOST_ALIASES=www.konnxion.com,138.197.174.76.sslip.io ``` The Agent must render an equivalent Traefik rule: ```text Host(`konnxion.com`) || Host(`www.konnxion.com`) || Host(`138.197.174.76.sslip.io`) ``` All routers must use the same host rule. The Agent must never render a public VPS router with only an old fallback hostname when a custom domain has been selected by the Manager. --- ## 6. Canonical ports ### 6.1 Allowed published ports | Port | Service | Profiles | | --------------: | --------- | ---------------------------------------------------------------------- | | `443` | `traefik` | `intranet_private`, `private_tunnel`, `public_temporary`, `public_vps` | | `80` | `traefik` | optional redirect, mostly `public_vps` | | `127.0.0.1:443` | `traefik` | `local_only` | | `127.0.0.1:80` | `traefik` | optional local redirect | ### 6.2 Forbidden published ports The following ports must never be published directly: | Port | Service | Rule | | ---------: | ----------------------- | -------------------------- | | `3000` | `frontend-next` | internal only | | `5000` | `django-api` / Gunicorn | internal only | | `5555` | `flower` | private only, never public | | `5432` | `postgres` | internal only | | `6379` | `redis` | internal only | | `8000` | Django dev server | forbidden in runtime | | Docker TCP | Docker daemon | forbidden | Only Traefik may publish host ports. --- ## 7. Network model The runtime uses internal Docker networks. Canonical logical networks: ```text kx-public - Traefik - receives published ports from host kx-private - Traefik - frontend-next - django-api - media-nginx - postgres - redis - celeryworker - celerybeat - flower kx-data - django-api - postgres - redis - celeryworker - celerybeat ``` Traefik attaches to: ```text kx-public kx-private ``` Application containers attach to: ```text kx-private ``` Stateful/backend containers may also attach to: ```text kx-data ``` No container except `traefik` may publish ports. --- ## 8. Volume model Instance data must live outside the capsule. Canonical persistent paths: ```text /opt/konnaxion/instances// ├── env/ ├── state/ ├── logs/ ├── data/ ├── backups/ └── runtime/ ``` Canonical Docker volumes or bind mounts: | Volume/path | Purpose | Persistent | | --------------------- | ----------------- | ----------------: | | `kx_postgres_data` | PostgreSQL data | yes | | `kx_postgres_backups` | PostgreSQL dumps | yes | | `kx_redis_data` | Redis persistence | yes | | `kx_django_media` | Uploaded media | yes | | `kx_traefik_acme` | TLS certificates | profile-dependent | | `kx_logs` | Runtime logs | yes | | `kx_state` | Instance state | yes | The capsule must not contain live secrets, database files, Redis state, uploaded media, or runtime logs. --- ## 9. Runtime file model Runtime env files live in the instance directory, not inside the capsule. Canonical location: ```text /opt/konnaxion/instances//env/ ├── kx.env ├── django.env ├── postgres.env ├── redis.env ├── frontend.env └── traefik.env ``` Rendered runtime compose location: ```text /opt/konnaxion/instances//state/docker-compose.runtime.yml ``` Rendered Traefik file-provider config location: ```text /opt/konnaxion/instances//state/traefik-dynamic.yml ``` The capsule may contain templates, but never real secrets. Host-derived runtime values are mutable instance state. When `KX_HOST` or `KX_HOST_ALIASES` changes, the Agent must regenerate the relevant env files and Traefik dynamic config while preserving generated secrets. --- ## 10. Required runtime variables ### 10.1 `kx.env` ```env KX_INSTANCE_ID=demo-001 KX_CAPSULE_ID=konnaxion-v14-demo-2026.04.30 KX_CAPSULE_VERSION=2026.04.30-demo.1 KX_APP_VERSION=v14 KX_PARAM_VERSION=kx-param-2026.04.30 KX_NETWORK_PROFILE=public_vps KX_EXPOSURE_MODE=public KX_PUBLIC_MODE_ENABLED=true KX_PUBLIC_MODE_EXPIRES_AT= KX_HOST=konnxion.com KX_HOST_ALIASES=www.konnxion.com,138.197.174.76.sslip.io KX_REQUIRE_SIGNED_CAPSULE=true KX_GENERATE_SECRETS_ON_INSTALL=true KX_ALLOW_UNKNOWN_IMAGES=false KX_ALLOW_PRIVILEGED_CONTAINERS=false KX_ALLOW_DOCKER_SOCKET_MOUNT=false KX_ALLOW_HOST_NETWORK=false KX_BACKUP_ENABLED=true ``` `KX_HOST` must be generated from the selected network profile and Manager payload. For `public_vps`, `KX_HOST` must be the canonical public runtime hostname selected by the operator: ```text domain or public_host or droplet_domain or sslip hostname or droplet_host fallback ``` The preference order must choose operator-facing public domain fields before the Droplet IP: ```text domain droplet_domain public_host public_url url host kx_host KX_HOST droplet_host target_host ``` It must never silently fall back to `127.0.0.1` for `public_vps`. `KX_HOST_ALIASES` should include useful alternate public names, such as: ```text www. .sslip.io ``` when available. `KX_HOST_ALIASES` must not include empty values, duplicate values, paths, schemes, or userinfo. ### 10.2 `django.env` ```env DJANGO_SETTINGS_MODULE=config.settings.production DJANGO_SECRET_KEY= DJANGO_DEBUG=False DJANGO_ALLOWED_HOSTS=127.0.0.1,localhost,,,django-api,kx--django-api DJANGO_CSRF_TRUSTED_ORIGINS=https://,http://,https://,http:// CSRF_TRUSTED_ORIGINS=https://,http://,https://,http:// USE_DOCKER=yes DATABASE_URL=postgres://konnaxion:@postgres:5432/konnaxion REDIS_URL=redis://redis:6379/0 CELERY_BROKER_URL=redis://redis:6379/0 DJANGO_ADMIN_URL=admin/ SENTRY_DSN= ``` `DJANGO_ALLOWED_HOSTS`, `DJANGO_CSRF_TRUSTED_ORIGINS`, `CSRF_TRUSTED_ORIGINS`, and `CORS_ALLOWED_ORIGINS` must be regenerated when `KX_HOST` or `KX_HOST_ALIASES` changes. They must include the public VPS hostname for `public_vps`. They should include all public aliases rendered into Traefik Host rules. ### 10.3 `postgres.env` ```env POSTGRES_HOST=postgres POSTGRES_PORT=5432 POSTGRES_DB=konnaxion POSTGRES_USER=konnaxion POSTGRES_PASSWORD= ``` ### 10.4 `redis.env` ```env REDIS_URL=redis://redis:6379/0 REDIS_APPENDONLY=yes ``` ### 10.5 `frontend.env` ```env NODE_ENV=production NEXT_TELEMETRY_DISABLED=1 NODE_OPTIONS=--max-old-space-size=4096 NEXT_PUBLIC_API_BASE=https:///api NEXT_PUBLIC_BACKEND_BASE=https:// ``` The frontend must use the canonical `KX_HOST`, not an arbitrary alias. The frontend image must not require runtime network access to download `pnpm`, Corepack packages, or build dependencies. --- ## 11. Frontend image runtime contract The frontend image must be production-runnable without `pnpm` or Corepack at runtime. The Builder-generated or canonical frontend image must include: ```text /app/package.json /app/node_modules /app/.next /app/public /app/next.config.* /app/env.mjs ``` The runtime command must be: ```text node node_modules/next/dist/bin/next start -H 0.0.0.0 -p 3000 ``` The runtime command must not be: ```text pnpm start corepack pnpm start npm install pnpm install pnpm build next dev ``` Build-time frontend generation may use: ```env NODE_OPTIONS=--max-old-space-size=4096 ``` The frontend build context must exclude: ```text node_modules .next out dist coverage reports test-results playwright-report .cache .turbo .vercel .git storageState.json *.log Dockerfile.capsule ``` --- ## 12. Canonical Compose file Capsule file name: ```text docker-compose.capsule.yml ``` Rendered runtime location: ```text /opt/konnaxion/instances//state/docker-compose.runtime.yml ``` Reference Compose: ```yaml services: traefik: image: ${KX_IMAGE_TRAEFIK:-traefik:v3.1} container_name: kx-${KX_INSTANCE_ID}-traefik restart: unless-stopped command: - --providers.file.filename=/etc/traefik/dynamic/traefik-dynamic.yml - --providers.file.watch=true - --entrypoints.web.address=:80 - --entrypoints.websecure.address=:443 - --entrypoints.web.http.redirections.entrypoint.to=websecure - --entrypoints.web.http.redirections.entrypoint.scheme=https - --api.dashboard=false env_file: - ../env/kx.env - ../env/traefik.env ports: - "${KX_BIND_HTTP:-0.0.0.0:80}:80" - "${KX_BIND_HTTPS:-0.0.0.0:443}:443" volumes: - ./traefik-dynamic.yml:/etc/traefik/dynamic/traefik-dynamic.yml:ro - ../logs/traefik:/var/log/traefik networks: - kx-public - kx-private security_opt: - no-new-privileges:true read_only: false privileged: false healthcheck: test: ["CMD", "traefik", "healthcheck", "--ping"] interval: 30s timeout: 5s retries: 5 frontend-next: image: ${KX_IMAGE_FRONTEND:-konnaxion/frontend-next:v14} container_name: kx-${KX_INSTANCE_ID}-frontend-next restart: unless-stopped env_file: - ../env/kx.env - ../env/frontend.env expose: - "3000" networks: - kx-private security_opt: - no-new-privileges:true read_only: false privileged: false pull_policy: never healthcheck: test: [ "CMD-SHELL", "node -e \"require('http').get('http://127.0.0.1:3000', r => { process.exit(r.statusCode < 500 ? 0 : 1) }).on('error', () => process.exit(1))\"" ] interval: 30s timeout: 5s retries: 10 django-api: image: ${KX_IMAGE_BACKEND:-konnaxion/django-api:v14} container_name: kx-${KX_INSTANCE_ID}-django-api restart: unless-stopped command: /start env_file: - ../env/kx.env - ../env/django.env - ../env/postgres.env - ../env/redis.env depends_on: postgres: condition: service_healthy redis: condition: service_healthy expose: - "5000" volumes: - kx_django_media:/app/konnaxion/media - kx_logs:/app/logs networks: - kx-private - kx-data security_opt: - no-new-privileges:true read_only: false privileged: false pull_policy: never healthcheck: test: [ "CMD-SHELL", "python -c \"import socket; sock=socket.create_connection(('127.0.0.1',5000),5); sock.close()\"" ] interval: 30s timeout: 5s retries: 10 media-nginx: image: ${KX_IMAGE_MEDIA_NGINX:-nginx:stable} container_name: kx-${KX_INSTANCE_ID}-media-nginx restart: unless-stopped depends_on: - django-api expose: - "80" volumes: - kx_django_media:/usr/share/nginx/media:ro networks: - kx-private security_opt: - no-new-privileges:true read_only: false privileged: false healthcheck: test: ["CMD-SHELL", "nginx -t >/dev/null 2>&1 || exit 1"] interval: 30s timeout: 5s retries: 10 postgres: image: ${KX_IMAGE_POSTGRES:-postgres:16} container_name: kx-${KX_INSTANCE_ID}-postgres restart: unless-stopped env_file: - ../env/postgres.env volumes: - kx_postgres_data:/var/lib/postgresql/data - kx_postgres_backups:/backups expose: - "5432" networks: - kx-data security_opt: - no-new-privileges:true healthcheck: test: ["CMD-SHELL", "pg_isready -U $${POSTGRES_USER} -d $${POSTGRES_DB}"] interval: 30s timeout: 5s retries: 10 redis: image: ${KX_IMAGE_REDIS:-redis:7} container_name: kx-${KX_INSTANCE_ID}-redis restart: unless-stopped command: ["redis-server", "--appendonly", "yes"] volumes: - kx_redis_data:/data expose: - "6379" networks: - kx-data - kx-private security_opt: - no-new-privileges:true healthcheck: test: ["CMD", "redis-cli", "ping"] interval: 30s timeout: 5s retries: 10 celeryworker: image: ${KX_IMAGE_BACKEND:-konnaxion/django-api:v14} container_name: kx-${KX_INSTANCE_ID}-celeryworker restart: unless-stopped command: /start-celeryworker env_file: - ../env/kx.env - ../env/django.env - ../env/postgres.env - ../env/redis.env depends_on: django-api: condition: service_healthy redis: condition: service_healthy volumes: - kx_django_media:/app/konnaxion/media - kx_logs:/app/logs networks: - kx-private - kx-data security_opt: - no-new-privileges:true pull_policy: never celerybeat: image: ${KX_IMAGE_BACKEND:-konnaxion/django-api:v14} container_name: kx-${KX_INSTANCE_ID}-celerybeat restart: unless-stopped command: /start-celerybeat env_file: - ../env/kx.env - ../env/django.env - ../env/postgres.env - ../env/redis.env depends_on: django-api: condition: service_healthy redis: condition: service_healthy volumes: - kx_logs:/app/logs networks: - kx-private - kx-data security_opt: - no-new-privileges:true pull_policy: never flower: image: ${KX_IMAGE_BACKEND:-konnaxion/django-api:v14} container_name: kx-${KX_INSTANCE_ID}-flower restart: unless-stopped command: /start-flower profiles: - observability env_file: - ../env/kx.env - ../env/django.env - ../env/postgres.env - ../env/redis.env depends_on: redis: condition: service_healthy expose: - "5555" networks: - kx-private - kx-data security_opt: - no-new-privileges:true pull_policy: never kx-migrate: image: ${KX_IMAGE_BACKEND:-konnaxion/django-api:v14} container_name: kx-${KX_INSTANCE_ID}-kx-migrate profiles: - jobs command: python manage.py migrate env_file: - ../env/kx.env - ../env/django.env - ../env/postgres.env - ../env/redis.env depends_on: postgres: condition: service_healthy redis: condition: service_healthy networks: - kx-private - kx-data security_opt: - no-new-privileges:true pull_policy: never volumes: kx_postgres_data: kx_postgres_backups: kx_redis_data: kx_django_media: kx_traefik_acme: kx_logs: kx_state: networks: kx-public: name: kx-${KX_INSTANCE_ID}-public kx-private: name: kx-${KX_INSTANCE_ID}-private kx-data: name: kx-${KX_INSTANCE_ID}-data ``` --- ## 13. Traefik dynamic file File name: ```text traefik-dynamic.yml ``` Rendered location: ```text /opt/konnaxion/instances//state/traefik-dynamic.yml ``` Mounted location: ```text /etc/traefik/dynamic/traefik-dynamic.yml ``` Reference: ```yaml http: routers: kx-frontend: rule: "() && PathPrefix(`/`)" entryPoints: - websecure tls: {} service: kx-frontend priority: 1 kx-api: rule: "() && PathPrefix(`/api/`)" entryPoints: - websecure tls: {} service: kx-api priority: 100 kx-admin: rule: "() && PathPrefix(`/admin/`)" entryPoints: - websecure tls: {} service: kx-api priority: 100 kx-media: rule: "() && PathPrefix(`/media/`)" entryPoints: - websecure tls: {} service: kx-media priority: 100 services: kx-frontend: loadBalancer: servers: - url: "http://kx--frontend-next:3000" kx-api: loadBalancer: servers: - url: "http://kx--django-api:5000" kx-media: loadBalancer: servers: - url: "http://kx--media-nginx:80" ``` `` is rendered from `KX_HOST` plus optional `KX_HOST_ALIASES`. Example rendered rule: ```text (Host(`konnxion.com`) || Host(`www.konnxion.com`) || Host(`138.197.174.76.sslip.io`)) && PathPrefix(`/api/`) ``` The Agent must render the same host rule for all routers. The Agent must render `` and aliases from the instance env/profile state, not from stale generated files. For `public_vps`, the host must be the public DNS name or sslip.io hostname selected by the Manager. For `.local` or intranet hostnames, do not configure public Let's Encrypt. --- ## 14. Network profile bindings The Agent must render `KX_BIND_HTTP`, `KX_BIND_HTTPS`, `KX_HOST`, `KX_HOST_ALIASES`, and exposure fields based on `KX_NETWORK_PROFILE`. ### 14.1 `local_only` ```env KX_NETWORK_PROFILE=local_only KX_HOST=127.0.0.1 KX_HOST_ALIASES=localhost KX_BIND_HTTP=127.0.0.1:80 KX_BIND_HTTPS=127.0.0.1:443 KX_EXPOSURE_MODE=private KX_PUBLIC_MODE_ENABLED=false ``` ### 14.2 `intranet_private` ```env KX_NETWORK_PROFILE=intranet_private KX_HOST= KX_HOST_ALIASES= KX_BIND_HTTP=0.0.0.0:80 KX_BIND_HTTPS=0.0.0.0:443 KX_EXPOSURE_MODE=lan KX_PUBLIC_MODE_ENABLED=false ``` Firewall must restrict exposure to LAN/private ranges. ### 14.3 `private_tunnel` ```env KX_NETWORK_PROFILE=private_tunnel KX_HOST= KX_HOST_ALIASES= KX_BIND_HTTP=127.0.0.1:80 KX_BIND_HTTPS=127.0.0.1:443 KX_EXPOSURE_MODE=vpn KX_PUBLIC_MODE_ENABLED=false ``` The tunnel agent exposes the service; Docker does not publish public ports. ### 14.4 `public_temporary` ```env KX_NETWORK_PROFILE=public_temporary KX_HOST= KX_HOST_ALIASES= KX_BIND_HTTP=127.0.0.1:80 KX_BIND_HTTPS=127.0.0.1:443 KX_EXPOSURE_MODE=temporary_tunnel KX_PUBLIC_MODE_ENABLED=true KX_PUBLIC_MODE_EXPIRES_AT= ``` Expiration is mandatory. ### 14.5 `public_vps` ```env KX_NETWORK_PROFILE=public_vps KX_HOST= KX_HOST_ALIASES= KX_BIND_HTTP=0.0.0.0:80 KX_BIND_HTTPS=0.0.0.0:443 KX_EXPOSURE_MODE=public KX_PUBLIC_MODE_ENABLED=true KX_PUBLIC_MODE_EXPIRES_AT= ``` Firewall must allow only: ```text 80/tcp 443/tcp 22/tcp from admin IP or VPN only ``` `public_vps` must not require `KX_PUBLIC_MODE_EXPIRES_AT`. `public_vps` must not use `127.0.0.1`, `localhost`, or an empty string as `KX_HOST`. --- ## 15. Manager-to-Agent Droplet transport For Droplet/VPS deployment, the Agent must remain private on the Droplet: ```text 127.0.0.1:8765 ``` The Manager must call the Droplet Agent through SSH-local curl: ```text Manager on Windows -> ssh root@ -> curl http://127.0.0.1:8765/v1/ ``` The Manager must not require a local tunnel such as: ```text 127.0.0.1:18765 -> tunnel -> 127.0.0.1:8765 ``` The Manager must not bind the Agent publicly on: ```text 0.0.0.0:8765 ``` For Droplet mode: ```text remote_agent_url empty or loopback -> use SSH-local transport remote_agent_url real non-loopback URL -> use direct HTTP only if explicitly configured ``` The following Agent calls must use the same transport: ```text /health /agent/info /capsules/import /instances/create /instances/update /network/set-profile /security/check /instances/start /logs /status ``` When sending network profile data, Manager must normalize public host fields into the Agent field named `host`. Canonical normalization preference: ```text domain droplet_domain public_host public_url url host kx_host KX_HOST droplet_host target_host ``` The Manager must keep these meanings distinct: ```text host/public_host/domain/droplet_domain = public runtime host, e.g. konnxion.com droplet_host/target_host = SSH target, e.g. 138.197.174.76 ``` The Agent schema should accept `host`, not arbitrary `domain`. The Manager must send `host` during both: ```text /instances/create /network/set-profile ``` The Agent must persist the host change during `/network/set-profile` by regenerating: ```text /opt/konnaxion/instances//env/kx.env /opt/konnaxion/instances//env/django.env /opt/konnaxion/instances//env/frontend.env /opt/konnaxion/instances//state/docker-compose.runtime.yml /opt/konnaxion/instances//state/traefik-dynamic.yml ``` `/network/set-profile` must not be validation-only. It must preserve existing secrets while rewriting host-derived env values. Preserve: ```text DJANGO_SECRET_KEY POSTGRES_PASSWORD DATABASE_URL password component ``` Rewrite: ```text KX_HOST KX_HOST_ALIASES KX_NETWORK_PROFILE KX_EXPOSURE_MODE KX_PUBLIC_MODE_ENABLED KX_PUBLIC_MODE_EXPIRES_AT DJANGO_ALLOWED_HOSTS DJANGO_CSRF_TRUSTED_ORIGINS CSRF_TRUSTED_ORIGINS CORS_ALLOWED_ORIGINS NEXT_PUBLIC_API_BASE NEXT_PUBLIC_BACKEND_BASE Traefik Host(...) rules ``` --- ## 16. Startup sequence Konnaxion Agent must start services in this order: ```text 1. Verify capsule signature. 2. Verify required image archives/checksums. 3. Resolve and validate network profile host. 4. Render runtime env files. 5. Render docker-compose.runtime.yml. 6. Render traefik-dynamic.yml. 7. Run Security Gate. 8. Start postgres and redis. 9. Run migrations. 10. Start django-api. 11. Start frontend-next. 12. Start media-nginx. 13. Start celeryworker and celerybeat. 14. Start traefik. 15. Run healthchecks. 16. Mark instance as running. ``` For dependencies that require Django health, the healthcheck must use a robust local socket check, not `wget`. Equivalent CLI flow: ```bash kx capsule verify konnaxion-v14-demo-2026.04.30.kxcap kx instance create demo-001 --capsule konnaxion-v14-demo-2026.04.30.kxcap --profile public_vps --host konnxion.com kx network set-profile demo-001 --profile public_vps --host konnxion.com --alias www.konnxion.com --alias 138.197.174.76.sslip.io kx security check demo-001 kx instance start demo-001 kx instance status demo-001 ``` --- ## 17. Migration flow Migrations must run as a one-off job. ```bash docker compose --profile jobs run --rm kx-migrate ``` Equivalent manager command: ```bash kx instance migrate demo-001 ``` Django model changes require migrations before the schema is considered valid. --- ## 18. Backup flow The runtime must support PostgreSQL backups through the `postgres` service. Canonical command: ```bash docker compose exec -T postgres \ pg_dump -U konnaxion -d konnaxion \ > ../backups/postgres/konnaxion_${KX_INSTANCE_ID}_$(date +%Y%m%d_%H%M%S).sql ``` Equivalent manager command: ```bash kx instance backup demo-001 ``` Backups must include: ```text PostgreSQL dump media volume runtime manifest capsule reference safe env metadata without secrets ``` Backups must not include: ```text old full disk image /tmp /dev/shm unknown crontabs unknown systemd units unknown Docker volumes old authorized_keys old sudoers fragments ``` --- ## 19. Update and rollback flow Each update uses a new immutable capsule. ```text current capsule: konnaxion-v14-demo-2026.04.30.kxcap next capsule: konnaxion-v14-demo-2026.05.07.kxcap ``` Update sequence: ```text 1. Verify new capsule. 2. Verify required image archives. 3. Backup current instance. 4. Stop frontend-next, celeryworker, celerybeat. 5. Load new images from capsule. 6. Render updated env and compose. 7. Preserve canonical network profile host and aliases unless the operator changes them. 8. Run migrations. 9. Start new services. 10. Run healthchecks. 11. If healthy, mark new capsule current. 12. If unhealthy, rollback to previous capsule. ``` Rollback command: ```bash kx instance rollback demo-001 ``` --- ## 20. Security requirements The runtime must enforce: ```text - no privileged containers - no host network mode - no Docker socket mount - no unknown images - no public database - no public Redis - no public frontend direct port - no public Django direct port - no public Flower dashboard - no secrets in image layers - no secrets inside .kxcap - no Traefik Docker provider requiring docker.sock ``` Traefik must use the file provider. The Docker socket must not be mounted into Traefik or any application container. --- ## 21. Security Gate checks Before `docker compose up`, Konnaxion Agent must run: ```text capsule_signature image_archives_present image_checksums manifest_schema compose_schema traefik_dynamic_schema forbidden_ports_not_published docker_socket_not_mounted no_privileged_containers no_host_network postgres_not_public redis_not_public frontend_not_public django_not_public flower_not_public allowed_images_only env_files_permissions secrets_not_default network_profile_valid public_mode_expiration_valid public_vps_host_present public_vps_host_not_loopback django_allowed_hosts_contains_kx_host django_allowed_hosts_contains_kx_host_aliases frontend_public_urls_match_kx_host traefik_host_rules_contain_kx_host traefik_host_rules_contain_kx_host_aliases ``` Blocking failures: ```text FAIL_BLOCKING if port 3000 is published FAIL_BLOCKING if port 5000 is published FAIL_BLOCKING if port 5432 is published FAIL_BLOCKING if port 6379 is published FAIL_BLOCKING if Docker socket is mounted FAIL_BLOCKING if privileged: true exists FAIL_BLOCKING if network_mode: host exists FAIL_BLOCKING if public_temporary has no expiration FAIL_BLOCKING if public_vps has no KX_HOST FAIL_BLOCKING if public_vps KX_HOST is 127.0.0.1 or localhost FAIL_BLOCKING if capsule signature is invalid FAIL_BLOCKING if required image archive is missing FAIL_BLOCKING if image checksum mismatch FAIL_BLOCKING if DJANGO_ALLOWED_HOSTS excludes KX_HOST FAIL_BLOCKING if Traefik dynamic config excludes KX_HOST FAIL_BLOCKING if Traefik dynamic config uses 127.0.0.1 for public_vps ``` --- ## 22. Compose validation command Konnaxion Agent must validate the rendered Compose file before starting. ```bash docker compose -f docker-compose.runtime.yml config ``` Then inspect published ports: ```bash docker compose -f docker-compose.runtime.yml config | grep -n "published\|target\|ports" || true ``` The final validation must prove that only Traefik publishes ports. --- ## 23. Healthcheck matrix | Service | Healthcheck | | --------------- | ------------------------------------------------ | | `traefik` | Traefik ping or container running | | `frontend-next` | Node HTTP request to `http://127.0.0.1:3000/` | | `django-api` | Python socket connect to `127.0.0.1:5000` | | `postgres` | `pg_isready` | | `redis` | `redis-cli ping` | | `media-nginx` | `nginx -t` or container running | | `celeryworker` | process running or Celery inspect ping, optional | | `celerybeat` | process running | | `flower` | private HTTP health, optional | External healthcheck must use only: ```text https:/// https:///api/ https:///admin/ https:///media/ ``` Alias healthchecks may also be used when `KX_HOST_ALIASES` is configured: ```text https:/// https:///api/ ``` Never: ```text http://:3000 http://:5000 http://:5555 http://:5432 http://:6379 ``` `/api/` or `/api/health/` may return Django `404` if those exact routes do not exist. That is acceptable infrastructure-wise if the response comes from Django/Uvicorn and not Traefik `404`. A Traefik plain-text response of: ```text 404 page not found ``` for `https:///` or `https:///api/` is a blocking routing failure for `public_vps`. It means the Host rule did not match the public domain. --- ## 24. Observability Minimum commands: ```bash docker compose ps docker compose logs --tail=100 traefik docker compose logs --tail=100 django-api docker compose logs --tail=100 frontend-next docker compose logs --tail=100 celeryworker docker compose logs --tail=100 postgres docker compose logs --tail=100 redis ``` Canonical manager commands: ```bash kx instance status demo-001 kx instance logs demo-001 --service traefik kx instance logs demo-001 --service django-api kx instance logs demo-001 --service frontend-next kx security check demo-001 ``` Useful direct diagnostic checks: ```bash curl -k -I https:// curl -k -I https:///api/ curl -k -I https:///admin/ docker inspect kx--django-api --format '{{json .State.Health}}' docker inspect kx--frontend-next --format '{{json .State.Health}}' ``` Useful host-rule diagnostics from the VPS: ```bash curl -k -i -H 'Host: ' https://127.0.0.1/ curl -k -i -H 'Host: ' https://127.0.0.1/api/ curl -k -i -H 'Host: ' https://127.0.0.1/ curl -k -i -H 'Host: ' https://127.0.0.1/api/ grep -RniE 'Host|KX_HOST|NEXT_PUBLIC|DJANGO_ALLOWED_HOSTS' \ /opt/konnaxion/instances//env \ /opt/konnaxion/instances//state ``` For local DNS bypass testing: ```bash curl -k -i --resolve :443: https:/// curl -k -i --resolve :443: https:///api/ ``` --- ## 25. Host-level runtime requirements Minimum host: ```text Linux host Docker Engine Docker Compose v2 4 GB RAM minimum 8 GB RAM recommended SSD storage Firewall available ``` For small demo VPS hosts, 2 GB RAM plus swap can work, but image build should preferably happen locally or in CI, then images should be loaded on the VPS. For capsule/appliance deployment, recommended: ```text Ubuntu Server LTS or Debian minimal Docker from official repository Konnaxion Agent installed as system service Konnaxion Agent private on 127.0.0.1:8765 Konnaxion Manager local UI UFW or equivalent firewall Tailscale or tunnel agent optional ``` --- ## 26. Forbidden runtime patterns Do not use: ```text frontend on host systemd as target architecture public port 3000 public port 5000 public port 5555 public PostgreSQL public Redis Docker socket mounted into app containers Traefik Docker provider requiring docker.sock deployment user in docker group by default unverified images unknown containers host network mode privileged containers manual edits inside running containers runtime pnpm/Corepack network downloads ``` Manual edits to generated runtime files may be used only as emergency diagnostics. Permanent behavior belongs in Agent renderers and Manager payload generation. --- ## 27. Compatibility with legacy deployment Legacy production shape: ```text Backend: Docker Compose Frontend: Node.js / pnpm on host Database: Docker Postgres Redis: Docker Redis Proxy: Docker Traefik ``` Target capsule runtime: ```text Frontend: Docker container Backend: Docker container Database: Docker Postgres Redis: Docker Redis Proxy: Docker Traefik file provider Media: Docker Nginx Workers: Docker Celery ``` Migration from legacy to capsule requires: ```text 1. Build frontend image. 2. Include frontend-next image archive in .kxcap. 3. Add frontend-next service to docker-compose.capsule.yml. 4. Route Traefik to frontend-next:3000. 5. Remove public host exposure of port 3000. 6. Preserve /api/, /admin/, and /media/ routing. 7. Generate KX_HOST, KX_HOST_ALIASES, DJANGO_ALLOWED_HOSTS, and NEXT_PUBLIC_* from network profile. 8. Ensure /network/set-profile persists runtime host changes. ``` --- ## 28. Capsule image requirements A deployable capsule must contain required runtime image archives. Minimum required app images: ```text images/frontend-next.oci.tar images/django-api.oci.tar ``` Recommended full runtime image archive set: ```text images/frontend-next.oci.tar images/django-api.oci.tar images/traefik.oci.tar images/media-nginx.oci.tar images/postgres.oci.tar images/redis.oci.tar ``` A capsule with only: ```text images/README.json ``` must fail verification for production or Droplet deployment. Builder must write image archives before: ```text checksums.txt signature.sig ``` Verify must fail if manifest/compose requires images that are absent. --- ## 29. Acceptance criteria `DOC-08` is implemented correctly when: ```text [PASS] docker compose config succeeds [PASS] only traefik publishes ports [PASS] postgres has no published port [PASS] redis has no published port [PASS] frontend-next has no published port [PASS] django-api has no published port [PASS] flower has no published port [PASS] / routes to frontend-next [PASS] /api/ routes to django-api or returns Django/Uvicorn response [PASS] /admin/ routes to django-api [PASS] /media/ routes to media-nginx [PASS] frontend-next runs without runtime pnpm/Corepack download [PASS] django-api becomes healthy using robust socket healthcheck [PASS] Traefik uses file provider and no Docker socket [PASS] KX_HOST is correct for selected network profile [PASS] KX_HOST_ALIASES are optional but correctly routed when present [PASS] Traefik Host rules include KX_HOST [PASS] Traefik Host rules include KX_HOST_ALIASES when configured [PASS] DJANGO_ALLOWED_HOSTS includes KX_HOST [PASS] DJANGO_ALLOWED_HOSTS includes KX_HOST_ALIASES when configured [PASS] NEXT_PUBLIC_API_BASE uses canonical KX_HOST [PASS] /network/set-profile regenerates env files [PASS] /network/set-profile regenerates traefik-dynamic.yml [PASS] /network/set-profile preserves existing secrets [PASS] migrations run through kx-migrate [PASS] backups can be created from postgres [PASS] Security Gate blocks dangerous compose changes [PASS] local_only profile binds to localhost [PASS] intranet_private exposes only 80/443 to LAN [PASS] public_temporary requires expiration [PASS] public_vps exposes only 80/443 publicly [PASS] public_vps never renders 127.0.0.1 as KX_HOST [PASS] Manager reaches Droplet Agent through SSH-local curl when Agent is private [PASS] Manager sends host during /instances/create [PASS] Manager sends host during /network/set-profile [PASS] capsule verify fails if required image archives are missing ``` --- ## 30. Out of scope This document does not define: ```text Konnaxion Capsule file signing internals Konnaxion Manager UI screens Konnaxion Agent privilege boundary Threat model details Backup retention policy Full VPS hardening guide Frontend application architecture Backend model architecture ``` Those belong to: ```text DOC-03_Konnaxion_Capsule_Format.md DOC-04_Konnaxion_Manager_Architecture.md DOC-05_Konnaxion_Agent_Security_Model.md DOC-07_Konnaxion_Security_Gate.md DOC-09_Konnaxion_Backup_Restore_Rollback.md DOC-13_Konnaxion_Threat_Model.md ``` --- ## 31. Final decision The canonical Konnaxion runtime is: ```text Docker Compose Traefik as only public entrypoint Traefik file provider, not Docker socket provider Next.js frontend in container Django/Gunicorn backend in container PostgreSQL internal only Redis internal only Celery internal only Nginx/media internal only Flower optional and private only Security Gate before start Network profiles rendered and persisted by Konnaxion Agent KX_HOST propagated to Traefik, Django, and frontend env KX_HOST_ALIASES propagated to Traefik and Django env when configured No public app internals No runtime package-manager downloads No public Agent listener Droplet Agent private on 127.0.0.1:8765 and reached by SSH-local curl Manager preserves the distinction between public runtime host and SSH Droplet host /network/set-profile regenerates runtime files and is not validation-only ``` This replaces the legacy hybrid VPS model for future Konnaxion Capsule and Konnaxion Box deployments. ================================================================================================ FILE: docs/DOC-09_Konnaxion_Backup_Restore_Rollback.md AUTHORITY: reference CONTENT_ROLE: knowledge CONTENT_SHA256: 61b390afd59da3e4c12e328f7efc0e1886e143e2861c3468d3dd03f442d5ec46 CONTENT_BYTES: 31725 ================================================================================================ --- doc_id: DOC-09 title: Konnaxion Backup, Restore & Rollback project: Konnaxion app_version: v14 param_version: kx-param-2026.04.30 status: draft owner: Konnaxion Architecture last_updated: 2026-04-30 depends_on: - DOC-00_Konnaxion_Canonical_Variables.md - DOC-02_Konnaxion_Capsule_Architecture.md - DOC-03_Konnaxion_Capsule_Format.md - DOC-04_Konnaxion_Manager_Architecture.md - DOC-05_Konnaxion_Agent_Security_Model.md - DOC-06_Konnaxion_Network_Profiles.md - DOC-07_Konnaxion_Security_Gate.md - DOC-08_Konnaxion_Runtime_Docker_Compose.md related_docs: - DOC-11_Konnaxion_Box_Appliance_Image.md - DOC-12_Konnaxion_Install_Runbook.md - DOC-14_Konnaxion_Operator_Guide.md --- # DOC-09 — Konnaxion Backup, Restore & Rollback ## 1. Purpose This document defines the canonical backup, restore and rollback model for **Konnaxion Capsule Manager**, **Konnaxion Agent**, **Konnaxion Instance** and **Konnaxion Box**. The goal is to make recovery safe, repeatable and plug-and-play while preserving the core security principle: ```text Never preserve malware. Never restore unverified system state. Never mix capsule code with instance data. ``` This document is written for the target architecture: ```text Konnaxion Capsule = immutable application package Konnaxion Instance = data, secrets, media, logs, backups and runtime state ``` Backup, restore and rollback are not generic file copy operations. They are controlled lifecycle operations executed by **Konnaxion Agent** and presented through **Konnaxion Capsule Manager**. --- ## 2. Scope This document covers: ```text PostgreSQL backups media/uploads backups instance configuration backups secret backup policy capsule rollback instance rollback database restore media restore restore into new instance health validation after restore automatic rollback after failed update backup retention backup verification disaster recovery ``` This document does **not** cover: ```text full disk cloning forensic imaging provider-level snapshot implementation details CI/CD build pipeline internals external database provider backups manual incident response beyond restore safety arbitrary host migration arbitrary Docker volume migration ``` --- ## 3. Canonical Terms | Term | Meaning | |---|---| | `Konnaxion Capsule` | Signed `.kxcap` file containing application images, manifest, profiles and templates. | | `Konnaxion Instance` | Installed runtime state: database, media, logs, secrets and backups. | | `Konnaxion Capsule Manager` | User-facing app that imports capsules, starts/stops instances and manages network mode. | | `Konnaxion Agent` | Local privileged service that performs controlled system actions. | | `Konnaxion Box` | Dedicated plug-and-play host machine. | | `Backup Set` | One complete backup unit with manifest, database dump, media archive, metadata and checksums. | | `Restore Plan` | The validated procedure generated before applying a restore. | | `Rollback` | Returning to the previous known-good capsule, database snapshot or instance state. | | `Preflight` | Safety validation before backup, restore or rollback. | | `Postflight` | Health validation after backup, restore or rollback. | --- ## 4. Canonical Paths All new documentation must use these target paths. ```text /opt/konnaxion/ ├── capsules/ ├── instances/ ├── manager/ ├── agent/ ├── shared/ ├── releases/ └── backups/ ``` Instance layout: ```text /opt/konnaxion/instances// ├── env/ ├── postgres/ ├── redis/ ├── media/ ├── logs/ ├── backups/ └── state/ ``` Canonical backup storage: ```text /opt/konnaxion/backups/ └── / ├── daily/ ├── weekly/ ├── monthly/ ├── pre-update/ ├── pre-restore/ └── manual/ ``` Canonical example: ```text /opt/konnaxion/backups/demo-001/daily/20260430_230000/ ``` ### 4.1 Global Backup Path vs Instance Backup Path The canonical backup repository is: ```text /opt/konnaxion/backups// ``` The instance-local backup directory is reserved for local pointers, state, restore markers or temporary Agent work files: ```text /opt/konnaxion/instances//backups/ ``` Rules: ```text Do store durable backup sets under /opt/konnaxion/backups//. Do not treat /opt/konnaxion/instances//backups/ as the durable backup repository. Do not duplicate large backup archives in both paths unless an explicit cache policy exists. ``` --- ## 5. Backup Policy ### 5.1 Backup Classes Konnaxion defines six canonical backup classes. | Class | Trigger | Purpose | |---|---|---| | `daily` | Automatic schedule | Routine recovery point | | `weekly` | Automatic schedule | Longer retention recovery point | | `monthly` | Automatic schedule | Archive-grade recovery point | | `pre-update` | Before capsule update | Rollback before applying new capsule | | `pre-restore` | Before restore | Safety backup before overwriting current state | | `manual` | User action | Operator-controlled snapshot | The Konnaxion Agent must expose backup creation through the canonical CLI and Manager UI: ```bash kx instance backup --class daily kx instance backup --class pre-update kx instance backup --class manual ``` ### 5.2 Backup Variables The following variables are canonical for DOC-09 and should be mirrored in `DOC-00_Konnaxion_Canonical_Variables.md`. ```env KX_BACKUP_ENABLED=true KX_BACKUP_ROOT=/opt/konnaxion/backups KX_BACKUP_RETENTION_DAYS=14 KX_DAILY_BACKUP_RETENTION_DAYS=14 KX_WEEKLY_BACKUP_RETENTION_WEEKS=8 KX_MONTHLY_BACKUP_RETENTION_MONTHS=12 KX_PRE_UPDATE_BACKUP_RETENTION_COUNT=5 KX_PRE_RESTORE_BACKUP_RETENTION_COUNT=5 ``` Internal Agent variables used in implementation examples: ```env KX_COMPOSE_FILE= KX_BACKUP_DIR= KX_HOST= ``` These internal variables are not intended for manual operator configuration. ### 5.3 Default Retention Default retention: ```text daily backups: 14 days weekly backups: 8 weeks monthly backups: 12 months pre-update backups: last 5 pre-restore backups: last 5 ``` For demo-only deployments, the Manager may reduce retention, but it must never disable backups silently. ### 5.4 Default Schedule Canonical automatic schedule: ```text daily backup: 03:00 local time weekly backup: Sunday 03:30 local time monthly backup: first day of month 04:00 local time ``` For offline/intranet environments, schedule must not depend on external services. --- ## 6. What Must Be Backed Up A Konnaxion backup set must include: ```text PostgreSQL logical dump media/uploads directory instance manifest snapshot network profile snapshot capsule reference environment template reference redacted environment metadata backup manifest checksums healthcheck result Manager/Agent version metadata ``` ### 6.1 PostgreSQL Canonical database backup format: ```text logical dump compressed or externally compressed checksummed restorable into a clean Postgres volume ``` Preferred command pattern inside the controlled Agent: ```bash docker compose -f "$KX_COMPOSE_FILE" exec -T postgres \ pg_dump -U "$POSTGRES_USER" -d "$POSTGRES_DB" \ --format=custom \ --no-owner \ --no-acl \ > "$KX_BACKUP_DIR/postgres.dump" ``` The custom format is preferred because it supports stronger restore workflows with `pg_restore`. ### 6.2 Media Media files must be backed up separately from the database. Canonical path: ```text /opt/konnaxion/instances//media/ ``` Backup target: ```text /media.tar.zst ``` Preferred command pattern: ```bash tar -C "/opt/konnaxion/instances/$KX_INSTANCE_ID" \ -cf - media \ | zstd -T0 -o "$KX_BACKUP_DIR/media.tar.zst" ``` ### 6.3 Instance Metadata Each backup must include: ```text instance.json capsule.json network-profile.json security-gate.json healthcheck.json versions.json ``` These files are used to verify compatibility before restore. ### 6.4 Environment Metadata The backup may include **redacted** environment metadata. Allowed: ```text variable names whether required values exist hashes/fingerprints of values profile-derived hostnames non-secret feature flags ``` Forbidden: ```text DJANGO_SECRET_KEY plaintext POSTGRES_PASSWORD plaintext DATABASE_URL plaintext API keys tokens private keys SSH keys full .env files with secrets ``` --- ## 7. What Must Never Be Backed Up For Normal Restore Normal Konnaxion backups must not include: ```text entire disk images /tmp /dev/shm system crontabs user crontabs unknown systemd services old authorized_keys old sudoers files unknown Docker volumes Docker daemon state Docker socket unverified binaries malware cleanup quarantine folders provider-level snapshots from compromised hosts ``` This rule exists because a compromised host can contain persistence outside the application directory. Konnaxion restore must recover the application and data, not the attacker’s persistence. --- ## 8. Backup Set Structure Each backup set must use this structure: ```text / ├── backup-manifest.yaml ├── postgres.dump ├── media.tar.zst ├── instance.json ├── capsule.json ├── network-profile.json ├── security-gate.json ├── healthcheck-before.json ├── checksums.sha256 ├── restore-plan.template.yaml └── logs/ ├── backup.log └── verification.log ``` Example: ```text /opt/konnaxion/backups/demo-001/daily/20260430_230000/ ├── backup-manifest.yaml ├── postgres.dump ├── media.tar.zst ├── instance.json ├── capsule.json ├── network-profile.json ├── security-gate.json ├── healthcheck-before.json ├── checksums.sha256 └── logs/ ``` --- ## 9. Backup Manifest Schema Canonical `backup-manifest.yaml`: ```yaml schema_version: kx-backup-manifest-v1 backup_id: demo-001_20260430_230000_daily created_at: "2026-04-30T23:00:00-04:00" backup_class: daily instance: kx_instance_id: demo-001 kx_app_version: v14 kx_capsule_id: konnaxion-v14-demo-2026.04.30 kx_capsule_version: 2026.04.30-demo.1 kx_param_version: kx-param-2026.04.30 environment: kx_network_profile: intranet_private kx_exposure_mode: private public_mode_enabled: false contents: postgres_dump: postgres.dump media_archive: media.tar.zst instance_metadata: instance.json capsule_metadata: capsule.json network_profile: network-profile.json security_gate: security-gate.json database: engine: postgres dump_format: custom logical_backup: true security: secrets_included: false full_disk_backup: false contains_tmp: false contains_crontabs: false contains_authorized_keys: false contains_sudoers: false contains_docker_socket: false verification: checksum_file: checksums.sha256 backup_verified: true restore_tested: false notes: "" ``` --- ## 10. Backup Preflight Before any backup, the Konnaxion Agent must run: ```bash kx security check kx instance status ``` The Agent also runs an internal backup preflight operation. This operation may be logged as: ```text backup_preflight ``` It should not be required as a public operator command. Preflight checks: ```text instance exists instance state is running or stopped Docker services are known Postgres service is reachable media path exists backup target is writable available disk space is sufficient capsule reference exists network profile is known Security Gate is not FAIL_BLOCKING no unknown containers are attached to Konnaxion network no forbidden paths are included in backup plan ``` If preflight fails, the backup must return: ```text FAIL_BLOCKING ``` and no partial backup should be promoted to a valid backup set. --- ## 11. Backup Postflight After backup, the Agent must verify: ```text postgres.dump exists media archive exists or is explicitly empty manifest exists checksums file exists checksums match backup size is non-zero unless instance is empty backup log contains no secrets backup set is marked verified ``` Postflight status values: ```text PASS WARN FAIL_BLOCKING ``` A backup set is valid only when: ```text backup-manifest.yaml exists checksums.sha256 exists verification.backup_verified=true postflight status is PASS ``` --- ## 12. Restore Policy Restore must be deliberate, reversible and validated. Before any restore, the Manager must: ```text show the source backup show the target instance show what will be overwritten create a pre-restore backup of current state run restore preflight require explicit confirmation stop affected services restore database and media run migrations if needed run Security Gate run healthchecks restart services ``` The Manager must not restore directly over an instance without first creating a `pre-restore` backup, unless the instance is already marked `failed` and no recoverable state exists. --- ## 13. Restore Types ### 13.1 Full Instance Restore Restores: ```text PostgreSQL media/uploads instance metadata network profile capsule reference if compatible ``` Command: ```bash kx instance restore \ --from \ --mode full ``` ### 13.2 Database-Only Restore Restores: ```text PostgreSQL only ``` Command: ```bash kx instance restore \ --from \ --mode database-only ``` ### 13.3 Media-Only Restore Restores: ```text media/uploads only ``` Command: ```bash kx instance restore \ --from \ --mode media-only ``` ### 13.4 Restore Into New Instance Preferred for high-risk recovery: ```bash kx instance restore-new \ --from \ --new-instance-id demo-restore-001 \ --network local_only ``` This is the safest method because it preserves the original instance and allows validation before switch-over. --- ## 14. Restore Preflight Restore preflight must verify: ```text backup manifest exists backup checksums match backup was verified backup does not include forbidden paths target instance exists or new target path is clean target has enough disk space target capsule compatibility is acceptable target profile is allowed Postgres service can be recreated media path can be restored Security Gate policy can be enforced ``` Compatibility rules: ```text same APP_VERSION: allowed newer patch capsule: allowed after migration plan older capsule: warn or block depending on migration history different PARAM_VERSION: require compatibility check different schema major version: block unless migration adapter exists ``` ### 14.1 Restore Network Profile Rules Restore must be private by default. ```text Restore into local_only: safest default for validation and test restore Restore into intranet_private: allowed after Security Gate PASS Restore into private_tunnel: allowed only after tunnel configuration validation Restore into public_temporary: must not automatically enable public exposure requires new explicit temporary access request Restore into public_vps: requires explicit approval, firewall PASS and public_vps policy PASS ``` A backup restore must not silently re-enable public exposure, even if the source backup was created while public mode was active. --- ## 15. Restore Procedure — Existing Instance Canonical sequence: ```text 1. Set instance state to restoring. 2. Create pre-restore backup. 3. Stop frontend-next, django-api, celeryworker, celerybeat. 4. Keep postgres available for dump or stop/recreate depending on restore mode. 5. Verify backup checksums. 6. Restore database. 7. Restore media. 8. Run migrations. 9. Run collectstatic if required. 10. Run Security Gate. 11. Start services. 12. Run healthchecks. 13. Mark instance running if checks pass. 14. Mark instance degraded or failed if checks fail. ``` Operator command pattern: ```bash kx instance backup --class pre-restore kx instance restore \ --from \ --mode full kx security check kx instance health ``` Stopping individual services is an internal Agent operation, not a normal operator command. --- ## 16. PostgreSQL Restore Procedure For a full database restore, the Agent should use a clean database target. Canonical pattern: ```bash docker compose -f "$KX_COMPOSE_FILE" exec -T postgres \ dropdb -U "$POSTGRES_USER" "$POSTGRES_DB" docker compose -f "$KX_COMPOSE_FILE" exec -T postgres \ createdb -U "$POSTGRES_USER" "$POSTGRES_DB" cat "$KX_BACKUP_DIR/postgres.dump" | docker compose -f "$KX_COMPOSE_FILE" exec -T postgres \ pg_restore -U "$POSTGRES_USER" -d "$POSTGRES_DB" \ --no-owner \ --no-acl \ --clean \ --if-exists ``` If the restore is into a brand-new Postgres volume, `--clean --if-exists` may be omitted. After restore: ```bash docker compose -f "$KX_COMPOSE_FILE" run --rm django-api \ python manage.py migrate docker compose -f "$KX_COMPOSE_FILE" run --rm django-api \ python manage.py check --deploy ``` If the implementation-specific Compose service name differs from `django-api`, the Agent must map it internally. Documentation must continue to use the canonical service name `django-api`. --- ## 17. Media Restore Procedure Media restore must not blindly merge unknown files into the existing media directory. Preferred pattern: ```text 1. Move current media to media.previous.. 2. Extract media archive into a new clean media directory. 3. Set correct ownership and permissions. 4. Verify expected paths. 5. Keep previous media until postflight passes. ``` Command pattern: ```bash INSTANCE_DIR="/opt/konnaxion/instances/$KX_INSTANCE_ID" TS="$(date +%Y%m%d_%H%M%S)" mv "$INSTANCE_DIR/media" "$INSTANCE_DIR/media.previous.$TS" mkdir -p "$INSTANCE_DIR/media" zstd -dc "$KX_BACKUP_DIR/media.tar.zst" \ | tar -C "$INSTANCE_DIR" -xf - ``` Permission repair is an internal Agent operation. It may be logged as: ```text fix_permissions ``` It should not be required as a public operator command. If postflight fails, restore the previous media directory: ```bash rm -rf "$INSTANCE_DIR/media" mv "$INSTANCE_DIR/media.previous.$TS" "$INSTANCE_DIR/media" ``` --- ## 18. Rollback Policy Rollback has three levels: | Level | Name | What changes | |---|---|---| | 1 | Capsule rollback | Repoints instance to previous capsule/release | | 2 | Data rollback | Restores database/media backup | | 3 | Full instance rollback | Restores capsule reference + database + media | Default rollback after failed update: ```text capsule rollback first data rollback only if migrations or data writes changed state ``` The Manager must not automatically roll back data unless the update process marked the database as changed. --- ## 19. Capsule Rollback Capsule rollback returns to the previous known-good `.kxcap`. Canonical release links: ```text /opt/konnaxion/instances//state/current-capsule /opt/konnaxion/instances//state/previous-capsule ``` Command: ```bash kx instance rollback --level capsule ``` Procedure: ```text 1. Stop application services. 2. Repoint current-capsule to previous-capsule. 3. Recreate containers from previous capsule. 4. Do not modify database unless required. 5. Run Security Gate. 6. Run healthchecks. 7. Mark running or degraded. ``` --- ## 20. Data Rollback Data rollback restores a backup set. Command: ```bash kx instance rollback \ --level data \ --from ``` Procedure: ```text 1. Create pre-rollback backup. 2. Stop write-capable services. 3. Restore database. 4. Restore media if included. 5. Run migrations only if required by selected capsule. 6. Run Security Gate. 7. Run healthchecks. ``` --- ## 21. Full Instance Rollback Full rollback combines capsule rollback and data rollback. Command: ```bash kx instance rollback \ --level full \ --from ``` Use this only when: ```text capsule update failed database migration changed schema/data media changed during failed update simple capsule rollback did not recover the instance ``` --- ## 22. Update With Automatic Rollback Every capsule update must follow this safe sequence: ```text 1. Verify new capsule signature. 2. Create pre-update backup. 3. Stop write-heavy services if needed. 4. Apply new capsule. 5. Start services. 6. Run migrations. 7. Run Security Gate. 8. Run healthchecks. 9. If PASS, mark new capsule current. 10. If FAIL_BLOCKING, rollback to previous capsule. 11. If database changed, request or execute data rollback according to policy. ``` Canonical command: ```bash kx instance update \ --capsule konnaxion-v14-demo-2026.05.01.kxcap \ --auto-rollback true ``` --- ## 23. Healthchecks After Restore or Rollback Post-restore healthchecks: ```text Traefik responds frontend route responds /api/ responds /admin/ responds /media/ responds if media exists Django migrate state is clean Django check passes Celery worker is running Celery beat is running if enabled Redis is reachable only internally Postgres is reachable only internally dangerous ports are not public ``` Command pattern: ```bash kx instance health kx security check ``` Minimum HTTP checks: ```bash curl -I https:/// curl -I https:///api/ curl -I https:///admin/ ``` For local/intranet mode, `` may be: ```text localhost konnaxion.local konnaxion.lan private tailnet hostname ``` --- ## 24. Security Gate Requirements Backup, restore and rollback must integrate with Security Gate. Required blocking checks: ```text capsule_signature image_checksums manifest_schema secrets_present secrets_not_default firewall_enabled dangerous_ports_blocked postgres_not_public redis_not_public docker_socket_not_mounted no_privileged_containers no_host_network allowed_images_only admin_surface_private backup_configured ``` If any critical check returns `FAIL_BLOCKING`, the Manager must not mark the restore as successful. --- ## 25. Backup Verification Backups are not valid until verified. Verification steps: ```text checksum verification manifest validation postgres dump header check media archive listing check forbidden path check secret leak scan minimum size sanity check optional restore-test into temporary instance ``` Command: ```bash kx backup verify ``` Optional restore test: ```bash kx backup test-restore \ --temporary-instance restore-test-$(date +%Y%m%d_%H%M%S) \ --network local_only \ --destroy-after-pass ``` --- ## 26. Secret Leak Scan Backup verification must scan for high-risk patterns. Block backup promotion if plaintext matches likely secrets: ```text DJANGO_SECRET_KEY= POSTGRES_PASSWORD= DATABASE_URL= PRIVATE KEY BEGIN OPENSSH PRIVATE KEY AWS_SECRET_ACCESS_KEY API_KEY= TOKEN= ``` Allowed exception: ```text redacted variable metadata empty placeholders template examples ``` If a backup contains leaked secrets, status must be: ```text FAIL_BLOCKING ``` and the operator must rotate affected secrets. --- ## 27. Disaster Recovery Model For a lost Konnaxion Box or VPS: ```text 1. Install clean host. 2. Install Konnaxion Capsule Manager. 3. Import trusted capsule. 4. Import verified backup set. 5. Restore into new instance. 6. Generate new host-level secrets if required. 7. Apply safe network profile. 8. Run Security Gate. 9. Run healthchecks. 10. Only then expose to intranet/tunnel/public profile. ``` Command pattern: ```bash kx capsule import konnaxion-v14-demo-2026.04.30.kxcap kx instance restore-new \ --from demo-001_20260430_230000_daily \ --new-instance-id demo-001-restored \ --network intranet_private kx security check demo-001-restored kx instance health demo-001-restored ``` --- ## 28. Incident Recovery Rule If the host is suspected compromised, do **not** use ordinary rollback as the final fix. Use: ```text clean host trusted capsule verified DB dump verified media backup rotated secrets new SSH keys new firewall policy Security Gate PASS ``` Do not restore: ```text old disk image old Docker daemon state old system users old crontabs old sudoers old authorized_keys old /tmp or /dev/shm old unknown containers ``` The safe recovery unit is: ```text clean capsule + verified application data ``` not: ```text old server state ``` --- ## 29. Manager UI Requirements The Konnaxion Capsule Manager must expose backup/restore in a plug-and-play way. Main backup screen: ```text Backups Instance: demo-001 Status: running Last backup: 2026-04-30 23:00 Backup health: PASS Retention: 14 daily / 8 weekly / 12 monthly [Create Backup] [Restore] [Test Restore] [Download Backup] ``` Restore screen: ```text Restore Konnaxion Instance Source backup: demo-001_20260430_230000_daily Target: demo-001 This will restore: [x] Database [x] Media [ ] Network profile [ ] Capsule version Safety: [x] Create pre-restore backup first [x] Run Security Gate after restore [x] Keep rollback point [Restore] ``` Danger confirmation text: ```text RESTORE demo-001 ``` --- ## 30. CLI Requirements ### 30.1 Public Operator CLI Canonical operator-facing commands: ```bash kx instance backup kx instance backup --class manual kx backup list kx backup verify kx backup test-restore kx instance restore --from kx instance restore-new --from --new-instance-id kx instance health kx instance rollback --level capsule kx instance rollback --level data --from kx instance rollback --level full --from ``` The following commands should be added to the canonical CLI section of `DOC-00_Konnaxion_Canonical_Variables.md` if accepted: ```bash kx backup list kx backup verify kx backup test-restore kx instance restore-new kx instance health ``` ### 30.2 Internal Agent Operations The following are internal Agent operations, not normal public CLI commands: ```text backup_preflight restore_preflight restore_postflight stop_selected_services start_selected_services fix_permissions verify_forbidden_paths scan_backup_for_secret_leaks ``` Implementations may expose debug/admin forms of these operations later, but they must not be required for normal plug-and-play operation. --- ## 31. Resource Status Values The statuses below are **resource-specific statuses**, not canonical `Konnaxion Instance` states. Canonical instance states remain defined in `DOC-00_Konnaxion_Canonical_Variables.md`. ### 31.1 Backup Statuses ```text created running verifying verified failed expired deleted quarantined ``` ### 31.2 Restore Statuses ```text planned preflight creating_pre_restore_backup restoring_database restoring_media running_migrations running_security_gate running_healthchecks restored degraded failed rolled_back ``` ### 31.3 Rollback Statuses ```text planned running capsule_repointed data_restored healthchecking completed failed ``` These statuses should be mirrored in `DOC-00_Konnaxion_Canonical_Variables.md` if they become canonical across the full documentation set. --- ## 32. Failure Handling If backup fails: ```text do not mark backup as valid keep logs delete incomplete dump unless debugging enabled return FAIL_BLOCKING if backup was required before update ``` If restore fails before database overwrite: ```text abort restore keep current instance unchanged mark restore failed ``` If restore fails after database overwrite: ```text attempt restore from pre-restore backup keep failed backup logs mark instance degraded or failed ``` If rollback fails: ```text stop public exposure switch to safest private profile keep services stopped if integrity is unknown show recovery instructions ``` --- ## 33. File Naming Backup ID format: ```text __ ``` Examples: ```text demo-001_20260430_230000_daily demo-001_20260430_173000_pre-update demo-001_20260430_181500_manual ``` Archive file naming: ```text postgres.dump media.tar.zst checksums.sha256 backup-manifest.yaml ``` --- ## 34. Minimum Acceptance Criteria A DOC-09-compliant backup system must satisfy: ```text Can create a verified Postgres dump. Can backup media separately. Can generate backup-manifest.yaml. Can verify checksums. Can reject forbidden paths. Can scan for leaked secrets. Can restore into a new instance. Can create pre-update backup. Can perform capsule rollback. Can block restore if Security Gate fails. Can show simple Manager UI state. ``` --- ## 35. MVP Implementation Plan ### Phase 1 — Manual-safe backups ```text kx instance backup kx backup list kx backup verify Postgres dump media archive backup manifest checksums ``` ### Phase 2 — Restore into new instance ```text kx instance restore-new local_only restore tests healthchecks Security Gate integration ``` ### Phase 3 — Update rollback ```text pre-update backup capsule rollback automatic rollback on healthcheck failure ``` ### Phase 4 — Manager UI ```text backup status page restore wizard test restore button rollback button ``` ### Phase 5 — Hardened disaster recovery ```text off-host backup export encrypted backup support scheduled backup alerts restore drills ``` --- ## 36. Open Decisions | Decision | Default for now | |---|---| | Backup encryption | Required later; not required for MVP if backups stay local and protected. | | Offsite backup provider | Not fixed; must support offline/intranet use. | | Backup compression | `zstd` preferred. | | Postgres dump format | `custom` preferred. | | Restore into same instance | Supported, but restore-new is safer. | | Public demo backup behavior | Same as private; no secrets in backup. | | Automatic data rollback | Only if update marks database as changed. | | Canonical backup CLI location | Add runtime backup commands to DOC-00; keep DOC-10 builder-only unless CLI scope changes. | --- ## 37. Cross-Document Updates Required To make this document fully canonical, update the following files: ```text DOC-00_Konnaxion_Canonical_Variables.md Add backup variables, backup path convention, backup/restore/rollback statuses, and accepted runtime backup CLI commands. DOC-05_Konnaxion_Agent_Security_Model.md Add backup/restore/rollback to the Agent allowlist and forbidden restore list. DOC-06_Konnaxion_Network_Profiles.md Add restore behavior by network profile. DOC-14_Konnaxion_Operator_Guide.md Add operator backup, restore, verify and rollback workflows. DOC-12_Konnaxion_Install_Runbook.md Add backup directory setup and first backup verification. DOC-11_Konnaxion_Box_Appliance_Image.md Add appliance-level backup storage, restore and factory reset behavior. ``` `DOC-10_Konnaxion_Builder_CLI.md` should only change if the project decides that DOC-10 documents all CLI commands. If DOC-10 remains builder-only, backup CLI should be documented in DOC-00, DOC-09 and DOC-14 instead. --- ## 38. Canonical Summary ```text Konnaxion backup protects application data, not the host. Konnaxion restore rebuilds into a trusted runtime, not an old system image. Konnaxion rollback first reverts capsule code, then data only when necessary. Konnaxion Manager must make backup/restore plug-and-play. Konnaxion Agent must enforce safety rules and block dangerous restores. ``` ================================================================================================ FILE: docs/DOC-10_Konnaxion_Builder_CLI.md AUTHORITY: reference CONTENT_ROLE: knowledge CONTENT_SHA256: abad2df0bc7dfef67b5dc8fc1b9f0ad2a2c4cc67abc76c7337f4919199ee744c CONTENT_BYTES: 48385 ================================================================================================ doc_id: DOC-10 title: Konnaxion Builder CLI project: Konnaxion app_version: v14 param_version: kx-param-2026.04.30 status: canonical-draft owner: Konnaxion last_updated: 2026-05-02 depends_on: - DOC-00_Konnaxion_Canonical_Variables.md - DOC-03_Konnaxion_Capsule_Format.md - DOC-07_Konnaxion_Security_Gate.md - DOC-08_Konnaxion_Runtime_Docker_Compose.md - DOC-16_Konnaxion_Manager_GUI_Technical_Contract.md - DOC-18_Konnaxion_GUI_Target_Modes.md --- # DOC-10 — Konnaxion Builder CLI ## 0. Purpose This document defines the canonical command-line interface for building, verifying, exporting, and inspecting a `Konnaxion Capsule`. The canonical public CLI command is: ```bash kx ```` The current implementation may also expose this compatibility executable: ```bash kx-builder ``` Documentation should prefer: ```bash kx capsule ``` Implementation and development examples may use: ```bash uv run kx-builder capsule ``` The Builder CLI must produce portable, signed `.kxcap` files that can be imported by the `Konnaxion Capsule Manager` and executed through the `Konnaxion Agent` without manual image loading, manual runtime env edits, manual Traefik edits, or tunnel-only behavior. This document depends on: ```text DOC-00_Konnaxion_Canonical_Variables.md DOC-03_Konnaxion_Capsule_Format.md DOC-07_Konnaxion_Security_Gate.md DOC-08_Konnaxion_Runtime_Docker_Compose.md DOC-16_Konnaxion_Manager_GUI_Technical_Contract.md DOC-18_Konnaxion_GUI_Target_Modes.md ``` All naming, paths, profiles, ports, services, instance states, security statuses, image archive names, and variable names must remain aligned with `DOC-00`. Scope boundary: ```text DOC-10 owns build-time capsule commands only. DOC-10 does not own runtime instance commands. DOC-10 does not own backup, restore or rollback commands. DOC-10 does not own live network profile mutation. ``` Runtime operations belong to: ```text Konnaxion Capsule Manager Konnaxion Agent Docker Compose Runtime ``` Backup, restore, rollback, and live runtime operations belong to: ```text DOC-09_Konnaxion_Backup_Restore_Rollback.md DOC-14_Konnaxion_Operator_Guide.md DOC-16_Konnaxion_Manager_GUI_Technical_Contract.md ``` --- ## 1. Scope The Builder CLI is responsible for: ```text Building frontend and backend release artifacts Building canonical app Docker images Exporting all required runtime images as loadable .oci.tar archives Generating manifest.yaml Generating docker-compose.capsule.yml Injecting canonical profiles Generating env templates Generating healthcheck templates Validating capsule structure Running build-time security checks Generating checksums Signing the capsule Producing a .kxcap file Verifying an existing .kxcap file Inspecting capsule metadata ``` The Builder CLI is not responsible for: ```text Running a production instance Managing live network profiles Opening or closing firewall ports Creating local users Running long-lived services Hosting Konnaxion Managing runtime backups Verifying runtime backup sets Restoring runtime data Rolling back live instances Running live healthchecks Changing active network exposure Replacing the Konnaxion Capsule Manager Replacing the Konnaxion Agent ``` Runtime actions are handled by: ```text Konnaxion Capsule Manager Konnaxion Agent Docker Compose Runtime ``` --- ## 2. Canonical CLI Name The canonical public CLI executable is: ```bash kx ``` The Builder functionality lives under: ```bash kx capsule kx build ``` The preferred public command group is: ```bash kx capsule ``` The `kx build` group may exist as a convenience alias, but documentation should primarily use `kx capsule`. The development executable may be: ```bash kx-builder ``` The compatibility mapping is: | Public command | Implementation-compatible command | | ---------------------------- | ------------------------------------ | | `kx capsule build` | `kx-builder capsule build` | | `kx capsule verify` | `kx-builder capsule verify` | | `kx capsule inspect` | `kx-builder capsule inspect` | | `kx capsule list-profiles` | `kx-builder capsule list-profiles` | | `kx capsule export-manifest` | `kx-builder capsule export-manifest` | --- ## 3. Canonical Builder Commands ## 3.1 Capsule Commands ```bash kx capsule build kx capsule verify kx capsule inspect kx capsule list-profiles kx capsule export-manifest ``` ## 3.2 Optional Developer Commands ```bash kx capsule clean kx capsule doctor kx capsule schema kx capsule sign kx capsule checksum ``` ## 3.3 Runtime Commands Mentioned for Alignment Only The Builder CLI may reference runtime commands only to explain the handoff between a built capsule and a running instance. These commands are not owned by DOC-10: ```bash kx capsule import kx instance create kx instance start kx instance stop kx instance status kx instance logs kx instance backup kx instance restore kx instance update kx instance rollback kx instance restore-new kx instance health kx backup list kx backup verify kx backup test-restore kx security check kx network set-profile ``` Ownership: | Command group | Owning document | | ---------------------------- | --------------------------------------------------------------------------------------- | | `kx capsule build` | `DOC-10_Konnaxion_Builder_CLI.md` | | `kx capsule verify` | `DOC-10_Konnaxion_Builder_CLI.md` | | `kx capsule inspect` | `DOC-10_Konnaxion_Builder_CLI.md` | | `kx capsule list-profiles` | `DOC-10_Konnaxion_Builder_CLI.md` | | `kx capsule export-manifest` | `DOC-10_Konnaxion_Builder_CLI.md` | | `kx capsule import` | `DOC-04_Konnaxion_Manager_Architecture.md` / `DOC-05_Konnaxion_Agent_Security_Model.md` | | `kx instance *` | `DOC-04_Konnaxion_Manager_Architecture.md` / `DOC-05_Konnaxion_Agent_Security_Model.md` | | `kx backup *` | `DOC-09_Konnaxion_Backup_Restore_Rollback.md` | | `kx security check` | `DOC-07_Konnaxion_Security_Gate.md` | | `kx network set-profile` | `DOC-06_Konnaxion_Network_Profiles.md` | DOC-10 must not become the canonical reference for runtime operations. --- ## 3.4 Namespace Ownership Rule The `kx` executable is shared across Builder, Manager and Agent workflows, but ownership is split by command namespace. DOC-10 owns only these public command namespaces: ```bash kx capsule build kx capsule verify kx capsule inspect kx capsule list-profiles kx capsule export-manifest kx capsule doctor ``` DOC-10 may define developer convenience commands: ```bash kx capsule clean kx capsule schema kx capsule sign kx capsule checksum ``` DOC-10 must not define behavior for live runtime commands such as: ```bash kx instance backup kx instance restore kx instance rollback kx backup verify kx backup test-restore kx network set-profile ``` Those commands are intentionally delegated to runtime documents because they operate on a `Konnaxion Instance`, not on a static `.kxcap` file. --- ## 4. Canonical Build Output A successful build must output one `.kxcap` file. Canonical filename pattern: ```text konnaxion-v14-demo-YYYY.MM.DD.kxcap ``` Example: ```text konnaxion-v14-demo-2026.04.30.kxcap ``` Canonical output directory: ```text ./dist/capsules/ ``` Example: ```text ./dist/capsules/konnaxion-v14-demo-2026.04.30.kxcap ``` Development or GUI integration may write capsules to: ```text ./runtime/capsules/ ``` Example: ```text ./runtime/capsules/konnaxion-v14-demo-2026.05.02.kxcap ``` --- ## 5. Canonical Capsule Structure The Builder CLI must produce a `.kxcap` archive using this structure: ```text .kxcap ├── manifest.yaml ├── docker-compose.capsule.yml ├── images.yaml ├── images/ │ ├── frontend-next.oci.tar │ ├── django-api.oci.tar │ ├── traefik.oci.tar │ ├── postgres.oci.tar │ ├── redis.oci.tar │ ├── celeryworker.oci.tar │ ├── celerybeat.oci.tar │ └── media-nginx.oci.tar ├── profiles/ │ ├── local_only.yaml │ ├── intranet_private.yaml │ ├── private_tunnel.yaml │ ├── public_temporary.yaml │ ├── public_vps.yaml │ └── offline.yaml ├── env-templates/ │ ├── django.env.template │ ├── postgres.env.template │ ├── redis.env.template │ └── frontend.env.template ├── migrations/ ├── seed-data/ ├── healthchecks/ │ └── capsule-healthcheck.json ├── policies/ │ └── capsule-policy.json ├── metadata/ │ ├── build.json │ └── source-inventory.json ├── checksums.txt └── signature.sig ``` Optional private-only service archive: ```text images/flower.oci.tar ``` The Builder must fail if the generated capsule structure does not match the canonical format. The Builder must never produce a deployable-looking capsule whose `images/` directory contains only: ```text images/README.json ``` That state is invalid because the Droplet runtime cannot start private app images without offline-loadable image archives. --- ## 6. Canonical Services Built or Exported by the CLI The Builder must use canonical service names defined by `DOC-00`. | Service | Builder Responsibility | | --------------- | ------------------------------------------------------------------------------------------------ | | `frontend-next` | Build Next.js production frontend image and export as `frontend-next.oci.tar` | | `django-api` | Build Django/Gunicorn backend image and export as `django-api.oci.tar` | | `traefik` | Pull/include approved Traefik image and export as `traefik.oci.tar` | | `media-nginx` | Pull/include approved media/static image and export as `media-nginx.oci.tar` | | `postgres` | Pull/include approved upstream image and export as `postgres.oci.tar`; no custom secret baked in | | `redis` | Pull/include approved upstream image and export as `redis.oci.tar`; no custom secret baked in | | `celeryworker` | Reuse the `django-api` image and export a canonical `celeryworker.oci.tar` service archive | | `celerybeat` | Reuse the `django-api` image and export a canonical `celerybeat.oci.tar` service archive | | `flower` | Private-only optional service; may reuse the `django-api` image | | `kx-agent` | Not bundled as an application service unless explicitly approved | The capsule must not include images with non-canonical service names unless the manifest maps them explicitly. --- ## 7. Canonical Image Tags and Archives ## 7.1 App Image Tags The Builder should tag app-built images with capsule-scoped tags: ```text konnaxion/frontend-next:- konnaxion/django-api:- ``` Example: ```text konnaxion/frontend-next:v14-konnaxion-v14-demo-2026.05.02 konnaxion/django-api:v14-konnaxion-v14-demo-2026.05.02 ``` For runtime compose compatibility, the Agent may retag loaded images to: ```text konnaxion/frontend-next:v14 konnaxion/django-api:v14 ``` ## 7.2 External Runtime Images Approved default external images: ```text traefik:v3.1 postgres:16 redis:7 nginx:stable ``` These must be exported into the capsule so a Droplet or offline runtime does not need registry access. ## 7.3 Archive Names Archive names are canonical by service: ```text images/frontend-next.oci.tar images/django-api.oci.tar images/traefik.oci.tar images/postgres.oci.tar images/redis.oci.tar images/celeryworker.oci.tar images/celerybeat.oci.tar images/media-nginx.oci.tar ``` Even when multiple services share the same image tag, each canonical service should have a manifest-visible archive entry. --- ## 8. Frontend Image Contract The Builder must build `frontend-next` as a production runtime image. The runtime image must not require: ```text pnpm download at runtime Corepack download at runtime network access during container start development server command ``` The runtime image must include: ```text package.json node_modules/ .next/ public/ next.config.* env.mjs ``` The runtime command must be equivalent to: ```bash node node_modules/next/dist/bin/next start -H 0.0.0.0 -p 3000 ``` The build stage must set: ```text NODE_OPTIONS=--max-old-space-size=4096 NODE_ENV=production ``` A canonical frontend Dockerfile template is: ```dockerfile FROM node:20-alpine AS builder WORKDIR /app RUN corepack enable COPY package.json pnpm-lock.yaml* ./ RUN pnpm install --no-frozen-lockfile COPY . . ENV NODE_ENV=production ENV NODE_OPTIONS=--max-old-space-size=4096 RUN pnpm build FROM node:20-alpine AS runner WORKDIR /app ENV NODE_ENV=production ENV PORT=3000 ENV HOSTNAME=0.0.0.0 ENV NEXT_TELEMETRY_DISABLED=1 COPY --from=builder /app/package.json ./package.json COPY --from=builder /app/node_modules ./node_modules COPY --from=builder /app/.next ./.next COPY --from=builder /app/public ./public COPY --from=builder /app/next.config.* ./ COPY --from=builder /app/env.mjs ./env.mjs EXPOSE 3000 CMD ["node", "node_modules/next/dist/bin/next", "start", "-H", "0.0.0.0", "-p", "3000"] ``` --- ## 9. Backend Image Contract The Builder must build `django-api` as a production runtime image. The Builder must not allow local virtualenvs, caches, stale generated files, or development artifacts to pollute the Docker build context. The Builder must create or enforce a clean backend build context that excludes: ```text .venv venv env __pycache__ .pytest_cache .mypy_cache .ruff_cache media staticfiles logs *.pyc *.pyo *.pyd *.sqlite3 *.log ``` The Builder must verify the backend context before build. Required sanity checks: ```text backend/konnaxion/ethikos/models.py exists backend/konnaxion/ethikos/models.py must not contain migration-file content backend/konnaxion/ethikos/models.py must contain expected app models production Django Dockerfile exists ``` The Builder must fail if a source file is unexpectedly replaced by migration content, generated content, or an empty placeholder. --- ## 10. Build Pipeline A canonical `kx capsule build` must execute these stages in order: ```text 1. Load build configuration 2. Validate repository layout 3. Validate canonical variables 4. Validate network profiles 5. Prepare clean backend Docker context 6. Build frontend production image 7. Build backend production image 8. Pull or verify approved external runtime images 9. Export all required runtime images as images/*.oci.tar 10. Generate images.yaml 11. Generate docker-compose.capsule.yml 12. Generate manifest.yaml 13. Generate env templates 14. Add profiles 15. Add migrations and optional seed data 16. Generate healthcheck templates 17. Run build-time tests and static checks 18. Run build-time security checks 19. Generate checksums.txt 20. Sign capsule 21. Verify finished capsule 22. Write .kxcap to output path ``` If any critical stage fails, the Builder must stop and return a non-zero exit code. The Builder must not sign a capsule until image archives and checksums are complete. --- ## 11. Command: `kx capsule build` ## 11.1 Purpose Build a new signed `Konnaxion Capsule`. ## 11.2 Canonical Syntax ```bash kx capsule build \ --source-dir ./Konnaxion \ --output ./dist/capsules/konnaxion-v14-demo-2026.05.02.kxcap \ --channel demo \ --capsule-id konnaxion-v14-demo-2026.05.02 \ --version 2026.05.02-demo.1 \ --app-version v14 \ --param-version kx-param-2026.04.30 \ --profile public_vps \ --signing-key-file ./runtime/signing/kx-demo-ed25519-private.pem \ --public-key-file ./runtime/signing/kx-demo-ed25519-public.pem \ --force ``` Compatibility form: ```bash uv run kx-builder capsule build \ --source-dir C:\mycode\Konnaxion\Konnaxion \ --output C:\mycode\Konnaxion\runtime\capsules\konnaxion-v14-demo-2026.05.02.kxcap \ --channel demo \ --capsule-id konnaxion-v14-demo-2026.05.02 \ --version 2026.05.02-demo.1 \ --app-version v14 \ --param-version kx-param-2026.04.30 \ --profile public_vps \ --signing-key-file C:\mycode\Konnaxion\runtime\signing\kx-demo-ed25519-private.pem \ --public-key-file C:\mycode\Konnaxion\runtime\signing\kx-demo-ed25519-public.pem \ --force ``` ## 11.3 Common Options | Option | Required | Description | | --------------------- | ---------------------------: | -------------------------------------------------------- | | `--source-dir` | Yes | Source repo root containing `backend/` and `frontend/` | | `--output` | Yes | Output `.kxcap` path | | `--channel` | Yes | Build channel, e.g. `dev`, `demo`, `release`, `ci` | | `--capsule-id` | Yes | Capsule ID, e.g. `konnaxion-v14-demo-2026.05.02` | | `--version` | Yes | Capsule version, e.g. `2026.05.02-demo.1` | | `--app-version` | Yes | Application version, e.g. `v14` | | `--param-version` | Yes | Parameter version, e.g. `kx-param-2026.04.30` | | `--profile` | Yes | Default network profile to embed, e.g. `public_vps` | | `--signing-key-file` | Required except unsigned dev | Private signing key | | `--public-key-file` | Recommended | Public key used for verification metadata | | `--include-seed-data` | No | Include approved seed data | | `--skip-tests` | No | Skip tests; forbidden for release builds | | `--unsigned` | No | Produce unsigned dev capsule; forbidden for demo/release | | `--force` | No | Overwrite existing output | | `--verbose` | No | Detailed logs | | `--json` | No | Machine-readable output | ## 11.4 Example: Demo Capsule ```bash kx capsule build \ --source-dir ./Konnaxion \ --output ./dist/capsules/konnaxion-v14-demo-2026.05.02.kxcap \ --channel demo \ --capsule-id konnaxion-v14-demo-2026.05.02 \ --version 2026.05.02-demo.1 \ --app-version v14 \ --param-version kx-param-2026.04.30 \ --profile public_vps \ --include-seed-data \ --signing-key-file ./runtime/signing/kx-demo-ed25519-private.pem \ --public-key-file ./runtime/signing/kx-demo-ed25519-public.pem \ --force ``` ## 11.5 Example: Release Capsule ```bash kx capsule build \ --source-dir ./Konnaxion \ --output ./dist/capsules/konnaxion-v14-release-2026.05.02.kxcap \ --channel release \ --capsule-id konnaxion-v14-release-2026.05.02 \ --version 2026.05.02-release.1 \ --app-version v14 \ --param-version kx-param-2026.04.30 \ --profile public_vps \ --signing-key-file ./secrets/release-ed25519-private.pem \ --public-key-file ./secrets/release-ed25519-public.pem ``` Release builds must be signed. Release builds must not use: ```text --skip-tests --unsigned ``` Demo builds must be signed unless explicitly configured as development-only. --- ## 12. Command: `kx capsule verify` ## 12.1 Purpose Verify a `.kxcap` file before import, distribution, or installation. ## 12.2 Syntax ```bash kx capsule verify ./dist/capsules/konnaxion-v14-demo-2026.05.02.kxcap ``` Compatibility form: ```bash uv run kx-builder capsule verify C:\mycode\Konnaxion\runtime\capsules\konnaxion-v14-demo-2026.05.02.kxcap ``` ## 12.3 Required Checks The verify command must check: ```text capsule file exists capsule extension is .kxcap manifest.yaml exists manifest schema is valid docker-compose.capsule.yml exists images.yaml exists all required directories exist all required profiles exist all required image archives exist all listed image archives exist all listed image archives use .oci.tar suffix all listed image archives are non-empty all listed image archive checksums match images.yaml checksums.txt exists all checksums match signature.sig exists signature is valid when verifier provided no forbidden secrets are present no forbidden public ports are declared no Docker socket mount is declared no privileged containers are declared no host network mode is declared all service names are canonical or explicitly mapped ``` ## 12.4 Mandatory Image Verification Failure Cases Verification must fail if any of these are true: ```text images/ contains only README.json images.yaml is missing images.yaml has no images manifest declares service images but archive files are absent frontend-next.oci.tar is missing django-api.oci.tar is missing traefik.oci.tar is missing postgres.oci.tar is missing redis.oci.tar is missing celeryworker.oci.tar is missing celerybeat.oci.tar is missing media-nginx.oci.tar is missing any archive checksum does not match any archive is zero bytes ``` A capsule with this structure is invalid: ```text images/ └── README.json ``` The verify command must not report `OK` for that capsule. ## 12.5 Output Human-readable output: ```text Konnaxion Capsule Verification Capsule: konnaxion-v14-demo-2026.05.02.kxcap Status: PASS [PASS] manifest_schema [PASS] image_archives_present [PASS] image_checksums [PASS] capsule_signature [PASS] dangerous_ports_blocked [PASS] docker_socket_not_mounted [PASS] no_privileged_containers [PASS] no_host_network ``` Machine-readable output: ```bash kx capsule verify ./dist/capsules/konnaxion-v14-demo-2026.05.02.kxcap --json ``` Example JSON: ```json { "capsule_id": "konnaxion-v14-demo-2026.05.02", "capsule_version": "2026.05.02-demo.1", "status": "PASS", "checks": [ { "name": "manifest_schema", "status": "PASS" }, { "name": "image_archives_present", "status": "PASS" }, { "name": "capsule_signature", "status": "PASS" } ], "warnings": [], "errors": [] } ``` --- ## 13. Command: `kx capsule inspect` ## 13.1 Purpose Print metadata from a `.kxcap` file without importing it. ## 13.2 Syntax ```bash kx capsule inspect konnaxion-v14-demo-2026.05.02.kxcap ``` ## 13.3 Expected Output ```text Capsule ID: konnaxion-v14-demo-2026.05.02 Capsule Version: 2026.05.02-demo.1 Application Version: v14 Parameter Version: kx-param-2026.04.30 Default Network Profile: public_vps Default Exposure Mode: public Services: - traefik - frontend-next - django-api - postgres - redis - celeryworker - celerybeat - media-nginx Images: - images/traefik.oci.tar - images/frontend-next.oci.tar - images/django-api.oci.tar - images/postgres.oci.tar - images/redis.oci.tar - images/celeryworker.oci.tar - images/celerybeat.oci.tar - images/media-nginx.oci.tar Profiles: - local_only - intranet_private - private_tunnel - public_temporary - public_vps - offline Signed: yes ``` --- ## 14. Command: `kx capsule list-profiles` ## 14.1 Purpose List network profiles embedded in a capsule. ## 14.2 Syntax ```bash kx capsule list-profiles konnaxion-v14-demo-2026.05.02.kxcap ``` ## 14.3 Output ```text local_only intranet_private private_tunnel public_temporary public_vps offline ``` The command must fail if any canonical profile is missing. --- ## 15. Command: `kx capsule export-manifest` ## 15.1 Purpose Extract `manifest.yaml` from a capsule for inspection, auditing, or CI checks. ## 15.2 Syntax ```bash kx capsule export-manifest konnaxion-v14-demo-2026.05.02.kxcap \ --output ./dist/manifests/konnaxion-v14-demo-2026.05.02.manifest.yaml ``` --- ## 16. Command: `kx capsule doctor` ## 16.1 Purpose Check the local build environment. ## 16.2 Syntax ```bash kx capsule doctor ``` ## 16.3 Required Checks ```text Docker available Docker daemon running Docker Compose available Node.js available pnpm available Python available backend source exists frontend source exists backend production Dockerfile exists frontend package.json exists frontend env.mjs exists Git worktree status available sufficient disk space sufficient memory signing key configured for demo/release builds external images pullable or already available ``` Example: ```text Konnaxion Builder Doctor [PASS] docker_available [PASS] docker_daemon_running [PASS] docker_compose_available [PASS] node_available [PASS] pnpm_available [PASS] python_available [PASS] backend_root_exists [PASS] frontend_root_exists [PASS] backend_production_dockerfile_exists [PASS] frontend_env_mjs_exists [WARN] git_worktree_dirty [PASS] signing_key_available ``` A dirty Git worktree may be allowed for development builds but should block release builds unless explicitly overridden. --- ## 17. Build Configuration File The Builder may accept a canonical config file: ```text kxbuild.yaml ``` Example: ```yaml project: Konnaxion app_version: v14 param_version: kx-param-2026.04.30 source: root: . frontend_root: frontend backend_root: backend capsule: id: konnaxion-v14-demo-2026.05.02 version: 2026.05.02-demo.1 output: ./dist/capsules/konnaxion-v14-demo-2026.05.02.kxcap include_seed_data: true profiles: default_network_profile: public_vps default_exposure_mode: public include: - local_only - intranet_private - private_tunnel - public_temporary - public_vps - offline security: require_signature: true allow_unknown_images: false allow_privileged_containers: false allow_docker_socket_mount: false allow_host_network: false block_dangerous_ports: true build: run_tests: true export_oci_images: true include_external_runtime_images: true generate_checksums: true sign_capsule: true clean_backend_context: true ``` Command using config: ```bash kx capsule build --config kxbuild.yaml ``` Command-line flags override config values unless explicitly forbidden by the selected build profile. --- ## 18. Canonical `manifest.yaml` The Builder must generate `manifest.yaml`. Minimum required fields: ```yaml project: Konnaxion app_version: v14 capsule_id: konnaxion-v14-demo-2026.05.02 capsule_version: 2026.05.02-demo.1 param_version: kx-param-2026.04.30 default_network_profile: public_vps default_exposure_mode: public required_ram_mb: 4096 recommended_ram_mb: 8192 services: traefik: role: reverse_proxy public_entrypoint: true image: traefik:v3.1 archive: images/traefik.oci.tar frontend-next: role: frontend internal_port: 3000 image: konnaxion/frontend-next:v14 archive: images/frontend-next.oci.tar django-api: role: backend_api internal_port: 5000 image: konnaxion/django-api:v14 archive: images/django-api.oci.tar postgres: role: database internal_only: true image: postgres:16 archive: images/postgres.oci.tar redis: role: broker internal_only: true image: redis:7 archive: images/redis.oci.tar celeryworker: role: background_worker internal_only: true image: konnaxion/django-api:v14 archive: images/celeryworker.oci.tar celerybeat: role: scheduler internal_only: true image: konnaxion/django-api:v14 archive: images/celerybeat.oci.tar media-nginx: role: media_static internal_only: true image: nginx:stable archive: images/media-nginx.oci.tar routes: "/": frontend-next "/api/": django-api "/admin/": django-api "/media/": media-nginx profiles: - local_only - intranet_private - private_tunnel - public_temporary - public_vps - offline security: require_signed_capsule: true generate_secrets_on_install: true expose_docker_socket: false allow_privileged_containers: false allow_host_network: false allow_unknown_images: false ``` The Builder must fail if required manifest fields are missing. --- ## 19. Canonical `images.yaml` The Builder must generate `images.yaml`. Example: ```yaml generated_at: "2026-05-02T21:24:27Z" images: - service: frontend-next image: konnaxion/frontend-next:v14-konnaxion-v14-demo-2026.05.02 archive: frontend-next.oci.tar sha256: "" size_bytes: 524288000 exported_at: "2026-05-02T21:24:27Z" - service: django-api image: konnaxion/django-api:v14-konnaxion-v14-demo-2026.05.02 archive: django-api.oci.tar sha256: "" size_bytes: 156237824 exported_at: "2026-05-02T21:24:27Z" - service: traefik image: traefik:v3.1 archive: traefik.oci.tar sha256: "" size_bytes: 0 exported_at: "2026-05-02T21:24:27Z" ``` The `archive` field is relative to: ```text images/ ``` The Builder must keep `images.yaml`, `manifest.yaml`, and `checksums.txt` consistent. --- ## 20. Canonical `docker-compose.capsule.yml` The Builder must generate or include `docker-compose.capsule.yml`. It must obey the following rules: ```text Use canonical service names Use internal Docker networks Expose only Traefik entrypoints Do not publish Postgres Do not publish Redis Do not publish Django direct port Do not publish Next.js direct port Do not publish Flower by default Do not mount Docker socket Do not use privileged containers Do not use host network Use named volumes or instance paths provided by the Agent Use image names that match manifest/image metadata Use commands compatible with offline-loaded images ``` Forbidden examples: ```yaml services: postgres: ports: - "5432:5432" ``` ```yaml services: django-api: privileged: true ``` ```yaml services: frontend-next: ports: - "3000:3000" ``` ```yaml services: any-service: volumes: - /var/run/docker.sock:/var/run/docker.sock ``` The Builder does not need to embed live public hostnames in `docker-compose.capsule.yml`. The Agent owns final runtime rendering for: ```text KX_HOST DJANGO_ALLOWED_HOSTS NEXT_PUBLIC_API_BASE NEXT_PUBLIC_BACKEND_BASE Traefik Host() rules ``` However, Builder output must contain enough route metadata for the Agent to render those values correctly. --- ## 21. Runtime Handoff Requirements for `public_vps` A capsule built by DOC-10 must be usable by the Manager and Agent for `public_vps` deployment without manual editing. For `public_vps`, the Agent must be able to generate: ```text KX_HOST= DJANGO_ALLOWED_HOSTS=127.0.0.1,localhost,,django-api,kx--django-api NEXT_PUBLIC_API_BASE=https:///api NEXT_PUBLIC_BACKEND_BASE=https:// Traefik file-provider rule Host(``) ``` The Builder must not bake a specific Droplet host into the capsule. The Builder must provide canonical placeholders: ```text ``` The Manager and Agent must resolve those placeholders at import/create/start time. --- ## 22. Build-Time Secret Policy The Builder must not bake secrets into images or capsule files. Forbidden during build: ```text real DJANGO_SECRET_KEY real POSTGRES_PASSWORD real DATABASE_URL with password SSH private keys Git tokens provider tokens API keys production .env files private certificates cookies authorization headers ``` Allowed: ```text template env files placeholder values schema examples non-secret defaults development-only fake values clearly marked as fake ``` Required placeholder format: ```text ``` Example: ```env DJANGO_SECRET_KEY= POSTGRES_PASSWORD= DJANGO_ALLOWED_HOSTS= NEXT_PUBLIC_API_BASE= NEXT_PUBLIC_BACKEND_BASE= ``` --- ## 23. Signing and Checksums ## 23.1 Checksums The Builder must generate: ```text checksums.txt ``` The checksum file must include all relevant files inside the capsule except `signature.sig`. Recommended format: ```text sha256 manifest.yaml sha256 docker-compose.capsule.yml sha256 images.yaml sha256 images/frontend-next.oci.tar sha256 images/django-api.oci.tar sha256 images/traefik.oci.tar sha256 images/postgres.oci.tar sha256 images/redis.oci.tar sha256 images/celeryworker.oci.tar sha256 images/celerybeat.oci.tar sha256 images/media-nginx.oci.tar ``` ## 23.2 Signature The Builder must generate: ```text signature.sig ``` The signature must cover: ```text checksums.txt manifest.yaml docker-compose.capsule.yml images.yaml profiles/ env-templates/ images/ healthchecks/ policies/ metadata/ ``` Release and demo capsules must be signed. Unsigned capsules are allowed only for local development and must be clearly marked: ```yaml signature_status: unsigned_dev_only ``` The Manager and Agent must reject unsigned capsules unless explicitly running in a development mode. --- ## 24. Build Profiles The Builder supports these build profiles: | Build Profile | Purpose | Signed | Tests Required | Seed Data | | ------------- | -----------------------: | -----------------------------: | -------------: | ------------: | | `dev` | Local developer testing | Optional | Optional | Optional | | `demo` | Demo-ready capsule | Required | Required | Optional | | `release` | Production-grade capsule | Required | Required | No by default | | `ci` | Automated CI validation | Required for release artifacts | Required | No | These are build profiles, not network profiles. Do not confuse build profile values with `NETWORK_PROFILE` values. Canonical network profiles remain: ```text local_only intranet_private private_tunnel public_temporary public_vps offline ``` --- ## 25. Required Build Checks The Builder must perform these checks before producing a capsule: ```text canonical_service_names canonical_network_profiles repository_layout_valid clean_backend_context_valid frontend_runtime_image_valid backend_runtime_image_valid external_images_available image_export_complete image_metadata_generated no_real_secrets no_public_internal_ports no_docker_socket_mount no_privileged_containers no_host_network manifest_schema compose_schema checksums_generated signature_generated capsule_verify_passes ``` For release builds, all required checks must pass. For demo builds, all security checks must pass. For dev builds, warnings may be allowed, but the capsule must be marked as development-only. --- ## 26. Output Status Values The Builder uses the canonical Security Gate statuses from `DOC-00`: ```text PASS WARN FAIL_BLOCKING SKIPPED UNKNOWN ``` A build can return: ```text BUILD_PASS BUILD_PASS_WITH_WARNINGS BUILD_FAIL BUILD_SECURITY_BLOCKED ``` Mapping: | Build Result | Meaning | | -------------------------- | --------------------------------------------- | | `BUILD_PASS` | Capsule produced and verified | | `BUILD_PASS_WITH_WARNINGS` | Capsule produced, non-blocking warnings exist | | `BUILD_FAIL` | Build failed | | `BUILD_SECURITY_BLOCKED` | Build blocked by security policy | --- ## 27. Exit Codes Canonical exit codes: | Code | Meaning | | ---: | ----------------------- | | `0` | Success | | `1` | General error | | `2` | Invalid CLI usage | | `3` | Build failed | | `4` | Verification failed | | `5` | Security policy failure | | `6` | Missing dependency | | `7` | Signing failure | | `8` | Manifest/schema failure | | `9` | File or path error | Scripts and CI systems should rely on these exit codes. --- ## 28. Logs Default log directory: ```text ./dist/logs/ ``` Canonical build log: ```text ./dist/logs/kx-capsule-build-.log ``` Canonical verify log: ```text ./dist/logs/kx-capsule-verify-.log ``` Logs must not contain secrets. The Builder must redact: ```text DJANGO_SECRET_KEY POSTGRES_PASSWORD DATABASE_URL password segment REDIS_URL password segment API keys tokens private keys authorization headers cookies ``` Canonical redaction marker: ```text [REDACTED] ``` --- ## 29. JSON Output Contract All major commands should support: ```bash --json ``` Example: ```bash kx capsule build --config kxbuild.yaml --json ``` Minimum JSON fields: ```json { "command": "kx capsule build", "status": "BUILD_PASS", "capsule_id": "konnaxion-v14-demo-2026.05.02", "capsule_version": "2026.05.02-demo.1", "output": "./dist/capsules/konnaxion-v14-demo-2026.05.02.kxcap", "images": [ "images/frontend-next.oci.tar", "images/django-api.oci.tar" ], "checks": [], "warnings": [], "errors": [] } ``` All statuses inside `checks` must use: ```text PASS WARN FAIL_BLOCKING SKIPPED UNKNOWN ``` --- ## 30. CI Usage A release pipeline should run: ```bash kx capsule doctor kx capsule build --config kxbuild.yaml kx capsule verify ./dist/capsules/konnaxion-v14-demo-2026.05.02.kxcap kx capsule inspect ./dist/capsules/konnaxion-v14-demo-2026.05.02.kxcap ``` Example CI release gate: ```bash kx capsule verify ./dist/capsules/konnaxion-v14-demo-2026.05.02.kxcap --json > capsule-verify.json ``` The CI job must fail if: ```text status != PASS any check.status == FAIL_BLOCKING signature is missing release build is unsigned forbidden secret is detected forbidden port is exposed required image archive is missing image checksum mismatch exists ``` --- ## 31. Developer Workflow ## 31.1 Local Dev Capsule ```bash kx capsule doctor kx capsule build \ --source-dir ./Konnaxion \ --output ./dist/capsules/konnaxion-v14-dev-2026.05.02.kxcap \ --channel dev \ --capsule-id konnaxion-v14-dev-2026.05.02 \ --version 2026.05.02-dev.1 \ --app-version v14 \ --param-version kx-param-2026.04.30 \ --profile local_only \ --unsigned \ --force ``` ## 31.2 Demo Capsule ```bash kx capsule build \ --source-dir ./Konnaxion \ --output ./dist/capsules/konnaxion-v14-demo-2026.05.02.kxcap \ --channel demo \ --capsule-id konnaxion-v14-demo-2026.05.02 \ --version 2026.05.02-demo.1 \ --app-version v14 \ --param-version kx-param-2026.04.30 \ --profile public_vps \ --include-seed-data \ --signing-key-file ./runtime/signing/kx-demo-ed25519-private.pem \ --public-key-file ./runtime/signing/kx-demo-ed25519-public.pem \ --force kx capsule verify ./dist/capsules/konnaxion-v14-demo-2026.05.02.kxcap ``` ## 31.3 Release Capsule ```bash kx capsule build \ --source-dir ./Konnaxion \ --output ./dist/capsules/konnaxion-v14-release-2026.05.02.kxcap \ --channel release \ --capsule-id konnaxion-v14-release-2026.05.02 \ --version 2026.05.02-release.1 \ --app-version v14 \ --param-version kx-param-2026.04.30 \ --profile public_vps \ --signing-key-file ./secrets/release-ed25519-private.pem \ --public-key-file ./secrets/release-ed25519-public.pem kx capsule verify ./dist/capsules/konnaxion-v14-release-2026.05.02.kxcap ``` --- ## 32. Interaction With Manager and Agent The Builder produces the capsule. The Manager imports it. The Agent runs it. Canonical handoff: ```text kx capsule build ↓ .kxcap ↓ Konnaxion Capsule Manager ↓ Konnaxion Agent ↓ Docker Compose Runtime ↓ Konnaxion Instance ``` The Builder must not assume that the build machine and runtime machine are the same. The Builder must also not assume that runtime state exists. The Builder operates on: ```text source repository build configuration generated images capsule metadata .kxcap archive ``` The Manager and Agent operate on: ```text Konnaxion Instance runtime volumes network profiles firewall rules backup sets restore plans rollback state ``` --- ## 33. Import Contract A capsule built by the Builder must be importable by the Manager without manual edits. The Manager must be able to derive: ```text CAPSULE_ID CAPSULE_VERSION APP_VERSION PARAM_VERSION default NETWORK_PROFILE default EXPOSURE_MODE required services routes env templates image list healthchecks security requirements ``` from: ```text manifest.yaml images.yaml docker-compose.capsule.yml profiles/ env-templates/ healthchecks/ policies/ ``` No manual editing should be required after build. The import contract must not require runtime backup data. The capsule may declare backup-related capabilities, such as healthcheck names or required writable paths, but it must not contain backup sets, production database dumps, runtime secrets, or restore state. Backup and restore behavior is defined by: ```text DOC-09_Konnaxion_Backup_Restore_Rollback.md ``` --- ## 34. Droplet/Public VPS Compatibility Requirements A capsule built for `public_vps` must support the Manager/Agent Droplet flow: ```text Manager on Windows -> SSH to Droplet -> private Agent at 127.0.0.1:8765 -> import capsule -> load image archives -> create runtime env -> render Traefik file-provider config -> start instance ``` The Builder must ensure: ```text all required images are offline-loadable runtime compose never requires public registry pull for app images frontend container starts without network access backend container starts without local source bind mounts metadata lets Agent set public host correctly ``` The Builder must not require: ```text temporary SSH tunnel public Agent listener manual docker save/load manual Traefik patch manual DJANGO_ALLOWED_HOSTS patch manual frontend Dockerfile patch ``` --- ## 35. Security Requirements The Builder must enforce these requirements: ```text Private-by-default where applicable Signed capsules by default No real secrets in capsule No exposed internal ports No Docker socket mount No privileged containers No host networking Canonical service names only Canonical network profiles only Checksums for all payloads Manifest schema validation Images archived and checksummed Logs redacted Release builds cannot skip tests Release builds cannot be unsigned Demo builds cannot be unsigned unless explicitly development-only ``` If a security requirement fails, the build must return: ```text BUILD_SECURITY_BLOCKED ``` and exit code: ```text 5 ``` --- ## 36. Forbidden Build Outputs The Builder must never produce a capsule that: ```text exposes Postgres publicly exposes Redis publicly exposes frontend-next directly on 3000 publicly exposes django-api directly on 5000 or 8000 publicly exposes Flower publicly mounts /var/run/docker.sock uses privileged: true uses network_mode: host contains real production secrets contains SSH private keys contains provider tokens contains a production DB dump in cleartext contains only images/README.json instead of images/*.oci.tar requires runtime registry access for Konnaxion app images requires runtime pnpm/corepack download for frontend start ``` --- ## 37. Minimal Implementation Plan ## 37.1 MVP Builder Minimum viable implementation: ```text kx capsule build kx capsule verify kx capsule inspect kx capsule doctor ``` MVP build features: ```text build frontend production image build backend production image from clean context include Traefik/Postgres/Redis/media images generate manifest.yaml generate images.yaml generate docker-compose.capsule.yml include canonical profiles include env templates export image tar files generate checksums sign capsule verify capsule ``` ## 37.2 Phase 2 ```text JSON output CI integration schema command stronger secret scanning SBOM generation image provenance metadata release channels delta capsules image deduplication ``` ## 37.3 Phase 3 ```text GUI integration remote signing support hardware appliance factory build offline update packages multi-instance build variants registry-backed release promotion ``` --- ## 38. Open Design Questions The following are intentionally left open for later documents: ```text exact signing technology exact archive container format exact SBOM format exact OCI image naming convention exact image registry strategy whether capsules can support deltas whether capsules can include encrypted demo datasets whether release signing uses local keys or remote signer whether duplicate image archives should be deduplicated by digest ``` These questions must not block the DOC-10 CLI contract. --- ## 39. Fixed Decisions This document fixes the following decisions: ```text Canonical CLI executable: kx Canonical Builder group: kx capsule Implementation compatibility executable: kx-builder Canonical output: .kxcap Canonical default capsule output path: ./dist/capsules/ Release capsules must be signed Demo capsules must be signed Release builds cannot skip tests The Builder must reject real secrets The Builder must reject dangerous exposed ports The Builder must reject Docker socket mounts The Builder must reject privileged containers The Builder must reject host networking The Builder must generate and verify checksums The Builder must generate manifest.yaml The Builder must generate images.yaml The Builder must generate docker-compose.capsule.yml The Builder must export all required image archives The Builder must use canonical service names The Builder must include canonical network profiles Frontend runtime must not require Corepack/pnpm download Backend image must be built from a clean context DOC-10 owns build-time capsule commands only DOC-10 does not own runtime backup, restore or rollback commands DOC-10 may reference runtime commands only for handoff/alignment ``` --- ## 40. Reference Command Summary ```bash # Check local build environment kx capsule doctor # Build demo capsule kx capsule build \ --source-dir ./Konnaxion \ --output ./dist/capsules/konnaxion-v14-demo-2026.05.02.kxcap \ --channel demo \ --capsule-id konnaxion-v14-demo-2026.05.02 \ --version 2026.05.02-demo.1 \ --app-version v14 \ --param-version kx-param-2026.04.30 \ --profile public_vps \ --include-seed-data \ --signing-key-file ./runtime/signing/kx-demo-ed25519-private.pem \ --public-key-file ./runtime/signing/kx-demo-ed25519-public.pem \ --force # Verify capsule kx capsule verify ./dist/capsules/konnaxion-v14-demo-2026.05.02.kxcap # Inspect capsule kx capsule inspect ./dist/capsules/konnaxion-v14-demo-2026.05.02.kxcap # List embedded network profiles kx capsule list-profiles ./dist/capsules/konnaxion-v14-demo-2026.05.02.kxcap # Export manifest kx capsule export-manifest ./dist/capsules/konnaxion-v14-demo-2026.05.02.kxcap \ --output ./dist/manifests/konnaxion-v14-demo-2026.05.02.manifest.yaml ``` Compatibility command summary: ```bash uv run kx-builder capsule build \ --source-dir C:\mycode\Konnaxion\Konnaxion \ --output C:\mycode\Konnaxion\runtime\capsules\konnaxion-v14-demo-2026.05.02.kxcap \ --channel demo \ --capsule-id konnaxion-v14-demo-2026.05.02 \ --version 2026.05.02-demo.1 \ --app-version v14 \ --param-version kx-param-2026.04.30 \ --profile public_vps \ --signing-key-file C:\mycode\Konnaxion\runtime\signing\kx-demo-ed25519-private.pem \ --public-key-file C:\mycode\Konnaxion\runtime\signing\kx-demo-ed25519-public.pem \ --force uv run kx-builder capsule verify C:\mycode\Konnaxion\runtime\capsules\konnaxion-v14-demo-2026.05.02.kxcap ``` ================================================================================================ FILE: docs/DOC-11_Konnaxion_Box_Appliance_Image.md AUTHORITY: reference CONTENT_ROLE: knowledge CONTENT_SHA256: 149f630651e1239345bcb8f0f3af7104aa433842fd3b466dc42adb0670fad8a9 CONTENT_BYTES: 36334 ================================================================================================ --- doc_id: DOC-11 title: Konnaxion Box Appliance Image project: Konnaxion app_version: v14 param_version: kx-param-2026.04.30 status: draft owner: Konnaxion last_updated: 2026-04-30 depends_on: - DOC-00_Konnaxion_Canonical_Variables.md - DOC-01_Konnaxion_Product_Vision.md - DOC-02_Konnaxion_Capsule_Architecture.md - DOC-04_Konnaxion_Manager_Architecture.md - DOC-05_Konnaxion_Agent_Security_Model.md - DOC-06_Konnaxion_Network_Profiles.md - DOC-07_Konnaxion_Security_Gate.md - DOC-08_Konnaxion_Runtime_Docker_Compose.md - DOC-09_Konnaxion_Backup_Restore_Rollback.md canonical_terms: - Konnaxion Box - Konnaxion Capsule - Konnaxion Capsule Manager - Konnaxion Agent - Konnaxion Instance - Konnaxion Backup Set - Konnaxion Factory Reset - KX_* --- # DOC-11 — Konnaxion Box Appliance Image # 1. Objectif du document Ce document définit l’image appliance officielle de **Konnaxion Box**. Une **Konnaxion Box** est une machine dédiée prête à l’emploi qui démarre Konnaxion avec un minimum de configuration, en mode privé par défaut, avec sécurité intégrée, profils réseau prédéfinis, backups, mises à jour et rollback. ```text id="doc11-purpose" Konnaxion Box = machine dédiée + image système + Konnaxion Capsule Manager + Konnaxion Agent + runtime Docker sécurisé ``` L’objectif n’est pas seulement d’installer Konnaxion sur Linux. L’objectif est de produire une image système qui transforme un mini PC ou serveur local en appliance plug-and-play. --- # 2. Positionnement La Konnaxion Box est destinée à : ```text id="box-targets" démos locales intranets d’organisations laboratoires citoyens écoles OBNL salles de consultation déploiements semi-autonomes démos publiques temporaires contrôlées ``` Elle n’est pas conçue comme : ```text id="box-not-targets" serveur cloud multi-tenant cluster Kubernetes NAS généraliste machine personnelle non dédiée serveur résidentiel public ouvert par défaut ``` --- # 3. Principe central La Konnaxion Box doit être : ```text id="box-principles" plug-and-play private-by-default deny-by-default offline-capable capsule-driven recoverable observable updatable factory-resettable ``` L’utilisateur ne doit pas avoir à configurer manuellement : ```text id="operator-should-not-configure" Docker Traefik PostgreSQL Redis Celery Nginx UFW systemd .env ports internes certificats migrations volumes ``` Konnaxion utilise déjà une stack complète avec backend **Django + DRF + Celery + Redis**, frontend **Next.js/React**, base **PostgreSQL**, et une infrastructure Docker/Traefik/Nginx en production; la Konnaxion Box doit masquer cette complexité derrière une interface appliance. --- # 4. Architecture globale ```text id="box-architecture" ┌──────────────────────────────────────────────┐ │ Konnaxion Box │ │ Hardware dédié + OS minimal + firewall │ └──────────────────────┬───────────────────────┘ │ ┌──────────────────────▼───────────────────────┐ │ Konnaxion Appliance OS Layer │ │ updates, users, firewall, services système │ └──────────────────────┬───────────────────────┘ │ ┌──────────────────────▼───────────────────────┐ │ Konnaxion Capsule Manager │ │ UI locale, onboarding, status, backups │ └──────────────────────┬───────────────────────┘ │ ┌──────────────────────▼───────────────────────┐ │ Konnaxion Agent │ │ service privilégié limité et audité │ └──────────────────────┬───────────────────────┘ │ ┌──────────────────────▼───────────────────────┐ │ Docker Compose Runtime │ │ Traefik + Next.js + Django + DB + workers │ └──────────────────────┬───────────────────────┘ │ ┌──────────────────────▼───────────────────────┐ │ Konnaxion Instance │ │ données, secrets, logs, backups, médias │ └──────────────────────────────────────────────┘ ``` --- # 5. Éditions de l’image ## 5.1 Édition standard ```text id="standard-edition" Nom: Konnaxion Box Standard Base: Ubuntu Server LTS ou Debian stable Runtime: Docker Engine + Docker Compose UI: Konnaxion Capsule Manager Agent: Konnaxion Agent Usage: démo, intranet, petite organisation ``` ## 5.2 Édition développeur ```text id="developer-edition" Nom: Konnaxion Box Developer Inclut: outils de debug, logs étendus, shell admin, build tools optionnels Usage: développement appliance, QA, validation capsules ``` ## 5.3 Édition production locale ```text id="local-production-edition" Nom: Konnaxion Box Local Production Inclut: sécurité renforcée, logs réduits, backups automatiques, updates contrôlés Usage: installation durable en intranet ``` Le MVP doit commencer avec **Konnaxion Box Standard**. --- # 6. Base système recommandée ## 6.1 OS cible ```text id="target-os" Base OS: Ubuntu Server LTS Alternative: Debian stable Architecture: x86_64 Boot mode: UEFI Filesystem recommandé: ext4 ou btrfs Runtime containers: Docker Engine ``` ## 6.2 Raison du choix La base doit être : ```text id="os-requirements" stable documentée facile à maintenir compatible Docker compatible mini PC compatible scripts d’installation compatible firewall local ``` Ne pas utiliser dans le MVP : ```text id="not-os-mvp" Kubernetes microK8s Nomad Proxmox comme base obligatoire TrueNAS comme base obligatoire système immutable complexe ``` Proxmox peut être utilisé par un opérateur avancé pour héberger une VM Konnaxion Box, mais il ne doit pas être requis pour le MVP. --- # 7. Matériel recommandé ## 7.1 Minimum acceptable ```text id="hardware-minimum" CPU: 4 cores x86_64 RAM: 8 GB Disk: SSD 256 GB Network: Ethernet USB: 1 port pour recovery/install ``` ## 7.2 Recommandé ```text id="hardware-recommended" CPU: 6-8 cores x86_64 RAM: 16 GB Disk: NVMe/SSD 512 GB Network: Ethernet gigabit Power: petit UPS si installation durable ``` ## 7.3 Justification RAM Le build frontend Next.js validé nécessite `NODE_OPTIONS="--max-old-space-size=4096"` pour éviter les erreurs mémoire sur VPS limité. Pour une appliance stable, **8 GB** doit être considéré comme minimum réel, et **16 GB** comme cible confortable. --- # 8. Layout disque canonique ```text id="disk-layout" / ├── /opt/konnaxion/ │ ├── capsules/ │ ├── instances/ │ ├── manager/ │ ├── agent/ │ ├── releases/ │ ├── shared/ │ └── backups/ ├── /var/log/konnaxion/ ├── /etc/konnaxion/ └── /var/lib/konnaxion/ ``` ## 8.1 Répertoires système | Chemin | Rôle | | --------------------------- | ----------------------------- | | `/opt/konnaxion/capsules/` | Capsules `.kxcap` importées | | `/opt/konnaxion/instances/` | Instances installées | | `/opt/konnaxion/manager/` | UI/Manager | | `/opt/konnaxion/agent/` | Agent système | | `/opt/konnaxion/backups/` | Backups locaux | | `/etc/konnaxion/` | Configuration appliance | | `/var/log/konnaxion/` | Logs système Konnaxion | | `/var/lib/konnaxion/` | État interne du Manager/Agent | ## 8.2 Instance type ```text id="instance-layout" /opt/konnaxion/instances// ├── env/ ├── postgres/ ├── redis/ ├── media/ ├── logs/ ├── backups/ ├── state/ └── compose/ ``` Rappel canonique : ```text id="capsule-instance-rule" Capsule = application immuable Instance = données, secrets, logs, médias, backups et état runtime ``` --- # 9. Utilisateurs système ## 9.1 Utilisateurs canoniques | Utilisateur | Rôle | Sudo | Docker | | ------------- | ----------------------------- | -----: | -------------: | | `kx-agent` | exécute Konnaxion Agent | limité | contrôlé | | `kx-runtime` | propriétaire fichiers runtime | non | non | | `kx-backup` | tâches backup | limité | non | | `admin local` | maintenance manuelle | oui | non par défaut | ## 9.2 Règle Docker Ne pas ajouter un utilisateur opérateur au groupe `docker`. ```text id="docker-group-rule" Les opérations Docker doivent passer par Konnaxion Agent, pas par un accès Docker libre donné à l’utilisateur. ``` Cette règle vient directement de l’incident précédent : les notes indiquent que l’attaquant a lancé des conteneurs Docker malveillants, ajouté de la persistence cron et utilisé des mécanismes de backdoor; le nouvel environnement doit donc éviter de donner un contrôle Docker libre à un utilisateur de déploiement. --- # 10. Services systemd ```text id="systemd-services" konnaxion-agent.service konnaxion-manager.service konnaxion-firewall.service konnaxion-healthcheck.timer konnaxion-backup.timer konnaxion-update.timer ``` ## 10.1 `konnaxion-agent.service` Rôle : ```text id="agent-service-role" exécuter les opérations privilégiées autorisées contrôler Docker Compose appliquer les profils réseau vérifier les capsules gérer backups/restores appliquer Security Gate ``` ## 10.2 `konnaxion-manager.service` Rôle : ```text id="manager-service-role" servir l’interface locale afficher l’état de l’instance démarrer/arrêter via l’Agent présenter les profils réseau présenter logs, backups, healthchecks ``` ## 10.3 `konnaxion-firewall.service` Rôle : ```text id="firewall-service-role" appliquer la politique deny-by-default ouvrir uniquement les ports autorisés par profil fermer les ports dangereux revenir au profil privé après expiration publique ``` --- # 11. Réseau par défaut ## 11.1 Profil de démarrage ```env id="default-network-profile" KX_NETWORK_PROFILE=intranet_private KX_EXPOSURE_MODE=private KX_PUBLIC_MODE_ENABLED=false ``` Le mode public ne doit jamais être activé au premier boot. ## 11.2 Ports autorisés par défaut En mode `intranet_private` : ```text id="default-allowed-ports" 443/tcp LAN only 80/tcp optional redirect LAN only ``` ## 11.3 Ports bloqués par défaut ```text id="default-blocked-ports" 3000/tcp 5000/tcp 5432/tcp 6379/tcp 5555/tcp 8000/tcp Docker daemon TCP ``` Les documents de sécurité demandent explicitement de ne pas exposer `3000`, `5555`, `5432`, `6379`, `8000` ni le Docker daemon; les utilisateurs doivent passer par Traefik sur `80/443`. --- # 12. Profils réseau supportés ```text id="supported-network-profiles" local_only intranet_private private_tunnel public_temporary public_vps offline ``` ## 12.1 `local_only` ```text id="profile-local-only" Usage: démo sur la machine Exposition: localhost seulement Public: non LAN: non ``` ## 12.2 `intranet_private` ```text id="profile-intranet-private" Usage: organisation locale Exposition: LAN seulement Public: non URL cible: https://konnaxion.local ``` ## 12.3 `private_tunnel` ```text id="profile-private-tunnel" Usage: accès distant privé Exposition: VPN/tailnet seulement Port routeur: aucun ``` ## 12.4 `public_temporary` ```text id="profile-public-temporary" Usage: démo publique ponctuelle Exposition: tunnel temporaire Expiration: obligatoire Auth: obligatoire ``` ## 12.5 `public_vps` ```text id="profile-public-vps" Usage: instance web publique Exposition: 80/443 seulement Contexte: VPS propre ou host durci Non recommandé depuis réseau résidentiel ``` ## 12.6 `offline` ```text id="profile-offline" Usage: démonstration sans réseau Exposition: aucune Fonctions externes: désactivées ``` --- # 13. Premier démarrage ## 13.1 Objectif UX Le premier démarrage doit rester minimal : ```text id="first-boot-goal" 1. Brancher la machine. 2. Ouvrir Konnaxion Capsule Manager. 3. Choisir ou importer une capsule. 4. Choisir le mode réseau. 5. Générer le compte admin. 6. Démarrer. ``` ## 13.2 Écran premier démarrage ```text id="first-boot-screen" Bienvenue dans Konnaxion Box [1] Importer une capsule [2] Choisir le mode réseau [3] Créer l’admin [4] Démarrer Konnaxion ``` ## 13.3 Configuration demandée L’utilisateur doit seulement fournir : ```text id="minimal-user-input" nom de l’instance mode réseau mot de passe admin ou génération automatique option backup activé/désactivé ``` Tout le reste est généré automatiquement. --- # 14. Génération automatique Au premier démarrage, l’Agent génère : ```text id="auto-generated-items" KX_INSTANCE_ID DJANGO_SECRET_KEY POSTGRES_PASSWORD DATABASE_URL interne certificat local si requis admin initial Docker networks volumes .env d’instance profil firewall ``` La capsule ne doit jamais contenir les vrais secrets. Les notes de récupération indiquent que `DJANGO_SECRET_KEY`, `POSTGRES_PASSWORD`, `DATABASE_URL`, clés privées, tokens, clés SSH et mots de passe admin doivent être considérés comme secrets sensibles et rotés après exposition. --- # 15. Konnaxion Capsule incluse L’image appliance peut être livrée de deux manières. ## 15.1 Sans capsule préinstallée ```text id="no-preinstalled-capsule" La Konnaxion Box démarre sur le Manager. L’utilisateur importe un fichier .kxcap. ``` ## 15.2 Avec capsule de démo préinstallée ```text id="preinstalled-demo-capsule" La Konnaxion Box contient une capsule de démo signée. L’utilisateur peut démarrer immédiatement. ``` Pour le MVP, privilégier : ```text id="mvp-capsule-choice" capsule de démo préinstallée + option importer nouvelle capsule ``` --- # 16. Runtime Docker Compose La Konnaxion Box exécute une **Konnaxion Instance** via Docker Compose. Services canoniques : ```text id="runtime-services" traefik frontend-next django-api postgres redis celeryworker celerybeat flower media-nginx ``` Le déploiement VPS actuel/historique fonctionne déjà avec backend Docker Compose, frontend Node/pnpm, Postgres Docker, Redis Docker et Traefik Docker; la Konnaxion Box doit converger vers un runtime encore plus cohérent où le frontend est aussi intégré au modèle capsule/runtime. --- # 17. Routage runtime ```text id="runtime-routing" https:/// -> frontend-next https:///api/ -> django-api https:///admin/ -> django-api https:///media/ -> media-nginx ``` Règle : ```text id="routing-rule" Traefik est le seul point d’entrée réseau. Tous les autres services restent internes. ``` Le routage actuel documenté utilise déjà `/` vers Next.js, `/api/` vers Django, `/admin/` vers Django admin et `/media/` vers le service media. --- # 18. Security Gate appliance Avant chaque démarrage, l’Agent doit exécuter : ```text id="security-gate-checks" capsule_signature image_checksums manifest_schema secrets_present secrets_not_default firewall_enabled dangerous_ports_blocked postgres_not_public redis_not_public docker_socket_not_mounted no_privileged_containers no_host_network allowed_images_only admin_surface_private backup_configured ``` Résultats possibles : ```text id="security-statuses" PASS WARN FAIL_BLOCKING SKIPPED UNKNOWN ``` Si un contrôle critique retourne `FAIL_BLOCKING` : ```text id="security-blocked-state" KX_INSTANCE_STATE=security_blocked ``` et l’instance ne démarre pas. --- # 19. Interface principale ```text id="main-ui" Konnaxion Box Instance: demo-001 État: running Profil réseau: intranet_private URL: https://konnaxion.local Sécurité: PASS Backups: activés Dernier backup: 2026-04-30 09:00 [Ouvrir Konnaxion] [Changer mode réseau] [Créer backup] [Voir logs] [Mettre à jour] [Arrêter] ``` --- # 20. Logs ## 20.1 Logs visibles à l’opérateur ```text id="operator-logs" état instance erreurs démarrage résultat migrations résultat Security Gate état backups état réseau ``` ## 20.2 Logs techniques ```text id="technical-logs" docker compose logs django logs frontend logs traefik logs postgres health redis health celeryworker logs celerybeat logs agent logs ``` ## 20.3 Règle secrets ```text id="logs-secret-rule" Les logs ne doivent jamais afficher les secrets. ``` Si un secret apparaît dans les logs, il doit être roté. --- # 21. Backups La Konnaxion Box doit fournir des backups utilisables sans terminal, mais elle ne doit jamais sauvegarder ou restaurer l’état système complet d’une machine compromise. La règle canonique est : ```text id="box-backup-rule" Backup = données applicatives vérifiées. Backup ≠ image disque complète. Backup ≠ état système restaurable aveuglément. ``` ## 21.1 Backups locaux Un backup local doit inclure : ```text id="local-backups" PostgreSQL logical dump media/uploads instance manifest network profile snapshot capsule reference app version capsule version redacted env metadata healthcheck result backup manifest checksums ``` Un backup local ne doit jamais inclure : ```text id="local-backups-forbidden" secrets en clair image disque complète /tmp /dev/shm crontabs système ou utilisateur anciens authorized_keys sudoers Docker daemon state Docker socket conteneurs inconnus volumes Docker non vérifiés artefacts de compromission ``` ## 21.2 Chemins de backup Le stockage canonique des backups est global à la Box : ```text id="backup-path-canonical" /opt/konnaxion/backups// ``` Le dossier dans l’instance est réservé aux pointeurs, état local ou cache léger : ```text id="backup-path-instance-pointer" /opt/konnaxion/instances//backups/ ``` Règle : ```text id="backup-path-rule" Les vrais Backup Sets sont sous /opt/konnaxion/backups//. Le chemin instance/backups ne doit pas devenir une deuxième source de vérité. ``` ## 21.3 Classes de backup La Konnaxion Box doit supporter les classes suivantes : ```text id="box-backup-classes" daily weekly monthly pre-update pre-restore manual ``` Pour le MVP, seules ces classes sont obligatoires : ```text id="box-backup-mvp-classes" manual pre-update pre-restore ``` ## 21.4 Rétention par défaut ```env id="backup-retention" KX_BACKUP_ENABLED=true KX_BACKUP_ROOT=/opt/konnaxion/backups KX_BACKUP_RETENTION_DAYS=14 KX_DAILY_BACKUP_RETENTION_DAYS=14 KX_WEEKLY_BACKUP_RETENTION_WEEKS=8 KX_MONTHLY_BACKUP_RETENTION_MONTHS=12 KX_PRE_UPDATE_BACKUP_RETENTION_COUNT=5 KX_PRE_RESTORE_BACKUP_RETENTION_COUNT=5 ``` ## 21.5 Avertissement espace disque La Konnaxion Box doit surveiller l’espace disque avant backup, restore, update et factory reset. Seuils canoniques : ```env id="backup-disk-thresholds" KX_MIN_FREE_DISK_GB=20 KX_MIN_FREE_DISK_PERCENT=15 KX_BACKUP_WARN_DISK_PERCENT=25 ``` Comportement : ```text id="backup-disk-behavior" Si espace libre < KX_MIN_FREE_DISK_GB: bloquer backup/update/restore non critiques. Si espace libre < KX_BACKUP_WARN_DISK_PERCENT: afficher warning. Si backup pré-update impossible: bloquer update capsule. Si backup pré-restore impossible: bloquer restore destructif. ``` ## 21.6 Export hors machine La Konnaxion Box doit prévoir l’export hors machine, même si le MVP ne choisit pas encore un fournisseur. Formats d’export supportés cible : ```text id="backup-export-targets" USB drive local network share manual download from Manager UI encrypted archive future offsite provider ``` Règles : ```text id="backup-export-rules" L’export ne doit pas contenir de secrets en clair. L’export doit inclure backup-manifest.yaml. L’export doit inclure checksums.sha256. L’export doit être vérifiable avant import. L’export doit rester utilisable en environnement offline/intranet. ``` ## 21.7 Backup avant mise à jour Avant chaque update capsule : ```text id="backup-before-update" 1. vérifier capsule entrante 2. créer Backup Set pre-update 3. vérifier checksums 4. arrêter services write-heavy si nécessaire 5. appliquer nouvelle capsule 6. exécuter migrations 7. exécuter Security Gate 8. exécuter healthchecks 9. rollback si échec ``` Une update capsule sans backup `pre-update` vérifié doit être bloquée, sauf mode explicitement marqué `unsafe-dev`. --- # 22. Restore Un restore doit restaurer l’application dans un runtime fiable, pas reconstruire un ancien système potentiellement compromis. Règle canonique : ```text id="restore-rule" Restore = trusted capsule + verified Backup Set + generated/current secrets + safe network profile. ``` ## 22.1 Restore inclus Un restore peut restaurer : ```text id="restore-includes" PostgreSQL médias/uploads metadata instance référence capsule compatible profil réseau validé manifest backup healthcheck metadata ``` ## 22.2 Restore exclu Un restore ne doit pas restaurer aveuglément : ```text id="restore-excludes" anciens secrets compromis ancienne configuration firewall dangereuse ancienne clé SSH anciens tokens externes anciens conteneurs inconnus ancien état Docker daemon ancienne image disque /tmp /dev/shm crontabs sudoers authorized_keys ``` ## 22.3 Restore par défaut Le mode restore le plus sûr pour la Box est : ```text id="restore-default" restore-new ``` Comportement : ```text id="restore-new-behavior" 1. créer nouvelle instance 2. appliquer profil local_only 3. importer Backup Set vérifié 4. restaurer DB/media 5. générer ou réassocier secrets selon politique 6. exécuter migrations compatibles 7. exécuter Security Gate 8. exécuter healthchecks 9. proposer switch vers intranet_private seulement après PASS ``` ## 22.4 Restore après factory reset Après un factory reset, le Manager doit offrir : ```text id="restore-after-factory-reset" Importer une capsule .kxcap Importer un Backup Set vérifié Restaurer dans une nouvelle instance Démarrer en local_only Exécuter Security Gate Passer en intranet_private seulement après validation ``` Le restore après factory reset ne doit jamais réactiver automatiquement : ```text id="restore-after-reset-never-auto" public_temporary public_vps SSH maintenance anciens tunnels anciens ports publics ``` ## 22.5 Restore UI minimum L’interface doit présenter : ```text id="restore-ui-minimum" backup_id date création instance source version capsule source taille backup statut vérification contenu restauré profil réseau cible risques détectés bouton restore-new recommandé ``` --- # 23. Factory reset La Konnaxion Box doit supporter un reset usine clair, sécuritaire et non ambigu. Le reset usine n’est pas un restore. Il remet la Box dans un état connu et privé. ## 23.1 Reset soft ```text id="soft-reset" Supprime ou désactive l’instance active. Garde les capsules importées. Garde les Backup Sets vérifiés. Réinitialise le profil réseau en intranet_private. Désactive public mode. Désactive tunnels. Conserve logs essentiels de reset. ``` Usage : ```text id="soft-reset-use" Démo terminée Instance brisée mais Box saine Besoin de repartir sans effacer les archives ``` ## 23.2 Reset complet ```text id="full-reset" Supprime instances. Supprime capsules importées. Supprime logs applicatifs non essentiels. Supprime secrets générés. Désactive tunnels. Ferme ports publics. Retourne à l’état premier démarrage. ``` Par défaut, le reset complet doit demander quoi faire avec les Backup Sets : ```text id="full-reset-backup-choice" [recommandé] exporter les backups avant reset garder les backups locaux supprimer les backups locaux ``` Si l’utilisateur choisit de supprimer les backups, l’UI doit exiger une confirmation explicite : ```text id="full-reset-delete-confirmation" DELETE BACKUPS ``` ## 23.3 Reset sécurisé Le reset sécurisé est utilisé si la Box est suspectée compromise. ```text id="secure-reset" Efface secrets. Désactive tunnels. Ferme ports publics. Passe en offline ou intranet_private. Marque les backups locaux comme à vérifier. Bloque restore direct dans l’instance courante. Force restore-new depuis capsule fiable. Exige Security Gate PASS avant réexposition réseau. ``` Le reset sécurisé ne doit pas promettre d’effacer forensiquement tous les blocs disque dans le MVP. ## 23.4 Factory reset et backups Règle : ```text id="factory-reset-backup-rule" Aucun reset ne doit supprimer les backups sans confirmation explicite. Aucun restore post-reset ne doit exposer la Box au public automatiquement. Aucun Backup Set non vérifié ne doit être restauré après reset. ``` --- # 24. Mises à jour ## 24.1 Types de mises à jour ```text id="update-types" OS updates Konnaxion Manager updates Konnaxion Agent updates Konnaxion Capsule updates Security policy updates ``` ## 24.2 Politique MVP Pour le MVP : ```text id="mvp-update-policy" updates OS semi-automatiques updates Manager/Agent manuelles updates Capsule manuelles via import .kxcap rollback obligatoire ``` ## 24.3 Update capsule ```text id="capsule-update-flow" 1. importer nouvelle capsule 2. vérifier signature 3. vérifier compatibilité 4. backup instance 5. arrêter services 6. appliquer nouvelle capsule 7. migrations 8. healthcheck 9. switch 10. rollback si échec ``` Le workflow backend actuel documente déjà les opérations de rebuild, migrations Django, vérification des conteneurs et création de superuser; l’appliance doit automatiser ces étapes via le Manager/Agent. --- # 25. États système ## 25.1 États appliance ```text id="box-states" factory_new first_boot configured ready running degraded updating recovering security_blocked factory_resetting ``` ## 25.2 États instance ```text id="instance-states" created importing verifying ready starting running stopping stopped updating rolling_back degraded failed security_blocked ``` --- # 26. Variables appliance ```env id="box-env" KX_BOX_ID= KX_BOX_NAME=konnaxion-box KX_BOX_EDITION=standard KX_BOX_VERSION=2026.04.30 KX_OS_BASE=ubuntu-lts KX_AGENT_VERSION=0.1.0 KX_MANAGER_VERSION=0.1.0 KX_DEFAULT_NETWORK_PROFILE=intranet_private KX_REQUIRE_SIGNED_CAPSULE=true KX_BACKUP_ENABLED=true KX_BACKUP_ROOT=/opt/konnaxion/backups KX_BACKUP_RETENTION_DAYS=14 KX_DAILY_BACKUP_RETENTION_DAYS=14 KX_WEEKLY_BACKUP_RETENTION_WEEKS=8 KX_MONTHLY_BACKUP_RETENTION_MONTHS=12 KX_PRE_UPDATE_BACKUP_RETENTION_COUNT=5 KX_PRE_RESTORE_BACKUP_RETENTION_COUNT=5 KX_MIN_FREE_DISK_GB=20 KX_MIN_FREE_DISK_PERCENT=15 KX_BACKUP_WARN_DISK_PERCENT=25 KX_FACTORY_RESET_KEEP_BACKUPS=true KX_FACTORY_RESET_REQUIRE_BACKUP_EXPORT_WARNING=true KX_RESTORE_DEFAULT_MODE=restore-new KX_RESTORE_DEFAULT_NETWORK_PROFILE=local_only KX_PUBLIC_MODE_ENABLED=false ``` Ces variables doivent être harmonisées avec `DOC-00_Konnaxion_Canonical_Variables.md` avant d’être considérées comme définitivement canoniques si elles ne sont pas encore présentes dans DOC-00. --- # 27. Image build pipeline L’image Konnaxion Box doit être produite par un pipeline reproductible. ```text id="image-build-pipeline" 1. préparer base OS 2. appliquer hardening système 3. installer Docker Engine 4. installer Konnaxion Agent 5. installer Konnaxion Capsule Manager 6. installer firewall policy 7. installer services systemd 8. ajouter capsule de démo optionnelle 9. nettoyer secrets build 10. générer image disque 11. calculer checksum 12. signer image ``` --- # 28. Artefacts produits ```text id="image-artifacts" konnaxion-box-standard-2026.04.30.img konnaxion-box-standard-2026.04.30.img.sha256 konnaxion-box-standard-2026.04.30.img.sig konnaxion-box-standard-2026.04.30.release-notes.md ``` --- # 29. Installation sur machine dédiée ## 29.1 Méthode USB ```text id="usb-install" 1. flasher l’image sur USB 2. booter la machine dédiée 3. installer sur disque interne 4. redémarrer 5. ouvrir Konnaxion Manager ``` ## 29.2 Méthode disque préinstallé ```text id="preinstalled-disk" 1. image écrite directement sur SSD/NVMe 2. machine livrée prête 3. premier démarrage lance onboarding ``` ## 29.3 Méthode VM ```text id="vm-install" 1. créer VM Ubuntu/Debian compatible 2. installer Konnaxion Box image ou script bootstrap 3. utiliser comme appliance virtuelle ``` --- # 30. Sécurité bootstrapping Au premier démarrage : ```text id="bootstrap-security" désactiver mots de passe par défaut générer KX_BOX_ID générer secrets instance forcer changement admin appliquer firewall désactiver public mode désactiver SSH public vérifier capsules signées ``` ## 30.1 SSH Par défaut : ```text id="ssh-default" SSH désactivé ou LAN-only. Aucun accès root SSH. Aucune authentification par mot de passe en mode production locale. ``` Pour maintenance : ```text id="ssh-maintenance" activation temporaire clé SSH seulement expiration automatique possible journalisation obligatoire ``` --- # 31. Menaces couvertes La Konnaxion Box doit réduire les risques suivants : ```text id="covered-threats" exposition accidentelle de Postgres exposition accidentelle de Redis exposition accidentelle de Next.js direct exposition accidentelle de Flower/dashboard capsule modifiée image Docker inconnue secret par défaut secret transporté dans capsule Docker socket monté dans conteneur conteneur privileged mode public oublié actif absence de backup mauvaise restauration après incident ``` Le déploiement précédent a montré des indicateurs graves : image Docker malveillante `negoroo/amco:123`, conteneurs `amco_*`, miner, `/tmp/sshd`, `/dev/shm/*`, crontab de persistence, tentative de création `pakchoi` et fichier sudoers. --- # 32. Hors scope du MVP appliance ```text id="box-mvp-out-of-scope" haute disponibilité multi-machine cluster Kubernetes marketplace publique multi-tenant SaaS chiffrement disque avancé avec TPM obligatoire gestion MDM entreprise déploiement automatique chez clients externes support hardware universel ``` --- # 33. MVP Konnaxion Box Le MVP doit inclure : ```text id="box-mvp" image Ubuntu/Debian préparée Docker Engine Konnaxion Agent Konnaxion Capsule Manager import .kxcap capsule démo optionnelle profil local_only profil intranet_private profil public_temporary Security Gate firewall deny-by-default backup manuel backup pre-update backup pre-restore restore manuel restore-new recommandé export backup hors machine logs opérateur factory reset avec protection backups ``` Ne pas inclure immédiatement : ```text id="box-mvp-not-include" auto-update complexe cluster VPN propriétaire haute disponibilité marketplace gestion multi-box monitoring cloud centralisé ``` --- # 34. Critères d’acceptation ## 34.1 Plug-and-play ```text id="acceptance-plug-play" Une Konnaxion Box neuve démarre jusqu’au Manager. Un utilisateur peut importer une capsule. Un utilisateur peut démarrer Konnaxion sans terminal. Une URL fonctionnelle est affichée. Aucun .env n’est édité manuellement. ``` ## 34.2 Sécurité ```text id="acceptance-security" Le mode par défaut est privé. Aucun port dangereux n’est public. Postgres n’est pas accessible depuis le LAN hors réseau Docker. Redis n’est pas accessible depuis le LAN hors réseau Docker. Docker socket n’est pas monté dans les conteneurs. Les capsules non signées sont refusées. Les secrets sont générés au premier démarrage. Le mode public temporaire expire automatiquement. Un restore post-reset ne réactive pas le mode public automatiquement. Un Backup Set non vérifié ne peut pas être restauré. ``` ## 34.3 Opérations ```text id="acceptance-ops" Start fonctionne. Stop fonctionne. Backup fonctionne. Backup verify fonctionne. Restore fonctionne. Restore-new fonctionne. Factory reset fonctionne. Factory reset ne supprime pas les backups sans confirmation explicite. Export backup hors machine est prévu. Logs visibles. Security Gate visible. Update capsule avec rollback fonctionne. ``` ## 34.4 Performance minimale ```text id="acceptance-performance" La machine démarre le Manager automatiquement. L’instance Konnaxion atteint l’état running. Le frontend répond via Traefik. L’API répond via /api/. L’admin Django répond via /admin/. Les workers Celery démarrent. ``` --- # 35. Décisions fixées ```text id="doc11-decisions" DECISION-11-01: Konnaxion Box est une appliance dédiée, pas seulement un script d’installation. DECISION-11-02: La base MVP est Ubuntu Server LTS ou Debian stable. DECISION-11-03: Docker Compose est le runtime initial. DECISION-11-04: Le profil réseau par défaut est intranet_private. DECISION-11-05: Le mode public est toujours explicite, temporaire ou réservé au profil public_vps. DECISION-11-06: L’utilisateur opérateur ne reçoit pas d’accès Docker libre. DECISION-11-07: Konnaxion Agent est le seul composant autorisé à appliquer les opérations privilégiées. DECISION-11-08: La capsule ne contient aucun secret réel. DECISION-11-09: La Konnaxion Box doit supporter backup, restore et factory reset. DECISION-11-10: La Konnaxion Box doit être utilisable sans terminal pour le cas standard. DECISION-11-11: Le stockage canonique des backups est /opt/konnaxion/backups//. DECISION-11-12: Le restore par défaut après reset ou incident est restore-new en profil local_only. DECISION-11-13: Aucun factory reset ne supprime les backups sans confirmation explicite. DECISION-11-14: Une update capsule doit créer et vérifier un backup pre-update avant modification. ``` --- # 36. Relation avec les autres documents ```text id="doc-relations" DOC-00: définit variables et noms canoniques. DOC-01: définit la vision produit appliance/capsule. DOC-02: décrit la Konnaxion Capsule. DOC-04: décrit le Konnaxion Capsule Manager. DOC-05: décrit le modèle de sécurité du Konnaxion Agent. DOC-06: décrit les profils réseau. DOC-07: décrit le Security Gate. DOC-08: décrit le runtime Docker Compose. DOC-09: décrit backup, restore, rollback, Backup Sets, restore-new, pre-update, pre-restore et règles de récupération après incident. DOC-10: décrit le Builder CLI. ``` --- # 37. Résumé exécutif ```text id="doc11-summary" La Konnaxion Box est l’appliance matérielle/logicielle qui rend Konnaxion plug-and-play. Elle fournit une base système sécurisée, un Manager local, un Agent privilégié contrôlé, un runtime Docker Compose, des profils réseau prédéfinis, des backups vérifiables, un restore-new sécurisé, un export backup hors machine, un reset usine protégé, et un mode privé par défaut. Elle transforme Konnaxion d’une application complexe à déployer en une capsule opérable en local, intranet ou démo temporaire, sans exposer les services internes. ``` --- # 38. Prochaine documentation recommandée ```text id="next-doc" DOC-02_Konnaxion_Capsule_Architecture.md ``` ou, si on veut rester dans l’ordre appliance : ```text id="next-appliance-doc" DOC-05_Konnaxion_Agent_Security_Model.md ``` Le plus logique après DOC-11 est **DOC-05**, parce que la Konnaxion Box dépend fortement du modèle de permissions entre le Manager, l’Agent, Docker, le firewall et le système. ================================================================================================ FILE: docs/DOC-12_Konnaxion_Install_Runbook.md AUTHORITY: reference CONTENT_ROLE: knowledge CONTENT_SHA256: dd8756fdaedcb63c683c16495edf32324dd7c0cd2aaa23158d6ba363da14d24f CONTENT_BYTES: 36344 ================================================================================================ --- doc_id: DOC-12 title: Konnaxion Install Runbook project: Konnaxion app_version: v14 param_version: kx-param-2026.04.30 status: draft owner: Konnaxion Architecture last_updated: 2026-05-01 depends_on: - DOC-00_Konnaxion_Canonical_Variables.md - DOC-02_Konnaxion_Capsule_Architecture.md - DOC-03_Konnaxion_Capsule_Format.md - DOC-04_Konnaxion_Manager_Architecture.md - DOC-05_Konnaxion_Agent_Security_Model.md - DOC-06_Konnaxion_Network_Profiles.md - DOC-07_Konnaxion_Security_Gate.md - DOC-08_Konnaxion_Runtime_Docker_Compose.md - DOC-09_Konnaxion_Backup_Restore_Rollback.md related_docs: - DOC-10_Konnaxion_Builder_CLI.md - DOC-11_Konnaxion_Box_Appliance_Image.md - DOC-13_Konnaxion_Threat_Model.md - DOC-14_Konnaxion_Operator_Guide.md - DOC-16_Konnaxion_Manager_GUI_Technical_Contract.md - DOC-17_Konnaxion_GUI_Action_Coverage_Contract.md - DOC-17A_Konnaxion_GUI_Action_Payload_Contract.md - DOC-19_Konnaxion_GUI_Page_Split_Droplet_Payload_Contract.md --- # DOC-12 — Konnaxion Install Runbook --- ## 1. Purpose This runbook defines the standard installation process for a **Konnaxion Capsule** on a **Konnaxion Box**, local demo server, intranet machine, or hardened VPS. The goal is plug-and-play operation: ```text 1. Prepare host or boot Konnaxion Box. 2. Open Konnaxion Capsule Manager. 3. Import .kxcap file. 4. Choose network profile. 5. Start instance. 6. Open generated URL. ``` The operator should not manually configure Docker Compose, Traefik, PostgreSQL, Redis, Celery, Django settings, Next.js runtime, certificates, ports, or firewall rules. For fresh public VPS or Droplet targets, the control plane must be bootstrapped before capsule deployment. In that case, the operator runs the GUI bootstrap action first: ```text bootstrap_droplet_agent ``` --- ## 2. Installation model The install process creates a **Konnaxion Instance** from a signed **Konnaxion Capsule**. ```text Konnaxion Capsule (.kxcap) ↓ imported by Konnaxion Capsule Manager ↓ controlled through Konnaxion Agent ↓ creates Konnaxion Instance ``` The capsule is immutable. The instance is mutable. ```text Capsule = app images + manifest + profiles + templates + checksums + signature Instance = secrets + database + media + logs + backups + runtime state ``` A `.kxcap` file is an application artifact. It is not the installer for the Konnaxion Manager, Konnaxion Agent, systemd services, or host control-plane runtime. --- ## 3. Supported installation targets | Target | Use case | Default profile | | -------------------------- | ---------------------------------- | ------------------ | | `Konnaxion Box` | Dedicated plug-and-play machine | `intranet_private` | | `Local demo host` | Developer or demo machine | `local_only` | | `Intranet server` | School, organization, office LAN | `intranet_private` | | `Private remote demo host` | Access through Tailscale/VPN | `private_tunnel` | | `Temporary demo host` | Short-lived public access | `public_temporary` | | `Public VPS` | Public production-style deployment | `public_vps` | | `DigitalOcean Droplet` | Public VPS-style deployment | `public_vps` | The default must never be public. ```env KX_NETWORK_PROFILE=intranet_private KX_EXPOSURE_MODE=private KX_PUBLIC_MODE_ENABLED=false ``` --- ## 4. Existing application stack Konnaxion v14 uses: ```text Frontend: Next.js / React / TypeScript Backend: Django 5.1 + Django REST Framework Database: PostgreSQL Background jobs: Celery Broker/result backend: Redis Reverse proxy: Traefik Media/static service: Nginx Runtime target: Docker Compose ``` The v14 technical reference identifies Konnaxion as a Next.js frontend, Django + DRF backend, PostgreSQL primary database, and Celery + Redis background-processing stack. The current production Docker environment includes Django, Postgres, Redis, Traefik, Celery worker, Celery beat, Flower, and Nginx for static/media handling. --- ## 5. Security baseline Every install must follow these rules: ```text private-by-default deny-by-default firewall signed capsules only secrets generated on install Traefik-only external entrypoint PostgreSQL internal only Redis internal only Docker socket never exposed no privileged containers no host network mode public temporary mode expires automatically Konnaxion Agent local-only by default ``` The previous Namecheap VPS incident included malicious Docker containers, miner activity, cron persistence, `/tmp/sshd`, `/dev/shm` executables, a `pakchoi` sudo backdoor attempt, and exposed secrets. The compromised VPS must not be trusted long-term and should not be cloned. --- ## 6. Ports policy ### 6.1 Public or LAN entrypoints | Port | Usage | Rule | | ----: | ---------------------- | ----------------------------------------------- | | `443` | HTTPS through Traefik | allowed according to profile | | `80` | HTTP redirect to HTTPS | allowed for `public_vps`; optional for intranet | | `22` | SSH | allowed only for maintenance, restricted | ### 6.2 Forbidden public ports These ports must never be exposed directly: ```text 3000/tcp Next.js direct access 5000/tcp Django/Gunicorn internal 5555/tcp Flower or dashboard 5432/tcp PostgreSQL 6379/tcp Redis 8000/tcp Django dev/server direct 8765/tcp Konnaxion Agent API 8714/tcp Konnaxion Manager API/UI Docker daemon TCP ports ``` Security notes from the incident recovery plan explicitly identify `3000`, `5555`, `5432`, `6379`, `8000`, and Docker daemon ports as non-public surfaces; public traffic should reach only Traefik on `80/443`. The Konnaxion Agent health endpoint is local-only on the target host: ```text http://127.0.0.1:8765/v1/health ``` Do not open `8765` publicly to make GUI checks pass. --- ## 7. Required artifacts Before installation, the operator must have: ```text 1. Konnaxion Capsule file: konnaxion-v14-demo-YYYY.MM.DD.kxcap 2. Konnaxion Capsule Manager installed or preloaded. 3. Konnaxion Agent running on the target host. 4. Docker runtime available. 5. Host with enough memory and disk. 6. Optional: - Tailscale account for private tunnel mode. - Cloudflare Tunnel credentials for temporary public mode. - VPS cloud firewall access for public_vps mode. ``` The capsule file must be produced by **Konnaxion Capsule Builder** and signed before distribution. ### 7.1 Control-plane bootstrap requirement A `.kxcap` file is an application deployment artifact. It is not the installer for the Konnaxion control plane. For any target that does not already include a preinstalled Konnaxion control plane, the target must be bootstrapped before capsule import or deployment. The control plane consists of: ```text Konnaxion Capsule Manager code Konnaxion Agent code Agent runtime/config directory Shared Manager/Agent state directory systemd service for Konnaxion Agent Docker runtime availability canonical /opt/konnaxion directory layout ``` For public VPS or Droplet deployments, the GUI action is: ```text bootstrap_droplet_agent ``` This action prepares the remote host over SSH before any capsule deployment action is allowed to succeed. The bootstrap action must create or validate: ```text /opt/konnaxion/ /opt/konnaxion/manager/ /opt/konnaxion/agent/ /opt/konnaxion/shared/ /opt/konnaxion/capsules/ /opt/konnaxion/instances/ /opt/konnaxion/backups/ /opt/konnaxion/releases/ ``` The Agent must bind only to localhost on the Droplet: ```env KX_AGENT_HOST=127.0.0.1 KX_AGENT_PORT=8765 ``` The Agent healthcheck is: ```text http://127.0.0.1:8765/v1/health ``` Port `8765` must not be opened publicly. Public application traffic must reach only Traefik on `80/443`. ### 7.2 Bootstrap artifact source For development builds, `bootstrap_droplet_agent` may copy the current local Konnaxion Capsule Manager repository to: ```text /opt/konnaxion/manager ``` For production builds, bootstrap should use a trusted release artifact instead of copying a working tree. The bootstrap artifact must not include: ```text .git/ .venv/ runtime/ __pycache__/ .pytest_cache/ .mypy_cache/ .ruff_cache/ dist/ build/ local secrets private SSH keys tokens .env files with production secrets ``` --- ## 8. Hardware requirements ### 8.1 Minimum ```text CPU: 2 cores RAM: 4 GB Disk: 80 GB SSD Network: Ethernet preferred OS: Ubuntu Server LTS or Konnaxion Box image ``` ### 8.2 Recommended ```text CPU: 4+ cores RAM: 8–16 GB Disk: 256 GB SSD/NVMe Network: wired Ethernet Power: UPS for intranet installations ``` The frontend deployment runbook confirms that `NODE_OPTIONS="--max-old-space-size=4096"` was required to avoid Next.js heap out-of-memory failures during production builds on limited-memory servers. For capsule installs, the frontend should normally be prebuilt inside the capsule. The memory note remains relevant for build hosts and builder machines. --- ## 9. Host preparation modes ## 9.1 Konnaxion Box mode This is the preferred plug-and-play mode. Expected starting point: ```text Konnaxion Box image already installed Konnaxion Capsule Manager preinstalled Konnaxion Agent enabled Docker installed Firewall enabled Default network profile: intranet_private ``` Operator flow: ```text 1. Plug machine into power. 2. Plug Ethernet. 3. Boot. 4. Open Konnaxion Capsule Manager. 5. Import .kxcap. 6. Click Start. ``` No shell access should be required for standard operation. --- ## 9.2 Generic Linux host mode For a generic Ubuntu/Debian machine: ```bash sudo apt update sudo apt upgrade -y sudo apt install -y \ ca-certificates \ curl \ gnupg \ ufw \ fail2ban \ unattended-upgrades ``` Install Docker according to the approved Konnaxion runtime package or appliance image process. Enable baseline firewall: ```bash sudo ufw default deny incoming sudo ufw default allow outgoing sudo ufw allow 443/tcp sudo ufw allow 80/tcp sudo ufw enable sudo ufw status verbose ``` For a pure intranet host, `80/443` may be limited to private LAN ranges by the Agent profile. --- ## 9.3 Public VPS mode Public VPS mode is not the default. Use only for `KX_NETWORK_PROFILE=public_vps`. Minimum baseline: ```text Ubuntu Server LTS SSH key only root SSH restricted or disabled after bootstrap password SSH disabled cloud firewall enabled UFW enabled Fail2Ban enabled unattended security updates enabled provider snapshots/backups enabled ``` Public VPS firewall: ```text Allow 80/tcp from anywhere Allow 443/tcp from anywhere Allow 22/tcp only from admin IP or VPN Deny everything else ``` The incident recovery guidance recommends a fresh VPS, no disk clone, clean source deploy, verified DB/media restore only, full secret rotation, SSH keys only, password login disabled, cloud firewall + UFW, and only ports `22`, `80`, and `443` public. --- ## 9.4 Public VPS first-time bootstrap mode A fresh public VPS or Droplet normally does not have Konnaxion Agent or Manager code preinstalled. Expected starting point for a fresh Droplet: ```text Ubuntu Server LTS SSH key access Docker installed or installable /opt/konnaxion may or may not exist Konnaxion Agent not running yet ``` Before `check_droplet_agent`, `copy_capsule_to_droplet`, or `deploy_droplet`, the operator must run: ```text bootstrap_droplet_agent ``` The bootstrap action must: ```text 1. Connect to the Droplet over SSH. 2. Create the canonical /opt/konnaxion directory layout. 3. Copy or install the trusted Manager/Agent code on the Droplet. 4. Install required Python/runtime tooling. 5. Write a systemd service for Konnaxion Agent. 6. Start Konnaxion Agent. 7. Verify Agent health from inside the Droplet using localhost. ``` The bootstrap action must not: ```text open Agent port 8765 publicly publish internal app service ports disable Security Gate install arbitrary third-party applications clone old compromised VPS disks copy local private keys or secrets into the capsule ``` The required successful healthcheck is: ```bash curl --fail --max-time 10 http://127.0.0.1:8765/v1/health ``` After bootstrap succeeds, the GUI Droplet workflow is: ```text 1. Check Droplet Agent 2. Copy Capsule to Droplet 3. Deploy Droplet 4. Start Droplet Instance only if needed ``` `Deploy Droplet` owns the normal deployment flow: ```text prepare remote runtime check Droplet Agent import capsule create or update instance set public_vps network profile run Security Gate start instance ``` --- ## 10. First install flow The standard first-run flow depends on whether the target already has Konnaxion Manager and Konnaxion Agent installed. ### 10.1 Targets with preinstalled Agent For Konnaxion Box, local demo host, or already-prepared intranet machines: ```text 1. Open Konnaxion Capsule Manager. 2. Select “Import Capsule”. 3. Choose .kxcap file. 4. Manager sends capsule to Konnaxion Agent. 5. Agent verifies signature. 6. Agent validates manifest. 7. Agent loads approved images. 8. Agent creates instance directory. 9. Agent creates canonical backup root. 10. Agent generates secrets. 11. Operator chooses network profile. 12. Agent runs Security Gate. 13. Agent starts runtime. 14. Agent runs migrations. 15. Agent runs healthchecks. 16. Agent creates and verifies initial backup. 17. Manager displays URL, status and backup health. ``` ### 10.2 Fresh public VPS or Droplet For a fresh public VPS or Droplet, the control plane must be bootstrapped first: ```text 1. Open local Konnaxion Capsule Manager. 2. Go to Targets. 3. Configure Droplet target. 4. Go to Deploy. 5. Run Bootstrap Droplet Agent. 6. Run Check Droplet Agent. 7. Build and verify .kxcap if not already done. 8. Run Copy Capsule to Droplet. 9. Run Deploy Droplet. 10. Open generated public URL. ``` The operator should only provide: ```text Instance name Target mode or network profile Admin account option Droplet host SSH user SSH key path Remote KX root Remote capsule directory Domain Explicit public VPS confirmation ``` Everything else is automatic. Install is complete only when: ```text Konnaxion Agent healthcheck passes capsule verification passes Security Gate is PASS runtime starts successfully healthchecks pass backup root exists initial backup is created and verified public URL resolves when public_vps is selected ``` --- ## 11. Import capsule ### 11.1 UI path ```text Konnaxion Capsule Manager → Capsules → Import Capsule → Select .kxcap ``` ### 11.2 CLI equivalent ```bash kx capsule import ./konnaxion-v14-demo-2026.04.30.kxcap ``` Expected result: ```text Capsule imported Signature: PASS Manifest: PASS Images: PASS Capsule state: ready ``` If signature verification fails: ```text State: security_blocked Action: reject capsule ``` Do not provide an override button in normal UI. --- ## 12. Create instance ### 12.1 UI path ```text Konnaxion Capsule Manager → Capsules → konnaxion-v14-demo-2026.04.30 → Create Instance ``` Required fields: ```text Instance name: demo-001 Network profile: intranet_private Admin account: auto-generate or user-provided ``` ### 12.2 CLI equivalent ```bash kx instance create \ --capsule konnaxion-v14-demo-2026.04.30 \ --instance demo-001 \ --network intranet_private ``` Expected instance path: ```text /opt/konnaxion/instances/demo-001/ ├── env/ ├── postgres/ ├── redis/ ├── media/ ├── logs/ ├── backups/ └── state/ ``` --- ## 13. Secret generation During instance creation, the Agent generates: ```text DJANGO_SECRET_KEY POSTGRES_PASSWORD internal service tokens admin bootstrap token profile-specific hostnames local TLS material if needed ``` The capsule must contain only templates, never real secrets. Example generated env target: ```text /opt/konnaxion/instances/demo-001/env/.django /opt/konnaxion/instances/demo-001/env/.postgres /opt/konnaxion/instances/demo-001/env/.frontend ``` If installing after a compromised server incident, rotate: ```text SSH keys deploy passwords DJANGO_SECRET_KEY POSTGRES_PASSWORD DATABASE_URL Neon/database credentials Django admin passwords API keys tokens private keys ``` The recovery notes specifically instruct rotating these credentials and avoiding `.env` leaks in logs or chat. --- ## 14. Choose network profile Supported profiles: ```text local_only intranet_private private_tunnel public_temporary public_vps offline ``` ### 14.1 local_only ```text URL: https://localhost Exposure: same machine only Ports: localhost only ``` ### 14.2 intranet_private ```text URL: https://konnaxion.local or generated LAN hostname Exposure: private LAN only Ports: 443 on LAN Public Internet: no ``` ### 14.3 private_tunnel ```text URL: private tunnel hostname Exposure: VPN/tailnet only Router ports: none Public Internet: no ``` ### 14.4 public_temporary ```text URL: temporary public tunnel Expiration: required Authentication: recommended Router ports: none ``` ### 14.5 public_vps ```text URL: https://domain Exposure: public 80/443 through Traefik only Cloud firewall: required SSH hardening: required Agent API: localhost-only ``` ### 14.6 offline ```text URL: local only or none Network: disabled except internal container network ``` --- ## 15. Security Gate Before start, the Agent must run: ```bash kx security check demo-001 ``` Required checks: ```text capsule_signature image_checksums manifest_schema secrets_present secrets_not_default firewall_enabled dangerous_ports_blocked postgres_not_public redis_not_public docker_socket_not_mounted no_privileged_containers no_host_network allowed_images_only admin_surface_private backup_configured agent_local_only ``` Allowed statuses: ```text PASS WARN FAIL_BLOCKING SKIPPED UNKNOWN ``` Start is allowed only if all critical checks return: ```text PASS SKIPPED ``` Start must be blocked if any critical check returns: ```text FAIL_BLOCKING UNKNOWN ``` --- ## 16. Start instance ### 16.1 UI path ```text Konnaxion Capsule Manager → Instances → demo-001 → Start ``` ### 16.2 CLI equivalent ```bash kx instance start demo-001 ``` Expected lifecycle: ```text verifying starting migrating healthchecking running ``` Expected services: ```text traefik frontend-next django-api postgres redis celeryworker celerybeat media-nginx ``` Optional/private: ```text flower ``` --- ## 17. Runtime startup sequence The Agent must start services in this order: ```text 1. Create Docker networks. 2. Create volumes. 3. Start postgres. 4. Start redis. 5. Run database readiness check. 6. Run Django migrations. 7. Start django-api. 8. Start celeryworker. 9. Start celerybeat. 10. Start media-nginx. 11. Start frontend-next. 12. Start traefik. 13. Run healthchecks. 14. Mark instance running. ``` Production capsule installs must run: ```bash python manage.py migrate ``` They must not run: ```bash python manage.py makemigrations ``` Migration files must already be included in the capsule. The existing backend workflow confirms the required operational pattern: build/start Docker services, generate migrations during development, apply `migrate`, verify service status, and optionally create a superuser. For capsule runtime, only `migrate` belongs in the install path. --- ## 18. Verify installation ### 18.1 Manager UI Expected status: ```text Instance: demo-001 State: running Network profile: intranet_private Exposure: private Security Gate: PASS Healthchecks: PASS Backup: PASS Backup root: /opt/konnaxion/backups/demo-001 Public mode: disabled ``` For public VPS or Droplet mode: ```text Instance: demo-001 State: running Network profile: public_vps Exposure: public Security Gate: PASS Healthchecks: PASS Backup: PASS Public URL: https:// Agent API: local-only ``` The install is not complete if backup status is missing, unverified, failed, quarantined, or unknown. ### 18.2 CLI ```bash kx instance status demo-001 kx security check demo-001 kx instance logs demo-001 --tail 100 ``` Expected services: ```text traefik: healthy frontend-next: healthy django-api: healthy postgres: healthy redis: healthy celeryworker: healthy celerybeat: healthy media-nginx: healthy ``` ### 18.3 Initial backup validation A first verified backup must exist after install. ```bash kx instance backup demo-001 --class manual kx backup list demo-001 kx backup verify ``` Expected backup state: ```text Backup status: verified Backup class: manual Backup root: /opt/konnaxion/backups/demo-001/ Security Gate: PASS Secrets included: false Forbidden paths included: false ``` The Manager UI should show: ```text Backup health: PASS Last backup: Restore readiness: PASS ``` ### 18.4 HTTP checks For local mode: ```bash curl -k -I https://localhost/ curl -k -I https://localhost/api/ curl -k -I https://localhost/admin/ ``` For intranet mode: ```bash curl -k -I https://konnaxion.local/ curl -k -I https://konnaxion.local/api/ curl -k -I https://konnaxion.local/admin/ ``` For public VPS mode: ```bash curl -I https:/// curl -I https:///api/ curl -I https:///admin/ ``` The legacy deployment guide expects `/` to route to Next.js, `/api/` to Django, `/admin/` to Django admin, and `/media/` to the media service. --- ## 19. Verify blocked ports Run: ```bash sudo ss -tulpen ``` There must be no public listeners for: ```text 0.0.0.0:3000 0.0.0.0:5000 0.0.0.0:5555 0.0.0.0:5432 0.0.0.0:6379 0.0.0.0:8000 0.0.0.0:8765 0.0.0.0:8714 ``` For `public_vps`, expected external exposure: ```text 0.0.0.0:80 0.0.0.0:443 restricted:22 ``` For `intranet_private`, expected exposure is profile-specific and should be LAN-only. The Konnaxion Agent may listen on: ```text 127.0.0.1:8765 ``` The Konnaxion Manager may listen locally on: ```text 127.0.0.1:8714 ``` Neither Manager nor Agent should be public on a production VPS. --- ## 20. Admin bootstrap During first install, the operator chooses one of: ```text Auto-generate admin account Create admin account manually Import admin bootstrap file ``` ### 20.1 Auto-generate The Agent creates: ```text username: generated or provided temporary password: generated once must_change_password: true ``` The Manager displays the temporary password once. ### 20.2 Manual CLI fallback ```bash kx instance exec demo-001 django-api -- python manage.py createsuperuser ``` This should be hidden from standard users and used only by operators. --- ## 21. Backup configuration Backups must be enabled by default. ```env KX_BACKUP_ENABLED=true KX_BACKUP_RETENTION_DAYS=14 KX_BACKUP_ROOT=/opt/konnaxion/backups ``` ### 21.1 Canonical backup storage Canonical backup storage: ```text /opt/konnaxion/backups// ``` Example: ```text /opt/konnaxion/backups/demo-001/ ├── daily/ ├── weekly/ ├── monthly/ ├── pre-update/ ├── pre-restore/ └── manual/ ``` The instance-local backup directory is not the canonical storage root. It may exist only as a pointer, cache or state directory: ```text /opt/konnaxion/instances//backups/ ``` ### 21.2 Backup directory creation During install, the Agent must create and validate: ```bash sudo mkdir -p /opt/konnaxion/backups/demo-001/{daily,weekly,monthly,pre-update,pre-restore,manual} sudo chown -R kx-agent:konnaxion /opt/konnaxion/backups/demo-001 sudo chmod -R 750 /opt/konnaxion/backups/demo-001 ``` The exact user/group may vary by appliance implementation, but the directory must not be world-readable. ### 21.3 Backup contents Backup contents: ```text PostgreSQL logical dump media files instance metadata redacted env metadata without secret values capsule reference manifest reference network profile Security Gate result healthcheck result checksums ``` ### 21.4 Forbidden backup contents Do not back up: ```text /tmp /dev/shm host crontabs unknown systemd services old authorized_keys old sudoers files unknown Docker volumes Docker daemon state old compromised disk images plaintext secrets ``` The incident recovery rule is that backups must recover application data, not preserve malware or host persistence. ### 21.5 Initial verified backup After the first successful install, the Agent must create a first verified backup. ```bash kx instance backup demo-001 --class manual kx backup verify ``` Expected output: ```text Backup created: backup_id: demo-001_YYYYMMDD_HHMMSS_manual backup_root: /opt/konnaxion/backups/demo-001/manual/demo-001_YYYYMMDD_HHMMSS_manual status: verified ``` The Manager UI must show: ```text Backup health: PASS Last backup: Restore readiness: PASS ``` A Konnaxion Instance is not considered fully installed until backup verification passes. --- ## 22. Update instance Update requires a new signed capsule. ```bash kx capsule import ./konnaxion-v14-demo-2026.05.01.kxcap kx instance update demo-001 --capsule konnaxion-v14-demo-2026.05.01 ``` Update flow: ```text 1. Verify new capsule. 2. Run Security Gate pre-check. 3. Backup current instance. 4. Stop app services. 5. Apply new capsule references. 6. Run migrations. 7. Start services. 8. Run healthchecks. 9. Mark update complete. ``` If healthcheck fails, rollback begins automatically. --- ## 23. Rollback instance Manual rollback: ```bash kx instance rollback demo-001 ``` Rollback flow: ```text 1. Stop failed services. 2. Restore previous capsule pointer. 3. Restore previous runtime config if needed. 4. Restore DB backup if migration is not backward-compatible. 5. Start previous stack. 6. Run healthchecks. 7. Mark running or degraded. ``` Rollback is only safe if the previous backup exists and the database migration is either backward-compatible or restored. --- ## 24. Public temporary mode Public temporary mode is for short external demos only. Rules: ```text KX_PUBLIC_MODE_ENABLED=true KX_PUBLIC_MODE_EXPIRES_AT required authentication recommended automatic expiration required manual permanent public exposure forbidden ``` Start temporary access: ```bash kx network set-profile demo-001 public_temporary \ --duration-hours 2 ``` Expected: ```text Temporary public URL generated Expiration set Security Gate passed ``` After expiration: ```text Public tunnel closed KX_PUBLIC_MODE_ENABLED=false Network profile returns to previous private profile ``` --- ## 25. Public VPS mode Public VPS mode is for real public deployment. Preconditions: ```text fresh VPS not cloned from compromised server cloud firewall configured SSH key-only authentication password login disabled root login restricted or disabled after bootstrap UFW enabled Fail2Ban enabled unattended upgrades enabled backups/snapshots enabled Konnaxion Agent running on localhost only ``` The new deployment must not reuse old secrets or old server state. The recovery plan recommends clean Git/source deployment, verified DB dump/media only, full secret rotation, firewall before app exposure, and validating access only through `80/443`. ### 25.1 Public VPS control-plane bootstrap A fresh VPS must be bootstrapped before the first capsule deployment. Required GUI flow: ```text Targets → Set Droplet Target Deploy → Bootstrap Droplet Agent → Check Droplet Agent → Copy Capsule to Droplet → Deploy Droplet ``` The bootstrap action must use SSH and must not require public access to Agent port `8765`. Expected post-bootstrap check from inside the Droplet: ```bash curl --fail --max-time 10 http://127.0.0.1:8765/v1/health ``` Expected public check from outside the Droplet: ```text http://:8765/v1/health must not be reachable ``` --- ## 26. Uninstall instance Stop instance: ```bash kx instance stop demo-001 ``` Create final backup: ```bash kx instance backup demo-001 ``` Remove instance: ```bash kx instance remove demo-001 ``` The Manager must clearly distinguish: ```text Remove instance but keep backups Remove instance and delete backups ``` Default: ```text keep backups ``` --- ## 27. Decommission host For a host that is no longer trusted: ```text 1. Export verified DB dump. 2. Export required media only. 3. Copy backups off-host. 4. Rotate secrets. 5. Destroy VPS or wipe disk. 6. Do not reuse Docker volumes. 7. Do not reuse SSH keys. 8. Do not reuse authorized_keys. 9. Do not reuse crontabs. 10. Do not reuse systemd services. ``` For compromised hosts, never create a new Konnaxion Box image from that disk. --- ## 28. Troubleshooting ## 28.1 Capsule import fails Symptoms: ```text Signature: FAIL_BLOCKING Manifest: FAIL_BLOCKING Image checksum mismatch ``` Action: ```text Reject capsule. Do not start instance. Rebuild capsule from trusted source. ``` --- ## 28.2 Security Gate blocks start Check: ```bash kx security check demo-001 ``` Common causes: ```text dangerous port exposed Docker socket mounted unknown image found Postgres exposed publicly Redis exposed publicly firewall disabled public mode missing expiration Agent API exposed publicly ``` Action: ```text Fix profile or capsule. Re-run Security Gate. Do not bypass. ``` --- ## 28.3 Database migration fails Check logs: ```bash kx instance logs demo-001 --service django-api --tail 200 kx instance logs demo-001 --service postgres --tail 200 ``` Action: ```text Stop update. Keep backup. Rollback if needed. Do not run makemigrations on target host. ``` --- ## 28.4 Frontend fails healthcheck Check: ```bash kx instance logs demo-001 --service frontend-next --tail 200 ``` Possible causes: ```text bad baked API URL missing production build memory-related build problem on builder ``` The legacy frontend runbook notes that production frontend values are baked at build time and that `.next/BUILD_ID` must exist before starting Next.js. In capsule mode, frontend should be prebuilt during capsule build. --- ## 28.5 Public URL works but API fails Check routing: ```bash curl -I https:/// curl -I https:///api/ curl -I https:///admin/ curl -I https:///media/ ``` Expected routing: ```text / -> frontend-next /api/ -> django-api /admin/ -> django-api /media/ -> media-nginx ``` If `/api/` fails, inspect: ```bash kx instance logs demo-001 --service traefik --tail 200 kx instance logs demo-001 --service django-api --tail 200 ``` --- ## 28.6 Suspicious host state Run host inspection: ```bash echo "== users ==" cut -d: -f1,3,7 /etc/passwd | sort echo "== sudoers ==" sudo ls -la /etc/sudoers.d sudo grep -R . /etc/sudoers.d /etc/sudoers 2>/dev/null echo "== cron ==" sudo crontab -l || true crontab -l || true sudo ls -la /etc/cron.* /var/spool/cron/crontabs 2>/dev/null echo "== suspicious tmp/shm ==" sudo find /tmp /dev/shm -maxdepth 2 -type f -executable -ls 2>/dev/null echo "== ports ==" sudo ss -tulpen echo "== docker ==" docker ps -a --format "table {{.Names}}\t{{.Image}}\t{{.Status}}\t{{.Ports}}" 2>/dev/null || true docker images 2>/dev/null || true ``` Look for: ```text amco_* negoroo/amco supportxmr rx/0 /tmp/sshd pakchoi /dev/shm executable files unexpected crontabs unexpected sudoers files unknown Docker containers ``` These indicators match the previous compromise pattern. --- ## 28.7 Droplet Agent check fails Symptoms: ```text Check Droplet Agent failed curl to public :8765 times out curl to 127.0.0.1:8765 on the Droplet fails no konnaxion-agent systemd service /opt/konnaxion/agent missing /opt/konnaxion/manager missing /opt/konnaxion/shared missing ``` Meaning: ```text The Droplet control plane has not been bootstrapped. ``` Action: ```text Run Bootstrap Droplet Agent from the Manager GUI Deploy page. ``` Do not fix this by opening port `8765` publicly. Expected successful local Droplet healthcheck: ```bash curl --fail --max-time 10 http://127.0.0.1:8765/v1/health ``` Expected external state: ```text http://:8765/v1/health is not reachable publicly ``` --- ## 29. Standard install checklist Before install: ```text [ ] Host is fresh or trusted. [ ] Host is not cloned from compromised VPS. [ ] Konnaxion Capsule Manager installed or available locally. [ ] Konnaxion Agent running on target host or bootstrap action available. [ ] Docker runtime available. [ ] Firewall enabled. [ ] .kxcap file available. [ ] Capsule source trusted. ``` For fresh public VPS or Droplet targets: ```text [ ] Droplet target configured in Manager GUI. [ ] SSH key path exists on local Manager host. [ ] Remote KX root configured. [ ] Remote capsule directory configured. [ ] Domain configured. [ ] Public VPS confirmation checked. [ ] Bootstrap Droplet Agent completed. [ ] Check Droplet Agent completed. [ ] Agent is reachable on target localhost. [ ] Agent port 8765 is not public. ``` During install: ```text [ ] Capsule imported. [ ] Signature PASS. [ ] Manifest PASS. [ ] Images PASS. [ ] Instance created. [ ] Secrets generated. [ ] Network profile selected. [ ] Security Gate PASS. [ ] Runtime started. [ ] Migrations applied. [ ] Healthchecks PASS. [ ] Initial backup PASS. ``` After install: ```text [ ] URL opens. [ ] /api/ responds. [ ] /admin/ responds. [ ] /media/ responds if media is present. [ ] No dangerous ports public. [ ] Agent API is not public. [ ] Manager API is not public. [ ] Backup root created. [ ] Initial backup created. [ ] Initial backup verified. [ ] Manager UI shows Backup health PASS. [ ] Admin account created. [ ] Public mode disabled unless explicitly required. [ ] Logs show no secret leakage. ``` --- ## 30. Operator quick path For standard intranet install: ```bash kx capsule import ./konnaxion-v14-demo-2026.04.30.kxcap kx instance create \ --capsule konnaxion-v14-demo-2026.04.30 \ --instance demo-001 \ --network intranet_private kx security check demo-001 kx instance start demo-001 kx instance status demo-001 kx instance backup demo-001 --class manual kx backup list demo-001 kx backup verify ``` Expected final state: ```text Instance: demo-001 State: running Network profile: intranet_private Exposure: private Security Gate: PASS Backup health: PASS Restore readiness: PASS URL: https://konnaxion.local or generated LAN URL ``` ### 30.1 GUI quick path for fresh Droplet ```text 1. Start local Agent and Manager. 2. Open http://127.0.0.1:8714/ui. 3. Go to Capsules. 4. Build capsule using Public VPS profile. 5. Verify capsule. 6. Go to Targets. 7. Set Droplet Target. 8. Go to Deploy. 9. Bootstrap Droplet Agent. 10. Check Droplet Agent. 11. Copy Capsule to Droplet. 12. Deploy Droplet. 13. Open generated public URL. ``` Expected final state: ```text Instance: demo-001 State: running Network profile: public_vps Exposure: public Security Gate: PASS Backup health: PASS Restore readiness: PASS URL: https:// Agent API: localhost-only Public ports: 80, 443, restricted 22 only ``` --- ## 31. Non-goals This runbook does not cover: ```text Building a capsule from source Changing application code Writing migrations Designing Docker images Generic Docker hosting Kubernetes deployment Recovering secrets from compromised hosts Cloning old VPS disks Running arbitrary third-party apps Opening Konnaxion Agent publicly Using public Agent API as a deployment transport ``` Those are covered by other documents or explicitly out of scope. --- ## 32. Summary The Konnaxion install process must be: ```text plug-and-play private-by-default security-gated capsule-driven repeatable rollback-capable operator-safe bootstrap-aware for fresh VPS targets ``` The canonical install path is: ```text Bootstrap target control plane when missing Verify Konnaxion Agent health Import signed .kxcap Create Konnaxion Instance Generate secrets Choose network profile Run Security Gate Start Docker Compose runtime Apply migrations Run healthchecks Create backup root Create and verify initial backup Display URL ``` The user should configure only: ```text Instance name Target mode or network profile Admin account option Droplet connection details only when using public_vps/Droplet mode ``` Everything else is handled by the **Konnaxion Capsule Manager** and **Konnaxion Agent**. ================================================================================================ FILE: docs/DOC-13_Konnaxion_Threat_Model.md AUTHORITY: reference CONTENT_ROLE: knowledge CONTENT_SHA256: 019ac09c9625f43448bac0df63a890b8f7a59bafb8899bdfacbbee46de0244ed CONTENT_BYTES: 31694 ================================================================================================ --- doc_id: DOC-13 title: Konnaxion Threat Model project: Konnaxion app_version: v14 param_version: kx-param-2026.04.30 status: draft owner: Konnaxion Architecture depends_on: - DOC-00_Konnaxion_Canonical_Variables.md - DOC-03_Konnaxion_Capsule_Format.md - DOC-05_Konnaxion_Agent_Security_Model.md - DOC-06_Konnaxion_Network_Profiles.md - DOC-07_Konnaxion_Security_Gate.md - DOC-08_Konnaxion_Runtime_Docker_Compose.md --- # DOC-13 — Konnaxion Threat Model ## 0. Purpose This document defines the canonical threat model for the Konnaxion Capsule architecture. It covers: ```text Konnaxion Capsule Konnaxion Capsule Manager Konnaxion Agent Konnaxion Box / Host Docker Compose Runtime Konnaxion Instance Network profiles Secrets Backups Updates / rollback Public and private exposure modes ``` The goal is not only to describe risks. The goal is to define which risks must be prevented by architecture, which risks must be detected, and which risks must block startup. --- ## 1. Canonical security principle Konnaxion must be: ```text private-by-default deny-by-default signed-by-default least-privilege-by-default recoverable-by-default ``` The user experience target remains plug-and-play, but the system must not let plug-and-play become insecure-by-default. The user should choose simple modes such as: ```text Local Intranet Private Tunnel Public Temporary VPS Public ``` The system translates those choices into firewall rules, routing, container policies, secrets, certificates and health checks. --- ## 2. Security baseline The Konnaxion threat model assumes the following baseline: ```text 1. The capsule is signed. 2. The capsule contains no real secrets. 3. Secrets are generated on install. 4. Postgres is never exposed publicly. 5. Redis is never exposed publicly. 6. Docker socket is never mounted into application containers. 7. Docker daemon TCP is never exposed. 8. Next.js direct port is never public. 9. Django/Gunicorn direct port is never public. 10. Flower/dashboard surfaces are private only. 11. Traefik is the only public-facing entrypoint. 12. Public mode is never the default. 13. Temporary public mode must expire automatically. 14. The host firewall is deny-by-default. 15. Unknown containers or unknown images are blocking findings. ``` --- ## 3. System under threat model ### 3.1 Target architecture ```text Konnaxion Box / Host ├── Konnaxion Capsule Manager │ └── User-facing UI ├── Konnaxion Agent │ └── Privileged local service with allowlisted operations ├── Docker Engine / Compose Runtime │ └── Konnaxion Instance │ ├── traefik │ ├── frontend-next │ ├── django-api │ ├── media-nginx │ ├── postgres │ ├── redis │ ├── celeryworker │ └── celerybeat └── Host security layer ├── firewall ├── updates ├── logs ├── backups └── monitoring ``` ### 3.2 Canonical runtime routing ```text https:/// -> frontend-next https:///api/ -> django-api https:///admin/ -> django-api https:///media/ -> media-nginx ``` ### 3.3 Internal-only services ```text postgres redis celeryworker celerybeat flower, unless explicitly enabled in private mode ``` --- ## 4. Trust boundaries | Boundary | Description | Trust level | |---|---|---| | User browser → Traefik | User traffic enters Konnaxion | Untrusted | | Traefik → frontend-next | Internal reverse proxy traffic | Controlled | | Traefik → django-api | Internal reverse proxy traffic | Controlled | | django-api → postgres | Application data path | Sensitive | | django-api → redis | Job/broker path | Sensitive | | celeryworker → postgres/redis | Background processing path | Sensitive | | Manager UI → Agent | Local management API | Sensitive | | Agent → Docker Engine | Privileged orchestration path | Critical | | Agent → firewall | Privileged network control | Critical | | Capsule file → Manager | Supply-chain input | Untrusted until verified | | Backup archive → restore flow | Recovery input | Untrusted until verified | | Tunnel provider → Traefik | Temporary exposure path | Untrusted external edge | The most sensitive trust boundary is: ```text Konnaxion Agent -> Docker / firewall / host system ``` The Agent must not behave like a generic shell or unrestricted Docker frontend. --- ## 5. Assets to protect ### 5.1 Critical assets | Asset | Why it matters | |---|---| | `DJANGO_SECRET_KEY` | Session/signing security | | `POSTGRES_PASSWORD` | Database access | | `DATABASE_URL` | Full DB connection authority | | Admin credentials | Full platform control | | API tokens | External service access | | Private keys | Identity and encryption | | PostgreSQL data | Core user/platform data | | Media uploads | User files and content | | Capsule signing key | Supply-chain root of trust | | Konnaxion Agent control API | Privileged local control | | Backup archives | Full data recovery material | | Docker Engine access | Root-equivalent in many setups | | Network profile state | Determines exposure level | ### 5.2 Sensitive operational assets ```text logs crash dumps .env files capsule manifests healthcheck output backup metadata public tunnel URLs temporary admin credentials ``` Logs must never print full secrets. --- ## 6. Attacker profiles | Actor | Capability | Primary concern | |---|---|---| | Internet scanner | Finds open ports and weak services | Exposed dashboards, DB, Redis, SSH | | Opportunistic bot | Exploits known CVEs / weak configs | Container compromise, web exploit | | Malicious capsule distributor | Ships modified `.kxcap` | Supply-chain compromise | | Local network attacker | Same LAN as Konnaxion Box | Intranet sniffing, admin UI abuse | | Compromised admin workstation | Has access to Manager UI or capsule files | Credential theft, malicious deploy | | Malicious insider | Has physical or local access | Export data, alter config | | Malware on host | Attempts persistence and credential theft | Cron/systemd/backdoor persistence | | Misconfigured operator | Accidentally exposes internal ports | Repeat of public attack surface | | Compromised tunnel token | Opens unintended public access | Persistent public exposure | --- ## 7. Historical incident assumptions The previous VPS incident proves the threat model must assume: ```text 1. A server can be compromised during deployment. 2. Docker can be abused to run malicious containers. 3. Cron can be used for persistence. 4. Temporary directories can hide malware. 5. A malicious user/backdoor can be attempted. 6. Secrets on the host can be exposed. 7. Cleanup is not equivalent to trust restoration. 8. Rebuild from clean source is the long-term recovery path. ``` Therefore, Konnaxion Capsule architecture must prefer: ```text clean rebuild signed artifacts secret rotation known images only known containers only known ports only verified backups only ``` --- ## 8. Attack surfaces ### 8.1 External network | Surface | Threat | Required control | |---|---|---| | `80/tcp` | HTTP downgrade / ACME path abuse | Redirect to HTTPS, minimal middleware | | `443/tcp` | App exploit surface | Traefik only, security headers | | Public tunnel | Accidental public exposure | Expiration, auth, audit log | | SSH | Brute force / stolen key | Disabled by default for Box, key-only for VPS | | Admin UI | Account takeover | MFA recommended, rate limits, private by default | ### 8.2 Internal network | Surface | Threat | Required control | |---|---|---| | Postgres | Data theft/destruction | Internal Docker network only | | Redis | Job injection / data leakage | Internal Docker network only | | Celery worker | Code execution via job payloads | Authenticated app-only access | | Flower/dashboard | Operational leak/control | Disabled or private only | | Docker network | Lateral movement | Dedicated isolated network per instance | ### 8.3 Host | Surface | Threat | Required control | |---|---|---| | Docker socket | Root-equivalent host control | Never mounted into app containers | | Docker group | Root-equivalent for users | Avoid broad membership | | Systemd services | Persistence | Known service allowlist | | Cron | Persistence | Monitor and verify | | `/tmp`, `/dev/shm` | Malware staging | Monitor known IoCs, no trust in old host | | Firewall | Exposure drift | Managed by Agent, audited | | Backups | Malware preservation | Data-only backup policy | ### 8.4 Capsule supply chain | Surface | Threat | Required control | |---|---|---| | `.kxcap` file | Tampering | Signature required | | `manifest.yaml` | Port/image/volume abuse | Schema + policy validation | | OCI images | Malicious code | Checksums + allowlist | | env templates | Default secrets | No real secrets, no insecure defaults | | migration scripts | Destructive schema/code actions | Declared, reviewed, logged | | seed data | Embedded malicious payloads | Sanitize and size-limit | ### 8.5 Manager / Agent | Surface | Threat | Required control | |---|---|---| | Manager UI | CSRF/local web abuse | Local auth token, loopback binding | | Agent API | Privileged action abuse | mTLS or local socket ACLs | | Agent command execution | Arbitrary shell execution | No generic shell endpoint | | Docker calls | Unknown privileged containers | Policy allowlist | | Network mode changes | Unsafe exposure | Security Gate before applying | | Update flow | Malicious capsule update | Verify before switch | --- ## 9. STRIDE model ### 9.1 Spoofing | Threat | Example | Control | |---|---|---| | Fake capsule | Attacker provides modified `.kxcap` | Signature verification | | Fake Manager UI | Phishing local admin page | Signed app, local URL clarity | | Fake service | Rogue container named like official service | Service/image allowlist | | Fake admin | Stolen admin credential | MFA, password rotation, audit | Blocking controls: ```text KX_REQUIRE_SIGNED_CAPSULE=true KX_ALLOW_UNKNOWN_IMAGES=false KX_SECURITY_GATE_REQUIRED=true ``` ### 9.2 Tampering | Threat | Example | Control | |---|---|---| | Manifest edited | Adds public Postgres port | Schema + policy validation | | Image replaced | Modified backend image | Checksum validation | | Env file altered | Enables DEBUG or weak secrets | Security Gate checks | | Firewall altered | Opens `3000` or `5432` | Drift detection | | Backup altered | Restore malicious data/config | Restore verification | Blocking conditions: ```text manifest_schema = FAIL_BLOCKING image_checksums = FAIL_BLOCKING dangerous_ports_blocked = FAIL_BLOCKING secrets_not_default = FAIL_BLOCKING ``` ### 9.3 Repudiation | Threat | Example | Control | |---|---|---| | Operator denies enabling public tunnel | Missing audit log | Append-only event log | | Capsule source unclear | No provenance | Capsule metadata + signature | | Security override unclear | Manual change not tracked | Change log with reason | | Admin account action unclear | Lack of audit trail | App-level audit events | Required event log fields: ```yaml timestamp: actor: instance_id: action: network_profile: result: security_gate_result: capsule_id: capsule_version: ``` ### 9.4 Information disclosure | Threat | Example | Control | |---|---|---| | Secrets in logs | `.env` dumped to support log | Secret redaction | | DB exposed | `5432` bound publicly | Internal network only | | Redis exposed | `6379` public | Internal network only | | Admin dashboard public | Flower/Traefik dashboard visible | Private only | | Backup leak | Unencrypted dump copied | Protected backup path | | Analytics re-identification | Small cohort export | k-anonymity and export limits | ### 9.5 Denial of service | Threat | Example | Control | |---|---|---| | Public bot traffic | Overloads demo box | Rate limit / temporary public only | | Heavy frontend build | Exhausts RAM | Prebuilt capsule images | | Redis exhaustion | Job flood | Queue limits, internal only | | Disk exhaustion | Logs/backups fill disk | Retention policy | | CPU miner | Malicious process | Known process/container monitoring | | Failed migration | App down after update | Backup + rollback | ### 9.6 Elevation of privilege | Threat | Example | Control | |---|---|---| | Docker group abuse | User gains root-level host control | No broad Docker group access | | Privileged container | Container escapes/is too powerful | `privileged: false`, blocked | | Host network | Container bypasses network isolation | `network_mode: host` blocked | | Docker socket mount | Container controls Docker | Mount blocked | | Agent shell endpoint | UI becomes root shell | No generic command API | | Backdoor user | Malicious local sudo user | User/service allowlist checks | Blocking policies: ```yaml allow_privileged_containers: false allow_host_network: false allow_docker_socket_mount: false allow_unknown_images: false allow_unknown_containers: false ``` --- ## 10. Threat scenarios and required responses ### T01 — User imports a modified capsule **Scenario:** A `.kxcap` has been altered after build. **Impact:** Supply-chain compromise. **Required detection:** ```text signature invalid checksum mismatch manifest hash mismatch ``` **Required response:** ```text FAIL_BLOCKING Do not import. Do not extract images. Do not start instance. Show "Capsule verification failed." ``` --- ### T02 — Capsule tries to expose Postgres **Scenario:** `docker-compose.capsule.yml` includes: ```text 5432:5432 ``` **Impact:** Direct database exposure. **Required response:** ```text FAIL_BLOCKING Reject capsule or profile. ``` **Canonical rule:** ```text Postgres must be internal only in every profile. ``` --- ### T03 — Capsule tries to mount Docker socket **Scenario:** A service attempts: ```text /var/run/docker.sock:/var/run/docker.sock ``` **Impact:** Container can control Docker and likely host. **Required response:** ```text FAIL_BLOCKING ``` **Canonical rule:** ```text Application containers must never mount Docker socket. ``` --- ### T04 — Operator enables public temporary mode and forgets it **Scenario:** Public tunnel remains open. **Impact:** Demo becomes public long-term. **Required controls:** ```text expiration required max duration enforced auto-close timer audit event visible status in UI ``` **Required response after expiry:** ```text close tunnel return to previous private profile log event show status: public expired ``` --- ### T05 — Host firewall drift opens internal ports **Scenario:** A manual firewall change exposes `3000`, `5432`, `6379`, `5555` or `8000`. **Impact:** Direct service exposure. **Required detection:** ```text scheduled security check pre-start check network profile check ``` **Required response:** ```text FAIL_BLOCKING if startup WARN or auto-remediate if running show "Firewall drift detected" ``` --- ### T06 — Unknown container appears **Scenario:** Docker shows a container not declared by the active capsule. **Impact:** Possible compromise or operator drift. **Required response:** ```text instance status = degraded or security_blocked show unknown container name/image prevent update/start until resolved ``` For a Konnaxion Box, unknown containers should be treated as suspicious by default. --- ### T07 — Secrets appear in logs **Scenario:** `.env`, `DATABASE_URL`, `DJANGO_SECRET_KEY` or API tokens are printed. **Impact:** Credential disclosure. **Required response:** ```text redact in Manager UI flag security warning recommend secret rotation prevent uploading raw logs through support export ``` --- ### T08 — Restore from old compromised disk **Scenario:** Operator tries to restore full disk image or old Docker volumes after compromise. **Impact:** Malware and persistence restored. **Required response:** ```text block as unsupported recovery path allow only DB dump + media restore require new secrets require clean capsule ``` Canonical restore policy: ```text restore data, not machines restore verified data, not runtime state ``` --- ### T09 — Malicious cron/systemd persistence **Scenario:** Host contains unknown cron or systemd entries. **Impact:** Malware persistence. **Required detection:** ```text host integrity check known service allowlist cron scan ``` **Required response:** ```text security_blocked for public modes degraded for private modes unless manually accepted ``` --- ### T10 — Manager UI abused by local webpage **Scenario:** A browser page tries to call the Manager local API. **Impact:** Local privilege escalation through browser. **Required controls:** ```text Manager API bound to loopback or Unix socket CSRF protection random local auth token Origin checks no unauthenticated privileged actions ``` --- ## 11. Network profile threat controls ### 11.1 `local_only` | Risk | Control | |---|---| | Accidental LAN exposure | Bind to `127.0.0.1` only | | Browser abuse | Local auth token | | Public cert confusion | Use local cert or HTTP loopback only | Required: ```text KX_EXPOSURE_MODE=private No public tunnel No LAN bind No router instructions ``` ### 11.2 `intranet_private` | Risk | Control | |---|---| | Same-LAN attacker | HTTPS, admin auth | | Accidental WAN exposure | No router port forwarding | | mDNS spoofing | Clear host fingerprint / local cert warning handling | Required: ```text Bind 443 on LAN interface Block all internal service ports Show LAN URL Do not configure public DNS ``` ### 11.3 `private_tunnel` | Risk | Control | |---|---| | Unauthorized tunnel user | Tunnel access policy | | Stale device access | Tailnet/device review | | Token leak | Token storage protection | Required: ```text No public router port Tunnel identity required Visible status in Manager ``` ### 11.4 `public_temporary` | Risk | Control | |---|---| | Forgotten exposure | Expiration required | | Link sharing | Optional access password/auth | | Abuse traffic | Rate limit / max duration | | Misleading status | Prominent UI banner | Required: ```text KX_PUBLIC_MODE_ENABLED=true KX_PUBLIC_MODE_EXPIRES_AT required Max duration enforced Auto-close required ``` ### 11.5 `public_vps` | Risk | Control | |---|---| | Internet scanning | Cloud firewall + UFW | | SSH brute force | key-only, restricted IP | | Public dashboard | dashboard disabled/private | | Server compromise | backups, updates, monitoring | | Secrets on host | secret rotation, no logs | Required: ```text 80/443 public 22 restricted 3000/5432/6379/5555/8000 blocked Docker TCP blocked ``` --- ## 12. Required Security Gate checks The Security Gate must run: ```text before import before first start before profile change before public temporary mode before update before restore on scheduled health checks ``` ### 12.1 Blocking checks | Check | Blocking condition | |---|---| | `capsule_signature` | invalid, missing, unknown signer | | `manifest_schema` | invalid or unsupported version | | `image_checksums` | mismatch | | `allowed_images_only` | unknown image | | `dangerous_ports_blocked` | public/internal forbidden port exposed | | `postgres_not_public` | Postgres published | | `redis_not_public` | Redis published | | `docker_socket_not_mounted` | socket mounted | | `no_privileged_containers` | `privileged: true` | | `no_host_network` | `network_mode: host` | | `secrets_present` | required secret missing after install | | `secrets_not_default` | default placeholder secret | | `public_mode_expiry` | missing expiry for public temporary | | `unknown_containers` | unknown running container in managed namespace | | `agent_policy_valid` | Agent would execute unallowlisted action | ### 12.2 Warning checks | Check | Warning condition | |---|---| | `backup_configured` | backup disabled in local-only mode | | `host_updates` | updates pending | | `disk_space` | below warning threshold | | `log_retention` | not configured | | `admin_mfa` | not enabled | | `monitoring_configured` | missing optional alerts | --- ## 13. Container policy Every service in `docker-compose.capsule.yml` must satisfy: ```yaml privileged: false read_only: true where possible restart: unless-stopped networks: - konnaxion_internal ``` Disallowed patterns: ```yaml network_mode: host privileged: true pid: host ipc: host volumes: - /:/host - /var/run/docker.sock:/var/run/docker.sock ports: - "5432:5432" - "6379:6379" - "3000:3000" - "5555:5555" - "8000:8000" ``` Allowed published ports by profile: ```yaml local_only: - 127.0.0.1:443:443 intranet_private: - :443:443 private_tunnel: - 127.0.0.1:443:443 public_temporary: - 127.0.0.1:443:443 public_vps: - 0.0.0.0:80:80 - 0.0.0.0:443:443 ``` --- ## 14. Secret handling policy ### 14.1 Required generated secrets ```text DJANGO_SECRET_KEY POSTGRES_PASSWORD KX_INSTANCE_SECRET KX_LOCAL_MANAGER_TOKEN initial admin password or invite token tunnel token, if enabled backup encryption key, if enabled ``` ### 14.2 Rules ```text 1. Capsules contain templates only. 2. Real secrets are generated on install. 3. Secrets are stored under the instance, not inside the capsule. 4. Secrets must not be printed in logs. 5. Secret export requires explicit user action. 6. Secret rotation must be supported. 7. Restore must not reuse compromised secrets by default. ``` ### 14.3 Redaction patterns The Manager and Agent logs must redact: ```text DATABASE_URL= POSTGRES_PASSWORD= DJANGO_SECRET_KEY= SECRET_KEY= API_KEY= TOKEN= PRIVATE_KEY= BEGIN RSA PRIVATE KEY BEGIN OPENSSH PRIVATE KEY ``` --- ## 15. Backup and restore threat model ### 15.1 Backup scope Allowed backup contents: ```text Postgres dump media/uploads instance metadata sanitized manifest non-secret configuration snapshot ``` Protected or encrypted backup contents: ```text secrets admin recovery token tunnel config backup key material ``` Disallowed backup contents: ```text entire old disk /tmp /dev/shm unknown Docker volumes old crontabs old systemd units old authorized_keys old sudoers files malware cleanup workspace ``` ### 15.2 Restore controls Before restore: ```text verify backup metadata verify capsule compatibility scan for disallowed paths generate or rotate secrets unless explicitly preserving run migration dry-run if possible take pre-restore snapshot ``` After restore: ```text run Security Gate run app healthchecks verify no internal ports are public verify admin login verify migrations ``` --- ## 16. Update and rollback threat model ### 16.1 Update risks ```text malicious capsule update schema migration failure incompatible seed data partial image load old secrets carried forward unsafely public mode state retained unexpectedly rollback disabled by destructive migration ``` ### 16.2 Required update flow ```text 1. Verify new capsule. 2. Backup database and media. 3. Check migration plan. 4. Load images. 5. Start new stack or update stack. 6. Run migrations. 7. Run healthchecks. 8. Switch active capsule. 9. Keep previous capsule available for rollback. 10. If failure, rollback automatically where safe. ``` ### 16.3 Rollback constraints Rollback is allowed only if: ```text previous capsule exists backup exists migration compatibility is known Security Gate passes after rollback network profile remains safe ``` --- ## 17. Logging and monitoring ### 17.1 Required logs ```text Agent action log Manager UI event log Security Gate results Network profile changes Public tunnel open/close events Capsule import/verify events Backup/restore events Update/rollback events Unknown container findings Firewall drift findings ``` ### 17.2 Log requirements ```text structured JSON preferred timestamps in UTC instance_id included capsule_id included actor included when known result included no raw secrets ``` Example: ```json { "timestamp": "2026-04-30T17:30:00Z", "event": "network_profile_changed", "instance_id": "demo-001", "actor": "local_admin", "from": "intranet_private", "to": "public_temporary", "expires_at": "2026-04-30T19:30:00Z", "security_gate": "PASS" } ``` --- ## 18. Incident response model ### 18.1 Severity levels | Severity | Meaning | Example | |---|---|---| | `SEV-1` | Active compromise or public critical exposure | Unknown container + public DB | | `SEV-2` | Serious security drift | Firewall opened internal port | | `SEV-3` | Contained risk | Backup disabled | | `SEV-4` | Low-risk warning | Updates pending | ### 18.2 Automatic responses | Finding | Response | |---|---| | Unknown container | Mark instance `security_blocked` | | Public Postgres/Redis | Block startup, close profile change | | Invalid capsule signature | Reject import | | Missing public expiry | Reject public mode | | Docker socket mount | Reject capsule | | Privileged container | Reject capsule | | Host network | Reject capsule | | Secret in logs | Redact + recommend rotation | | Firewall drift | Auto-remediate if Manager owns firewall | ### 18.3 Manual recovery principle If host compromise is suspected: ```text Do not harden the same host as final fix. Do not clone the disk. Do not restore old Docker volumes blindly. Rebuild from clean capsule/source. Restore only verified data. Rotate secrets. ``` --- ## 19. Risk register | ID | Risk | Likelihood | Impact | Rating | Required mitigation | |---|---|---:|---:|---:|---| | R01 | Public exposure of Postgres | Medium | Critical | High | Blocking port policy | | R02 | Public exposure of Redis | Medium | Critical | High | Blocking port policy | | R03 | Docker socket exposed | Low | Critical | High | Compose policy validation | | R04 | Malicious capsule | Medium | Critical | High | Signature + checksums | | R05 | Unknown container compromise | Medium | Critical | High | Container allowlist | | R06 | Secret leakage in logs | Medium | High | High | Redaction + rotation | | R07 | Forgotten public tunnel | Medium | High | High | Mandatory expiry | | R08 | Host firewall drift | Medium | High | High | Drift detection | | R09 | Weak/default secrets | Medium | High | High | Generated secrets only | | R10 | Backup preserves malware | Medium | High | High | Data-only backups | | R11 | Failed update/migration | Medium | Medium | Medium | Backup + rollback | | R12 | LAN attacker abuses intranet mode | Medium | Medium | Medium | HTTPS + auth | | R13 | Admin credential theft | Medium | High | High | MFA + rotation | | R14 | Denial of service on demo box | Medium | Medium | Medium | public temporary limits | | R15 | Misuse of Agent API | Low | Critical | High | Allowlisted API only | --- ## 20. Non-goals This threat model does not attempt to solve: ```text nation-state adversaries physical hardware tampering by a skilled attacker full endpoint compromise of every admin device zero-day vulnerabilities in the OS or Docker Engine formal compliance certification multi-tenant hostile SaaS isolation ``` Konnaxion Capsule is designed for: ```text local demos private intranet deployment temporary public demos small production VPS deployments controlled organizational environments ``` It is not yet designed as a hardened multi-tenant public cloud platform. --- ## 21. MVP security acceptance criteria A Konnaxion Capsule MVP is not acceptable unless all of the following pass: ```text [ ] Invalid capsule signatures are rejected. [ ] Capsule contains no real secrets. [ ] Install generates new secrets. [ ] Postgres is not public. [ ] Redis is not public. [ ] Docker socket is not mounted. [ ] Privileged containers are blocked. [ ] Host network mode is blocked. [ ] Unknown images are blocked. [ ] Unknown containers trigger security status. [ ] Public temporary mode requires expiry. [ ] Public temporary mode auto-closes. [ ] Manager UI shows active network profile. [ ] Manager UI shows security status. [ ] Security Gate can block startup. [ ] Backup contains data only, not full host runtime. [ ] Restore runs Security Gate after completion. [ ] Logs redact known secret patterns. ``` --- ## 22. Test cases ### 22.1 Capsule validation tests ```text TC-13-001: Import unsigned capsule -> FAIL_BLOCKING TC-13-002: Import capsule with invalid checksum -> FAIL_BLOCKING TC-13-003: Import capsule with unsupported manifest version -> FAIL_BLOCKING TC-13-004: Import capsule with unknown image -> FAIL_BLOCKING TC-13-005: Import capsule with Docker socket mount -> FAIL_BLOCKING TC-13-006: Import capsule with privileged container -> FAIL_BLOCKING TC-13-007: Import capsule with host network -> FAIL_BLOCKING ``` ### 22.2 Network tests ```text TC-13-101: local_only binds only to localhost TC-13-102: intranet_private exposes only 443 on LAN TC-13-103: public_temporary requires expires_at TC-13-104: public_temporary closes after expiry TC-13-105: public_vps exposes only 80/443 publicly TC-13-106: postgres is unreachable from host public interface TC-13-107: redis is unreachable from host public interface TC-13-108: port 3000 is not public TC-13-109: port 5555 is not public ``` ### 22.3 Runtime tests ```text TC-13-201: Unknown container triggers security_blocked TC-13-202: Unknown image triggers security warning/block TC-13-203: Firewall drift is detected TC-13-204: Secret pattern is redacted from logs TC-13-205: Backup does not include /tmp or /dev/shm TC-13-206: Restore rejects backup with disallowed paths TC-13-207: Failed update rolls back where safe ``` --- ## 23. Canonical policy snippets ### 23.1 Security policy ```yaml security: private_by_default: true deny_by_default: true require_signed_capsule: true generate_secrets_on_install: true allow_unknown_images: false allow_unknown_containers: false allow_privileged_containers: false allow_host_network: false allow_docker_socket_mount: false expose_database: false expose_redis: false expose_frontend_direct: false expose_django_direct: false ``` ### 23.2 Public temporary policy ```yaml public_temporary: enabled_by_default: false require_expiration: true max_duration_hours: 8 require_security_gate_pass: true auto_close_on_expiry: true show_visible_banner: true ``` ### 23.3 Port policy ```yaml blocked_public_ports: - 3000 - 5000 - 5432 - 6379 - 5555 - 8000 allowed_public_ports_by_profile: local_only: [] intranet_private: - 443 private_tunnel: [] public_temporary: [] public_vps: - 80 - 443 ``` --- ## 24. Documentation alignment rules Any future document that mentions security, capsule import, runtime, ports, Docker, secrets, backups, updates, public mode, or intranet mode must align with this threat model. A future document must not introduce: ```text a public database port a public Redis port a public direct Next.js port a public direct Django/Gunicorn port a non-expiring public temporary mode real secrets inside capsules unverified capsules unknown images by default Docker socket mounts privileged containers host network containers ``` Any exception requires a formal architecture decision record. --- ## 25. Summary The Konnaxion threat model is built around one product requirement: ```text Konnaxion must feel plug-and-play, but behave like a locked-down appliance. ``` The architecture therefore uses: ```text signed capsules generated secrets deny-by-default network policy strict Docker policy Security Gate blocking checks private-by-default network profiles temporary public exposure with expiry data-only backups clean rebuild recovery ``` This is the security foundation for Konnaxion Capsule, Konnaxion Capsule Manager, Konnaxion Agent and Konnaxion Box. ================================================================================================ FILE: docs/DOC-14_Konnaxion_Operator_Guide.md AUTHORITY: reference CONTENT_ROLE: knowledge CONTENT_SHA256: 597ccb82ba63821d3afea0143b209e33cfb1b4dc0e5917ad553c3d71daeb774d CONTENT_BYTES: 30044 ================================================================================================ --- doc_id: DOC-14 title: Konnaxion Operator Guide project: Konnaxion app_version: v14 param_version: kx-param-2026.04.30 status: draft owner: Konnaxion last_updated: 2026-04-30 audience: - operators - demo facilitators - local administrators - support staff depends_on: - DOC-00_Konnaxion_Canonical_Variables.md - DOC-02_Konnaxion_Capsule_Architecture.md - DOC-03_Konnaxion_Capsule_Format.md - DOC-04_Konnaxion_Manager_Architecture.md - DOC-05_Konnaxion_Agent_Security_Model.md - DOC-06_Konnaxion_Network_Profiles.md - DOC-07_Konnaxion_Security_Gate.md - DOC-08_Konnaxion_Runtime_Docker_Compose.md - DOC-09_Konnaxion_Backup_Restore_Rollback.md --- # DOC-14 — Konnaxion Operator Guide ## 1. Purpose This document explains how to operate a **Konnaxion Instance** using the **Konnaxion Capsule Manager**. It is written for operators, demo facilitators, support staff, and local administrators. The operator should not need to understand Docker, Traefik, PostgreSQL, Redis, Celery, Django, Next.js, firewall rules, or environment files. The normal operating model is: ```text Open Konnaxion Capsule Manager Choose an instance Start / stop / backup / update / restore Use the displayed URL Respect Security Gate results ``` --- ## 2. Operator Scope Operators may: ```text start Konnaxion stop Konnaxion restart Konnaxion view instance status view safe logs run Security Gate checks change approved network profiles create backups restore approved backups apply verified capsule updates rollback after failed update export support bundles ``` Operators must not: ```text edit Docker Compose files manually edit firewall rules manually edit .env files manually open internal ports manually run arbitrary containers mount Docker socket disable Security Gate import unsigned capsules restore old compromised disks copy secrets into chat, tickets, or logs ``` --- ## 3. Canonical Terms Use these names consistently. | Term | Meaning | |---|---| | **Konnaxion Capsule** | Signed `.kxcap` package containing app images, manifest, profiles, templates, and checksums | | **Konnaxion Capsule Manager** | User-facing app used by operators | | **Konnaxion Agent** | Local privileged service that performs approved actions | | **Konnaxion Instance** | Installed runtime instance with data, secrets, media, logs, and backups | | **Konnaxion Box** | Dedicated machine running the Manager and the instance | | **Security Gate** | Blocking safety validation before start/update/network exposure | | **Network Profile** | Predefined exposure mode such as `local_only`, `intranet_private`, or `public_temporary` | --- ## 4. Default Safety Position The default state is private. ```env KX_NETWORK_PROFILE=intranet_private KX_EXPOSURE_MODE=private KX_PUBLIC_MODE_ENABLED=false ``` The Manager must not expose Konnaxion publicly unless the operator explicitly chooses an approved public profile. The preferred operating profiles are: ```text local_only intranet_private private_tunnel ``` The high-risk profiles are: ```text public_temporary public_vps ``` High-risk profiles require Security Gate validation before activation. --- ## 5. Operator Dashboard The Manager home screen must show: ```text Instance name Lifecycle state Network profile Exposure mode Primary URL Security Gate status Backup status App version Capsule version Last health check Last backup ``` Example: ```text Instance: demo-001 State: running Network: intranet_private Exposure: private URL: https://konnaxion.local Security: PASS Backups: enabled App Version: v14 Capsule: konnaxion-v14-demo-2026.04.30 ``` Required buttons: ```text Open Konnaxion Start Stop Restart Security Check View Logs Backup Restore Update Change Network Profile Export Support Bundle ``` --- ## 6. Lifecycle States The operator may see these states. | State | Meaning | Operator action | |---|---|---| | `created` | Instance exists but has not been verified | Run verification | | `verifying` | Capsule or instance checks are running | Wait | | `ready` | Instance can be started | Start | | `starting` | Runtime is starting | Wait | | `running` | Instance is online | Operate normally | | `stopping` | Instance is shutting down | Wait | | `stopped` | Instance is offline | Start or leave stopped | | `updating` | Update is in progress | Do not interrupt | | `rolling_back` | Rollback is in progress | Do not interrupt | | `degraded` | Instance is running with warnings | Review health/logs | | `failed` | Instance failed | Export support bundle | | `security_blocked` | Security Gate blocked action | Do not bypass; fix cause | --- ## 7. Daily Operating Procedure ### 7.1 Start of Day 1. Open **Konnaxion Capsule Manager**. 2. Confirm the correct `Konnaxion Instance` is selected. 3. Confirm the intended `KX_NETWORK_PROFILE`. 4. Run **Security Check**. 5. Confirm result is `PASS`. 6. Click **Start**. 7. Wait for state `running`. 8. Click **Open Konnaxion**. 9. Confirm the Konnaxion login/home page loads. CLI equivalent: ```bash kx instance status demo-001 kx security check demo-001 kx instance start demo-001 kx instance status demo-001 ``` Success criteria: ```text State: running Security: PASS Primary URL responds No public internal ports Last backup status visible ``` --- ### 7.2 End of Day 1. Confirm no active demo or user session is required. 2. Create a backup. 3. Wait for backup verification. 4. Stop the instance if the box is not needed overnight. 5. Confirm state is `stopped`. CLI equivalent: ```bash kx instance backup demo-001 kx instance stop demo-001 kx instance status demo-001 ``` Success criteria: ```text Backup completed Backup verified State: stopped No public temporary tunnel active ``` --- ## 8. Starting an Instance ### 8.1 Normal Start Use the Manager button: ```text Start ``` The Manager must automatically run: ```text manifest validation signature check image checksum validation secret presence check firewall check dangerous port check runtime health check ``` If all required checks pass, the instance starts. ### 8.2 Start Blocked by Security Gate If startup is blocked, the Manager displays: ```text State: security_blocked Security result: FAIL_BLOCKING ``` Operator action: ```text Do not retry blindly. Read the failed check. Export support bundle if the cause is not obvious. Escalate to technical maintainer. ``` Do not use manual Docker commands to bypass the block. --- ## 9. Stopping an Instance Use the Manager button: ```text Stop ``` The Manager must stop services in a safe order: ```text public tunnel if enabled Traefik exposure frontend-next django-api celerybeat celeryworker redis postgres media-nginx ``` The operator should wait for: ```text State: stopped ``` CLI equivalent: ```bash kx instance stop demo-001 ``` --- ## 10. Restarting an Instance Use restart when: ```text the app is sluggish a configuration profile was changed a support instruction requests restart the instance is degraded but not failed ``` Do not restart during: ```text backup restore update rollback migration ``` CLI equivalent: ```bash kx instance stop demo-001 kx instance start demo-001 ``` Success criteria: ```text State returns to running Health is healthy or acceptable Security remains PASS ``` --- ## 11. Network Profile Operations The operator must choose only predefined network profiles. | Profile | Use case | Exposure | |---|---|---| | `local_only` | Demo on the Konnaxion Box itself | Local machine only | | `intranet_private` | LAN/intranet demo | Local network only | | `private_tunnel` | Private remote access | VPN/tailnet only | | `public_temporary` | Time-limited external demo | Temporary public tunnel | | `public_vps` | Managed public server | Public 80/443 only | | `offline` | No network access | No external access | --- ### 11.1 Local Only Use for: ```text testing before a demo private local review offline presentation ``` Expected URL: ```text https://localhost ``` Allowed exposure: ```text localhost only ``` Operator checks: ```text No LAN URL shown No public URL shown No tunnel active ``` --- ### 11.2 Intranet Private Use for: ```text school network office network community center private LAN demo ``` Expected URL examples: ```text https://konnaxion.local https://konnaxion.lan ``` Allowed exposure: ```text LAN HTTPS only ``` Operator checks: ```text Internet exposure: disabled Allowed LAN port: 443 Postgres: blocked Redis: blocked Docker socket: blocked ``` --- ### 11.3 Private Tunnel Use for: ```text remote team demo trusted collaborator access support session ``` Allowed exposure: ```text private VPN/tailnet only ``` Operator checks: ```text No router port forwarding required Access limited to approved users/devices Public URL not displayed unless explicitly configured ``` --- ### 11.4 Public Temporary Use only for: ```text client demo public preview external stakeholder review ``` Required conditions: ```text expiration time set Security Gate PASS authentication enabled if available operator confirms public exposure no internal service exposed ``` Required variables: ```env KX_PUBLIC_MODE_ENABLED=true KX_PUBLIC_MODE_EXPIRES_AT= ``` The Manager must reject public temporary mode if `KX_PUBLIC_MODE_EXPIRES_AT` is empty. Operator checklist: ```text Set duration: 1h / 2h / 8h Confirm generated public URL Send only the public URL Monitor session Disable public mode after demo Confirm tunnel closed ``` CLI equivalent: ```bash kx network set-profile demo-001 public_temporary --duration-hours 2 kx security check demo-001 ``` --- ### 11.5 Public VPS Use only for a production-style environment. Required conditions: ```text clean VPS or trusted host SSH key only firewall enabled 80/443 only public 22 restricted Security Gate PASS backups enabled monitoring enabled ``` This profile is not the default demo mode. --- ## 12. Security Rules for Operators Operators must remember one rule: ```text Only the Manager exposes Konnaxion. Never expose internal services directly. ``` Always blocked: ```text 3000/tcp frontend-next direct 5000/tcp django-api direct 5432/tcp PostgreSQL 6379/tcp Redis 5555/tcp Flower/dashboard 8000/tcp Django development server Docker daemon TCP ``` Allowed through Traefik only: ```text / /api/ /admin/ /media/ ``` If a user asks to connect to Postgres, Redis, or Docker remotely, escalate to a technical maintainer. Do not open the ports manually. --- ## 13. Security Gate Results ### 13.1 PASS Meaning: ```text All required checks passed. Operation may continue. ``` Action: ```text Proceed. ``` ### 13.2 WARN Meaning: ```text Non-blocking issue detected. ``` Action: ```text Proceed only if the warning is understood. Document the warning in the operator log. Escalate if repeated. ``` ### 13.3 FAIL_BLOCKING Meaning: ```text The operation is unsafe. ``` Action: ```text Do not proceed. Do not bypass. Export support bundle. Escalate. ``` ### 13.4 SKIPPED Meaning: ```text Check does not apply to this profile. ``` Action: ```text No action unless unexpected. ``` ### 13.5 UNKNOWN Meaning: ```text The Manager could not verify the check. ``` Action: ```text Treat as suspicious if related to firewall, ports, secrets, or signatures. Escalate if it affects startup or public exposure. ``` --- ## 14. Logs Operators may view logs through the Manager. Allowed log categories: ```text manager agent traefik frontend-next django-api postgres redis celeryworker celerybeat media-nginx backup security network ``` The Manager must redact secrets. Never copy full values of: ```text DJANGO_SECRET_KEY POSTGRES_PASSWORD DATABASE_URL API keys tokens private keys session secrets SSH keys ``` Safe support excerpt: ```text timestamp service error code redacted message instance ID capsule version network profile ``` Unsafe support excerpt: ```text full .env file full DATABASE_URL secret keys private keys tokens passwords ``` --- ## 15. Backups Backups are mandatory operational safety controls, not optional convenience features. The operator-facing rule is: ```text Create backup. Verify backup. Only then update, restore, rollback, or perform risky maintenance. ``` ### 15.1 Backup Scope A valid Konnaxion backup includes: ```text PostgreSQL logical dump media files instance metadata capsule reference network profile reference redacted environment metadata backup manifest checksums verification result healthcheck snapshot ``` A normal operator backup must not include: ```text temporary files runtime sockets unknown Docker volumes raw old disk images /tmp /dev/shm crontabs authorized_keys sudoers files Docker daemon state Docker socket unredacted logs containing secrets ``` The operator must not attempt to recover Konnaxion by restoring a full old server image. Restore must use a verified backup set plus a trusted capsule. --- ### 15.2 Backup Classes Operators may see these backup classes: | Class | Meaning | |---|---| | `daily` | Automatic routine backup | | `weekly` | Automatic longer-retention backup | | `monthly` | Automatic archive backup | | `pre-update` | Created before applying a capsule update | | `pre-restore` | Created before restoring over an existing instance | | `manual` | Created by operator action | --- ### 15.3 Create Backup Use the Manager button: ```text Backup ``` Recommended operator flow: ```text 1. Open Konnaxion Capsule Manager. 2. Select the instance. 3. Click Backup. 4. Choose backup class: manual. 5. Wait for backup creation. 6. Wait for verification. 7. Confirm Backup health: PASS. ``` The Manager must show: ```text Backup ID backup class created_at capsule version database size media size checksum result verification result ``` CLI equivalent: ```bash kx instance backup demo-001 --class manual kx backup verify ``` Success criteria: ```text Backup status: verified Verification: PASS Backup visible in backup list No secret leak warning No forbidden path warning ``` --- ### 15.4 Verify Backup Every backup must be verifiable before it is trusted. Operator action: ```text Open Backups Select latest backup Confirm Verification: PASS Confirm Security: PASS or WARN only ``` CLI equivalent: ```bash kx backup verify ``` If verification fails: ```text Do not use this backup for restore. Do not delete the last known-good backup. Create another backup. Export support bundle. Escalate if repeated. ``` If verification reports leaked secrets: ```text Do not export or share the backup. Quarantine the backup. Escalate. Rotate affected secrets. ``` --- ### 15.5 Test Restore When time allows, the safest validation is a test restore into a temporary local-only instance. Operator action: ```text Open Backups Select backup Click Test Restore Choose temporary instance Confirm network profile: local_only Run test Destroy temporary instance after PASS ``` CLI equivalent: ```bash kx backup test-restore \ --temporary-instance restore-test-YYYYMMDD_HHMMSS \ --network local_only \ --destroy-after-pass ``` Success criteria: ```text Temporary instance created Restore completed Security Gate: PASS Health: healthy Temporary instance destroyed after test, if requested ``` --- ### 15.6 Restore Backup Into New Instance This is the preferred restore method for high-risk recovery. Use this when: ```text the current instance may be damaged the operator wants to validate data before replacing current state the host was recently rebuilt support requests a safe restore ``` Operator flow: ```text 1. Open Backups. 2. Select a verified backup. 3. Click Restore. 4. Choose Restore into new instance. 5. Set network profile to local_only or intranet_private. 6. Run restore. 7. Run Security Gate. 8. Run healthchecks. 9. Switch users to the restored instance only after PASS. ``` CLI equivalent: ```bash kx instance restore-new \ --from \ --new-instance-id demo-restore-001 \ --network local_only ``` Success criteria: ```text New instance created Restore completed Security: PASS Health: healthy Data appears correct Original instance remains unchanged ``` --- ### 15.7 Restore Backup Over Existing Instance Restoring over an existing instance is allowed, but it is riskier. Use only when: ```text data was accidentally deleted support confirms the restore path restore-new is not practical operator accepts downtime ``` Before restore, the Manager must create a `pre-restore` backup unless the instance is already unrecoverable. Operator flow: ```text 1. Select backup. 2. Confirm Verification: PASS. 3. Confirm selected target instance. 4. Confirm what will be overwritten. 5. Confirm pre-restore backup will be created. 6. Type the required confirmation phrase. 7. Run restore. 8. Run Security Gate. 9. Run healthchecks. ``` Required confirmation phrase: ```text RESTORE demo-001 ``` CLI equivalent: ```bash kx instance restore demo-001 \ --from \ --mode full ``` Success criteria: ```text Pre-restore backup created Database restored Media restored Migrations completed if required Security: PASS Health: healthy User data appears correct ``` --- ### 15.8 Backup Failure If backup fails: ```text Do not update. Do not restore. Do not delete older backups. Check logs. Export support bundle. Escalate if repeated. ``` If the failed backup was required before an update, the update must be cancelled. --- ## 16. Updates ### 16.1 Update Capsule Use the Manager button: ```text Update ``` Update flow: ```text 1. Verify new capsule signature. 2. Verify new capsule checksums. 3. Check compatibility. 4. Create pre-update backup. 5. Verify pre-update backup. 6. Stage update. 7. Apply new capsule. 8. Run migrations if required. 9. Start updated instance. 10. Run Security Gate. 11. Run healthchecks. 12. Mark update successful only after PASS. ``` Operator must confirm: ```text New capsule is signed Pre-update backup completed Pre-update backup verification passed Compatibility check passed Security Gate passed Rollback point exists ``` CLI equivalent: ```bash kx capsule verify konnaxion-v14-demo-YYYY.MM.DD.kxcap kx instance update demo-001 \ --capsule konnaxion-v14-demo-YYYY.MM.DD.kxcap \ --auto-rollback true ``` Success criteria: ```text State: running Security: PASS Health: healthy Backup: verified Current capsule updated Previous capsule kept as rollback point ``` --- ### 16.2 Update Failure If update fails, the Manager may show: ```text State: failed State: degraded State: rolling_back State: security_blocked ``` Operator action: ```text Do not force start. Do not expose publicly. Wait for automatic capsule rollback if active. Check Security Gate result. Export support bundle. Escalate if rollback fails. ``` If the update failed before database migrations changed data, capsule rollback is usually enough. If the update changed database or media state, support may instruct the operator to perform data rollback from the pre-update backup. --- ### 16.3 Update With Public Exposure If the instance is using `public_temporary` or `public_vps`, the Manager must reduce risk during update. Required behavior: ```text create pre-update backup verify backup pause or close public temporary tunnel if applicable apply update run Security Gate run healthchecks restore exposure only after PASS ``` Operator must not manually re-enable public exposure after a failed update. --- ## 17. Rollback Rollback returns the instance to a previous known-good state. There are three operator-visible rollback levels: | Level | Meaning | Default use | |---|---|---| | Capsule rollback | Return to previous capsule version | First response after failed update | | Data rollback | Restore database/media from backup | Only when data changed or became corrupted | | Full rollback | Restore capsule reference plus data backup | Last resort after failed update | --- ### 17.1 Capsule Rollback Capsule rollback is the safest first rollback. Use when: ```text update fails healthchecks fail after update critical feature is broken after update Security Gate blocks the new capsule support instructs rollback ``` CLI equivalent: ```bash kx instance rollback demo-001 --level capsule ``` Success criteria: ```text Previous capsule restored Database unchanged unless required State: running Security: PASS Health: healthy User data consistent ``` --- ### 17.2 Data Rollback Data rollback restores database and/or media from a verified backup. Use when: ```text data was corrupted migration changed data and update failed media changed during a failed update support instructs data rollback ``` CLI equivalent: ```bash kx instance rollback demo-001 \ --level data \ --from ``` Success criteria: ```text Pre-rollback backup created Selected backup verified Database/media restored Security: PASS Health: healthy ``` --- ### 17.3 Full Rollback Full rollback combines capsule rollback and data rollback. Use only when: ```text capsule rollback did not fix the instance database or media state is incompatible with the previous capsule support confirms full rollback is required ``` CLI equivalent: ```bash kx instance rollback demo-001 \ --level full \ --from ``` Success criteria: ```text Previous capsule restored Backup data restored Security: PASS Health: healthy Network profile remains safe ``` Rollback does not replace backups. A rollback path is only safe when backup verification has passed. --- ## 18. Health Checks The Manager should show health for: ```text manager agent docker traefik frontend-next django-api postgres redis celeryworker celerybeat media-nginx backup security network ``` Canonical health values: ```text healthy degraded unhealthy unknown stopped ``` Operator response: | Health | Action | |---|---| | `healthy` | Continue | | `degraded` | Check logs and monitor | | `unhealthy` | Restart if safe, then escalate | | `unknown` | Run Security Check and health refresh | | `stopped` | Start if expected | --- ## 19. Common Problems ### 19.1 Konnaxion URL Does Not Load Check: ```text Instance state is running Network profile is correct Primary URL is correct Traefik health is healthy frontend-next health is healthy django-api health is healthy ``` Operator action: ```text Run health check Restart if no backup/update is running Export support bundle if unresolved ``` --- ### 19.2 Login Page Loads but API Fails Likely affected services: ```text django-api postgres redis Traefik route /api/ ``` Operator action: ```text Check django-api logs Check postgres health Check Traefik health Do not expose backend directly Escalate if unresolved ``` --- ### 19.3 Background Tasks Not Running Likely affected services: ```text redis celeryworker celerybeat ``` Operator action: ```text Check worker health Check redis health Restart instance if safe Escalate if repeated ``` --- ### 19.4 Backup Fails Operator action: ```text Check available disk space in Manager Check postgres health Check media size Retry once Escalate if repeated ``` Do not delete old backups until a new verified backup exists. --- ### 19.5 Security Gate Blocks Public Mode Operator action: ```text Do not bypass. Read failed checks. Return to intranet_private if demo can continue privately. Export support bundle. Escalate. ``` --- ## 20. Emergency Procedures ### 20.1 Suspected Compromise Indicators: ```text unknown containers unknown Docker images unexpected public ports unknown admin users unexpected sudoers entries unexpected cron jobs /tmp or /dev/shm executables miner-like CPU usage unexpected outbound network traffic security checks failing suddenly ``` Immediate action: ```text 1. Disable public_temporary or public_vps exposure. 2. Disconnect from public network if needed. 3. Stop Konnaxion Instance. 4. Do not delete evidence unless instructed. 5. Export support bundle. 6. Rotate secrets if exposure is confirmed. 7. Rebuild on clean host if compromise is credible. ``` Never trust a compromised host as the long-term fix. --- ### 20.2 Public Tunnel Left Open Action: ```text Open Network Profile screen Disable public_temporary Confirm KX_PUBLIC_MODE_ENABLED=false Confirm public URL no longer works Run Security Check ``` CLI equivalent: ```bash kx network set-profile demo-001 intranet_private kx security check demo-001 ``` --- ### 20.3 Lost Admin Password Action: ```text Use Manager's Reset Admin flow if available. Require local operator confirmation. Generate temporary password. Force password change at next login if supported. Log the action. ``` Do not expose database or shell access to reset passwords manually unless a technical maintainer authorizes it. --- ### 20.4 Host Will Be Retired Before retiring a Konnaxion Box: ```text Create final verified backup Export backup to approved storage Stop instance Remove public tunnel Wipe secrets if decommissioning Record capsule version and backup ID ``` --- ## 21. Support Bundle Operators may export a support bundle. Allowed contents: ```text instance.yaml manager version agent version capsule ID capsule version network profile Security Gate results health summary redacted logs backup metadata runtime service list redacted compose summary ``` Forbidden contents: ```text full .env files private keys tokens database passwords Django secret key raw database dump user-uploaded media unless explicitly requested unredacted logs ``` Support bundle filename: ```text konnaxion-support--.zip ``` --- ## 22. Operator Checklists ### 22.1 Pre-Demo Checklist ```text [ ] Correct instance selected [ ] Network profile selected [ ] Security Gate PASS [ ] Backup exists [ ] Primary URL loads [ ] Login works [ ] Demo account works [ ] No public tunnel unless needed [ ] Public tunnel has expiration if enabled ``` ### 22.2 Post-Demo Checklist ```text [ ] Disable public temporary access [ ] Confirm private mode [ ] Create backup if data changed [ ] Export notes if needed [ ] Stop instance if not needed [ ] Confirm state stopped or private running ``` ### 22.3 Update Checklist ```text [ ] New capsule received [ ] Capsule verified [ ] Backup created [ ] Compatibility passed [ ] Security Gate PASS [ ] Update applied [ ] Health checks passed [ ] Rollback point retained ``` ### 22.4 Incident Checklist ```text [ ] Public exposure disabled [ ] Instance stopped if necessary [ ] Evidence preserved [ ] Support bundle exported [ ] Secrets identified for rotation [ ] Clean rebuild considered [ ] Incident notes recorded ``` --- ## 23. CLI Quick Reference The operator should prefer the Manager UI. CLI is available for support or advanced operation. ```bash kx instance status demo-001 kx security check demo-001 kx instance start demo-001 kx instance stop demo-001 kx instance logs demo-001 kx instance backup demo-001 --class manual kx backup list demo-001 kx backup verify kx backup test-restore kx instance restore-new --from --new-instance-id demo-restore-001 kx instance restore demo-001 --from --mode full kx capsule verify .kxcap kx capsule import .kxcap # Installed artifact discovery/lifecycle kx artifact list kx artifact list --products-only kx artifact list --composition-candidates kx artifact show kx artifact remove kx instance update demo-001 --capsule .kxcap --auto-rollback true kx instance rollback demo-001 --level capsule kx instance rollback demo-001 --level data --from kx instance rollback demo-001 --level full --from kx network set-profile demo-001 intranet_private ``` Never use raw Docker commands unless operating under technical maintainer instructions. Artifact removal is fail-closed. If the target is required by another installed artifact, provides a still-required capability, or is referenced by an active instance, the operator must resolve that dependency/runtime relationship first. Business/instance data is preserved by default. --- ## 24. Operator Log Operators should record: ```text date/time operator name instance ID capsule version network profile action performed result backup ID if relevant Security Gate result notes ``` Example: ```text 2026-04-30 14:05 operator: local-admin instance: demo-001 capsule: konnaxion-v14-demo-2026.04.30 network: intranet_private action: start security: PASS result: running notes: demo ready at https://konnaxion.local ``` --- ## 25. Escalation Rules Escalate to technical maintainer when: ```text Security Gate returns FAIL_BLOCKING Security Gate returns UNKNOWN for firewall, ports, signatures, or secrets unknown containers appear public tunnel cannot be disabled backup verification fails repeatedly restore fails update fails and rollback fails database health is unhealthy Postgres or Redis appears exposed Docker socket exposure is detected operator sees suspicious files or users ``` Do not troubleshoot security failures by weakening controls. --- ## 26. Acceptance Criteria This operator guide is valid when an operator can: ```text start a Konnaxion Instance stop a Konnaxion Instance choose the correct network profile avoid public exposure by default run Security Gate checks create and verify backups restore from backup apply capsule updates rollback failed updates read safe logs export support bundles respond to common failures escalate security incidents ``` The operator must be able to perform normal operations without editing infrastructure files manually. --- ## 27. Summary The operator experience must remain simple: ```text Start Open URL Backup Update Stop ``` The system must handle the complexity: ```text secrets ports firewall Docker Compose Traefik Postgres Redis Celery healthchecks Security Gate rollback ``` The safe path must be the easy path. The unsafe path must be blocked by default. ================================================================================================ FILE: docs/DOC-15_Konnaxion_Developer_Guide.md AUTHORITY: reference CONTENT_ROLE: knowledge CONTENT_SHA256: 727fa7e59e09f67fe4ab4c453e28586f7c90610582543e3f083b9b7cfb1f6b6c CONTENT_BYTES: 23110 ================================================================================================ doc_id: DOC-15 title: Konnaxion Developer Guide project: Konnaxion app_version: v14 param_version: kx-param-2026.04.30 status: draft depends_on: - DOC-00_Konnaxion_Canonical_Variables.md - DOC-02_Konnaxion_Capsule_Architecture.md - DOC-03_Konnaxion_Capsule_Format.md - DOC-04_Konnaxion_Manager_Architecture.md - DOC-05_Konnaxion_Agent_Security_Model.md - DOC-06_Konnaxion_Network_Profiles.md - DOC-07_Konnaxion_Security_Gate.md - DOC-08_Konnaxion_Runtime_Docker_Compose.md - DOC-10_Konnaxion_Builder_CLI.md --- # DOC-15 — Konnaxion Developer Guide ## 1. Purpose This document defines the canonical developer workflow for **Konnaxion v14** and the new **Konnaxion Capsule** architecture. It is intended for developers working on: - Konnaxion frontend - Konnaxion backend - Konnaxion Docker runtime - Konnaxion Capsule Builder - Konnaxion Capsule Manager - Konnaxion Agent - deployment, security, backup, and release tooling This guide is not an operator guide. Operational use of a deployed appliance is covered by: ```text DOC-14_Konnaxion_Operator_Guide.md ```` This guide is not a security model. Agent and runtime security are covered by: ```text DOC-05_Konnaxion_Agent_Security_Model.md DOC-07_Konnaxion_Security_Gate.md DOC-13_Konnaxion_Threat_Model.md ``` --- ## 2. Canonical stack Konnaxion v14 must be treated as the following stack: ```text Frontend: Next.js / React / TypeScript Backend: Django 5.1 + Django REST Framework Database: PostgreSQL Background jobs: Celery Broker/result backend: Redis Reverse proxy: Traefik Media/static service: Nginx Runtime target: Docker Compose ``` The platform currently uses a **Next.js frontend**, **Django + DRF backend**, **PostgreSQL**, and **Celery + Redis** for background processing. It is organized around five primary modules — Kollective Intelligence, ethiKos, keenKonnect, KonnectED, Kreative — plus common core and Reports/Insights. --- ## 3. Repository layout Canonical local repository root: ```text C:\mycode\Konnaxion\Konnaxion ``` Canonical main directories: ```text Konnaxion/ ├── backend/ ├── frontend/ ├── docs/ ├── PlantUML/ ├── Structurizr/ ├── EndPoints-Graphs/ ├── demoVideo/ ├── package.json ├── pnpm-lock.yaml └── workspace.dsl ``` The project contains backend code, frontend code, docs, PlantUML diagrams, Structurizr architecture files, endpoint graphs, and technical reference material under `docs/Technical-Reference`. --- ## 4. Development principles ## 4.1 Do not guess When modifying Konnaxion, developers must not invent architecture that contradicts the existing implementation. Canonical rules: ```text Do not rename the project. Do not replace Django/DRF with another backend framework. Do not replace REST with GraphQL unless explicitly approved. Do not assume Redis is only a cache. Do not introduce Tailwind into the Django backend layer. Do not create a second frontend shell. Do not create a second Celery app. Do not bypass the services layer for frontend API calls. Do not expose internal runtime ports publicly. ``` The codebase instructions explicitly state that Konnaxion uses Django 5.1 + DRF + Celery + Redis on the backend, Next.js/React on the frontend, PostgreSQL as the production relational database, and Redis as Celery broker/result backend, not merely as a cache. ## 4.2 Preserve modular domains Konnaxion is a modular platform. Developers must add features to the correct domain instead of collapsing everything into one generic model or service. Canonical backend domains: ```text users kollective_intelligence ethikos keenkonnect konnected kreative trust teambuilder ``` The backend documentation identifies real separate domain apps and warns against putting everything in one model. --- ## 5. Backend development ## 5.1 Backend root ```text backend/ ``` Key files: ```text backend/manage.py backend/config/settings/base.py backend/config/settings/local.py backend/config/settings/production.py backend/config/settings/test.py backend/config/urls.py backend/config/asgi.py backend/config/wsgi.py backend/config/celery_app.py ``` Canonical settings modules: ```text config.settings.base config.settings.local config.settings.production config.settings.test ``` Canonical assumptions: ```text AUTH_USER_MODEL = "users.User" ROOT_URLCONF = "config.urls" WSGI application = config.wsgi.application ASGI application = config.asgi.application ``` These settings and import paths are part of the Konnaxion backend ground truth. --- ## 5.2 Backend local Docker workflow When backend code, models, or dependencies change: ```powershell cd C:\mycode\Konnaxion\Konnaxion\backend docker-compose -f docker-compose.local.yml up -d --build ``` Generate migrations: ```powershell docker-compose -f docker-compose.local.yml run --rm django python manage.py makemigrations ``` Apply migrations: ```powershell docker-compose -f docker-compose.local.yml run --rm django python manage.py migrate ``` Check services: ```powershell docker-compose -f docker-compose.local.yml ps ``` Create a superuser when needed: ```powershell docker-compose -f docker-compose.local.yml run --rm django python manage.py createsuperuser ``` The backend migration workflow is already documented around `docker-compose.local.yml`, `makemigrations`, `migrate`, `ps`, and optional `createsuperuser`. --- ## 5.3 Backend coding rules When adding a backend feature: ```text 1. Identify the correct domain app. 2. Add or modify models in that app only. 3. Add migrations. 4. Add serializers. 5. Add permissions if required. 6. Add API views or ViewSets. 7. Register routes through the canonical router or app urls. 8. Add tests. 9. Update docs if routes, models, or parameters changed. ``` Do not: ```text use auth.User directly create duplicate Celery apps invent settings module names place unrelated features into users add hardcoded environment values commit real .env files paste secrets into docs, logs, commits, or chats ``` --- ## 5.4 Celery rules Canonical Celery facts: ```text Celery app name: konnaxion Celery config file: backend/config/celery_app.py Broker: REDIS_URL Result backend: REDIS_URL Beat scheduler: django_celery_beat.schedulers:DatabaseScheduler ``` When writing tasks: ```python from celery import shared_task @shared_task def example_task(): ... ``` Do not define another Celery app. Celery workers and beat are part of the current backend structure and should rely on autodiscovery and Redis-backed configuration. --- ## 6. Frontend development ## 6.1 Frontend root ```text frontend/ ``` The frontend is a Next.js / React / TypeScript application using the App Router and modular feature folders. Canonical frontend concepts: ```text global shell shared layout module pages services layer theme context/tokens ThemeSwitcher routes*.tsx routes.json routes-tests.json ``` The frontend has a global layout system with components such as `MainLayout`, `Header`, `Sider`, and `PageContainer`; module UIs plug into the shared shell rather than creating independent root apps. --- ## 6.2 Frontend module rules When adding a frontend screen: ```text 1. Add the screen under the correct module folder. 2. Use the existing global layout and page containers. 3. Use existing shared components where possible. 4. Register the route in the correct routing file. 5. Use the services layer for API calls. 6. Run typecheck. 7. Run production build. ``` Do not: ```text create a second root layout create module-specific independent apps bypass the services layer invent new API prefixes invent new theme state add a second ThemeSwitcher assume Tailwind dark mode ``` The current frontend module pattern uses per-domain folders such as `modules/ethikos`, `modules/keenkonnect`, `modules/konnected`, `modules/kreative`, `modules/admin`, `modules/insights`, `modules/konsensus`, and `modules/konsultations`, with centralized routing files. --- ## 6.3 Frontend API rules Canonical backend API base: ```text /api/ ``` Canonical API prefixes include: ```text /api/users/ /api/ethikos/topics/ /api/ethikos/stances/ /api/ethikos/arguments/ /api/ethikos/categories/ /api/keenkonnect/projects/ /api/kollective/votes/ /api/konnected/resources/ /api/konnected/certifications/paths/ /api/konnected/certifications/evaluations/ /api/konnected/certifications/peer-validations/ /api/konnected/portfolios/ /api/konnected/certifications/exam-attempts/ /api/kreative/artworks/ /api/kreative/galleries/ ``` Compatibility aliases: ```text /api/deliberate/ /api/deliberate/elite/ ``` Do not rename `/api/ethikos/...` to `/api/deliberation/...` or similar. Frontend API calls should use the services layer and existing path prefixes. --- ## 6.4 Frontend build workflow Before deployment or capsule build: ```powershell cd C:\mycode\Konnaxion\Konnaxion\frontend pnpm install --frozen-lockfile pnpm exec tsc --noEmit --pretty false $env:NODE_OPTIONS="--max-old-space-size=4096" pnpm build ``` Important rules: ```text Run pnpm build from frontend/, not repo root. Set NODE_OPTIONS=--max-old-space-size=4096 for large production builds. Do not restart a production frontend until .next/BUILD_ID exists. ``` The frontend deployment runbook explicitly requires building from the `frontend` directory and setting `NODE_OPTIONS=--max-old-space-size=4096` to avoid Next.js heap out-of-memory failures. --- ## 6.5 Reports / Insights routes Canonical Reports routes: ```text /reports /reports/custom /reports/smart-vote /reports/usage /reports/perf ``` These routes are real implemented routes and must remain aligned across navigation, UI specs, and technical references. Do not ignore: ```text frontend/app/reports/ frontend/app/reports/ReportsPageShell.tsx ``` The deployment guide notes that `frontend/app/reports/` contains real Next.js routes and that missing `ReportsPageShell.tsx` can break production builds. --- ## 7. Runtime and deployment development ## 7.1 Legacy deployment model The current/historical VPS deployment is hybrid: ```text Backend: Docker Compose Frontend: Node.js / pnpm Database: Docker Postgres Redis: Docker Redis Proxy: Docker Traefik ``` Canonical routing in that deployment: ```text https://konnaxion.com/ -> Next.js frontend on port 3000 https://konnaxion.com/api/ -> Django https://konnaxion.com/admin/ -> Django admin https://konnaxion.com/media/ -> Docker nginx media service ``` This layout is documented in the Namecheap VPS guide. --- ## 7.2 Target capsule runtime For the capsule architecture, developers should target a fully containerized runtime: ```text traefik frontend-next django-api postgres redis celeryworker celerybeat flower media-nginx ``` Public routing remains: ```text / -> frontend-next /api/ -> django-api /admin/ -> django-api /media/ -> media-nginx ``` Internal-only services: ```text postgres redis celeryworker celerybeat flower unless protected ``` --- ## 7.3 Dangerous ports Developers must not create code, docs, compose files, or examples that publicly expose: ```text 3000 Next.js direct 5000 Django/Gunicorn internal 5432 PostgreSQL 6379 Redis 5555 Flower/dashboard 8000 Django dev server Docker daemon TCP ports ``` The security recovery notes explicitly state that public users should reach only Traefik on `80/443`, not the frontend direct port, dashboard/admin ports, Postgres, Redis, or Django/Gunicorn. --- ## 8. Konnaxion Capsule development ## 8.1 Capsule principle A Konnaxion Capsule is the portable, signed application package. Canonical extension: ```text .kxcap ``` Canonical build output example: ```text konnaxion-v14-demo-2026.04.30.kxcap ``` The capsule contains: ```text manifest.yaml docker-compose.capsule.yml images/ profiles/ env-templates/ migrations/ seed-data/ healthchecks/ checksums.txt signature.sig ``` The capsule must not contain: ```text real .env files DJANGO_SECRET_KEY POSTGRES_PASSWORD DATABASE_URL with password SSH private keys API tokens provider credentials Django admin passwords production database dumps in cleartext ``` --- ## 8.2 Capsule Builder workflow Canonical CLI: ```text kx ``` Build sequence: ```text 1. Validate working tree. 2. Run backend tests. 3. Run backend migrations check. 4. Run frontend typecheck. 5. Run frontend production build. 6. Build Docker images. 7. Export images as OCI archives. 8. Generate manifest.yaml. 9. Generate checksums. 10. Sign capsule. 11. Output .kxcap. ``` Canonical command: ```bash kx capsule build --profile demo --output konnaxion-v14-demo-2026.04.30.kxcap ``` --- ## 8.3 Capsule compatibility Every capsule must declare: ```yaml app_version: v14 capsule_version: 2026.04.30-demo.1 param_version: kx-param-2026.04.30 required_ram_mb: 4096 recommended_ram_mb: 8192 ``` Every capsule must declare compatible network profiles: ```yaml profiles: - local_only - intranet_private - private_tunnel - public_temporary - public_vps - offline ``` --- ## 9. Konnaxion Agent development Agent development must follow: ```text DOC-05_Konnaxion_Agent_Security_Model.md ``` Agent rules: ```text local-only API no arbitrary shell execution no arbitrary Docker execution signed capsules only allowed images only allowed services only blocked dangerous ports no privileged containers no host network no Docker socket mounts Security Gate before runtime audit log for privileged operations ``` The Agent exists because previous deployment compromise involved malicious Docker containers, cron persistence, `/tmp/sshd`, a miner, and a sudo backdoor attempt; therefore deployment automation must be allowlist-driven and fail closed. --- ## 10. Security rules for developers ## 10.1 Never commit secrets Never commit or paste: ```text DATABASE_URL POSTGRES_PASSWORD DJANGO_SECRET_KEY API keys tokens private keys SSH keys provider credentials Django admin passwords ``` If a secret appears in logs, docs, commits, screenshots, or chat, rotate it. The VPS guide explicitly warns not to paste full `.env` files or logs containing database URLs, Postgres passwords, Django secret keys, API keys, tokens, or private keys. --- ## 10.2 Never trust compromised artifacts Developers must not reuse: ```text old disk images old Docker volumes old crontabs old authorized_keys old sudoers files old /tmp contents old /dev/shm contents unknown systemd services unknown Docker images ``` Backups should include only: ```text Postgres dump media/uploads configuration templates ``` The security recovery notes say backups must not preserve malware and should not restore whole old disks, `/tmp`, `/dev/shm`, old crontabs, unknown systemd services, old authorized keys, old sudoers files, or unverified Docker volumes. --- ## 10.3 Local malware indicators When investigating suspicious systems, look for: ```text amco_* negoroo/amco supportxmr rx/0 /tmp/sshd pakchoi /dev/shm executable files unexpected crontabs unexpected sudoers files ``` These match the previous compromise indicators and should be included in Security Gate checks and incident procedures. --- ## 11. Testing expectations ## 11.1 Backend tests Run backend tests from `backend/` using the existing project tooling. Typical patterns: ```powershell cd C:\mycode\Konnaxion\Konnaxion\backend docker-compose -f docker-compose.local.yml run --rm django pytest ``` Before merging backend model changes: ```text makemigrations succeeds migrate succeeds tests pass API routes work admin still loads Celery tasks still import ``` --- ## 11.2 Frontend tests and validation Before merging frontend changes: ```powershell cd C:\mycode\Konnaxion\Konnaxion\frontend pnpm install --frozen-lockfile pnpm exec tsc --noEmit --pretty false $env:NODE_OPTIONS="--max-old-space-size=4096" pnpm build ``` Required checks: ```text typecheck passes production build passes reports routes still build module routes still render services use correct /api/... paths no direct browser calls to internal ports ``` --- ## 11.3 Capsule validation Before publishing a capsule: ```bash kx capsule verify konnaxion-v14-demo-2026.04.30.kxcap kx security check --capsule konnaxion-v14-demo-2026.04.30.kxcap ``` Required result: ```text capsule_signature: PASS image_checksums: PASS manifest_schema: PASS secrets_embedded: PASS dangerous_ports_blocked: PASS allowed_images_only: PASS no_privileged_containers: PASS no_host_network: PASS docker_socket_not_mounted: PASS ``` --- ## 12. Documentation update rules When a developer changes code, they must update the correct documentation. Use the technical reference map: ```text Need setting / env / route invariant: Global Parameter Reference Need module architecture: Full-Stack Technical Specification Need Reports / Insights frontend behavior: Insights Module UI Spec Need Reports / Insights config: Insights Module Config Parameters Need route ownership: Site Navigation Map Need table/model ownership: Database Schema Reference Need functional code-name mapping: Functional Code-Name Inventory ``` The documentation index states that these files are the sources of truth for architecture, routes, environment/configuration invariants, module specs, database tables, and functional code-name mapping. --- ## 13. Branching and commit rules Recommended branch naming: ```text feature/ fix/ docs/ security/ infra/ capsule/ ``` Commit message examples: ```text feat(frontend): add Reports usage chart shell fix(backend): correct Ethikos stance validation docs(capsule): add network profile reference security(agent): block Docker socket mounts infra(runtime): add media-nginx healthcheck ``` Before commit: ```bash git status ``` Do not commit: ```text .env .env.production with secrets database dumps media backups node_modules .next __pycache__ deployment archives *.tar.gz *.zip private keys logs containing secrets ``` The deployment guide warns not to commit deployment archives such as `.tar.gz` or `.zip`, and recommends generating clean archives from Git when deploying. --- ## 14. Pull request checklist Every PR must answer: ```text What module changed? Did backend models change? Were migrations generated? Did API routes change? Did frontend routes change? Did environment variables change? Did Docker/runtime behavior change? Did any public exposure change? Did docs need updating? Did tests/build pass? Are secrets absent? ``` Minimum PR checklist: ```text [ ] Backend tests pass, if backend changed. [ ] Migrations are included, if models changed. [ ] Frontend typecheck passes, if frontend changed. [ ] Frontend production build passes, if frontend changed. [ ] Capsule manifest updated, if runtime changed. [ ] Security Gate rules updated, if exposure changed. [ ] Docs updated. [ ] No secrets committed. [ ] No dangerous ports exposed. ``` --- ## 15. Release development workflow ## 15.1 Legacy safe archive flow For non-capsule deployments, create clean archive from Git: ```powershell cd C:\mycode\Konnaxion\Konnaxion git status git archive --format=tar.gz -o konnaxion-deploy.tar.gz HEAD ``` The Namecheap guide recommends clean Git archives when the VPS folder is not guaranteed to be a Git repository. ## 15.2 Target capsule release flow For capsule releases: ```bash kx capsule build --profile demo --output konnaxion-v14-demo-2026.04.30.kxcap kx capsule verify konnaxion-v14-demo-2026.04.30.kxcap kx security check --capsule konnaxion-v14-demo-2026.04.30.kxcap ``` Then import on a Konnaxion Box: ```bash kx capsule import konnaxion-v14-demo-2026.04.30.kxcap kx instance create demo-001 --capsule konnaxion-v14-demo-2026.04.30 kx instance start demo-001 --network intranet_private ``` --- ## 16. Environment variables ## 16.1 Backend production variables Canonical backend variables include: ```env DJANGO_SETTINGS_MODULE=config.settings.production DJANGO_SECRET_KEY= DJANGO_DEBUG=False DJANGO_ALLOWED_HOSTS= USE_DOCKER=yes DATABASE_URL=postgres://konnaxion:@postgres:5432/konnaxion REDIS_URL=redis://redis:6379/0 CELERY_BROKER_URL=redis://redis:6379/0 DJANGO_ADMIN_URL=admin/ SENTRY_DSN= ``` ## 16.2 Database variables ```env POSTGRES_HOST=postgres POSTGRES_PORT=5432 POSTGRES_DB=konnaxion POSTGRES_USER=konnaxion POSTGRES_PASSWORD= ``` ## 16.3 Frontend variables ```env NEXT_PUBLIC_API_BASE=https:///api NEXT_PUBLIC_BACKEND_BASE=https:// NEXT_TELEMETRY_DISABLED=1 NODE_OPTIONS=--max-old-space-size=4096 ``` ## 16.4 Capsule/Manager variables ```env KX_INSTANCE_ID=demo-001 KX_CAPSULE_ID=konnaxion-v14-demo-2026.04.30 KX_APP_VERSION=v14 KX_PARAM_VERSION=kx-param-2026.04.30 KX_NETWORK_PROFILE=intranet_private KX_EXPOSURE_MODE=private KX_PUBLIC_MODE_ENABLED=false KX_REQUIRE_SIGNED_CAPSULE=true KX_ALLOW_UNKNOWN_IMAGES=false KX_ALLOW_PRIVILEGED_CONTAINERS=false KX_ALLOW_DOCKER_SOCKET_MOUNT=false KX_ALLOW_HOST_NETWORK=false ``` --- ## 17. Common developer mistakes ## 17.1 Running frontend build from the wrong folder Wrong: ```powershell cd C:\mycode\Konnaxion\Konnaxion pnpm build ``` Correct: ```powershell cd C:\mycode\Konnaxion\Konnaxion\frontend pnpm build ``` ## 17.2 Forgetting memory option Wrong: ```powershell pnpm build ``` Correct for production build validation: ```powershell $env:NODE_OPTIONS="--max-old-space-size=4096" pnpm build ``` ## 17.3 Exposing app internals Wrong: ```text http://server-ip:3000 http://server-ip:5555 http://server-ip:5432 http://server-ip:6379 ``` Correct: ```text https:/// https:///api/ https:///admin/ https:///media/ ``` ## 17.4 Reusing compromised deployment state Wrong: ```text clone old disk reuse old authorized_keys reuse old .env reuse old Docker volumes reuse old crontabs ``` Correct: ```text clean source verified DB dump required media only new secrets new SSH keys fresh runtime Security Gate ``` --- ## 18. Developer acceptance criteria A development change is acceptable when: ```text It preserves the canonical stack. It respects module ownership. It uses existing frontend layout and services patterns. It uses canonical backend settings and apps. It passes backend tests when backend changed. It passes frontend typecheck/build when frontend changed. It does not expose dangerous ports. It does not include secrets. It updates docs when contracts changed. It remains compatible with Konnaxion Capsule packaging. It does not weaken Security Gate or Agent policies. ``` --- ## 19. Final rule Konnaxion development must optimize for: ```text clean architecture module boundaries repeatable builds capsule packaging private-by-default runtime minimal configuration for operators strong security defaults ``` Developers may add capability, but must not add ambiguity. If a change makes Konnaxion harder to package, harder to secure, harder to run offline/intranet, or easier to misconfigure publicly, it must be redesigned before merge. ================================================================================================ FILE: docs/DOC-16_Konnaxion_Manager_GUI_Technical_Contract.md AUTHORITY: reference CONTENT_ROLE: knowledge CONTENT_SHA256: 8e7785c59a59ce44f1c40f64ea9d2e06253d54d3878ff1eb0c669c7a4217f14d CONTENT_BYTES: 48068 ================================================================================================ ````markdown doc_id: DOC-16 title: Konnaxion Capsule Manager GUI Technical Contract project: Konnaxion app_version: v14 param_version: kx-param-2026.04.30 status: technical-contract owner: Konnaxion last_updated: 2026-05-03 --- # DOC-16 — Konnaxion Capsule Manager GUI Technical Contract ## 1. Purpose This document defines the fixed technical contract for the Konnaxion Capsule Manager GUI. It aligns the frontend/UI files with the Manager, Agent, Builder, CLI, shared constants, runtime generation, network profiles, Droplet deployment, and tests. The GUI must let an operator use Konnaxion from a local browser without manually typing normal lifecycle commands. The GUI must support: ```text select Konnaxion source folder select capsule output folder build capsule verify capsule import capsule create instance update instance start instance stop instance restart instance view status view health view logs run Security Gate set network profile disable public mode create backup list backups verify backup restore backup restore backup into new instance test restore backup rollback instance configure local/intranet/temporary-public/droplet targets deploy local/intranet/droplet ```` The GUI must not invent names, states, profiles, routes, actions, service names, runtime variables, or transport modes. Friendly labels are allowed for display only. Stored and exchanged values must remain canonical. --- ## 2. Runtime Topology ## 2.1 Local services | Service | Default URL | Purpose | | ----------------- | ----------------------------- | ------------------------------------------------ | | Manager GUI/API | `http://127.0.0.1:8714` | Browser UI and Manager API | | Agent API | `http://127.0.0.1:8765/v1` | Privileged local runtime actions | | Konnaxion runtime | `C:\mycode\Konnaxion\runtime` | Local capsules, instances, backups, shared state | ## 2.2 Local control flow ```text Browser GUI -> kx_manager UI route/action -> kx_manager service/client -> kx_agent API -> kx_agent action/runtime module -> Docker/filesystem/backup/network operation ``` The Manager GUI must not directly control Docker, firewall rules, host services, host networking, or backups except through approved Manager service wrappers or Agent calls. ## 2.3 Droplet/VPS control flow Droplet mode keeps the Agent private on the Droplet by default. Correct Droplet control flow: ```text Browser GUI on Windows -> local Manager -> Manager deploy/action backend -> SSH root@droplet -> curl http://127.0.0.1:8765/v1/... on the Droplet -> Droplet Agent -> Docker/runtime operation on the Droplet ``` The Manager must not require a local SSH tunnel such as: ```text http://127.0.0.1:18765/v1 ``` for normal Droplet deployment. Loopback `remote_agent_url` values in Droplet mode are treated as stale tunnel URLs and must force SSH-local Agent transport. Allowed Droplet transports: ```text default: ssh-local Agent transport ssh root@host "curl http://127.0.0.1:8765/v1/..." optional: direct HTTP only when remote_agent_url is non-loopback and points at the selected Droplet host ``` --- ## 3. Source File Ownership ## 3.1 Core UI files | File | Responsibility | | ------------------------------- | --------------------------------------------------- | | `kx_manager/ui/__init__.py` | UI package declaration | | `kx_manager/ui/app.py` | FastAPI `/ui` GUI route registration | | `kx_manager/ui/static.py` | Canonical UI routes, action names, labels, aliases | | `kx_manager/ui/pages.py` | Page IDs, page routes, UI action IDs, page metadata | | `kx_manager/ui/state.py` | Canonical UI display state and normalization | | `kx_manager/ui/components.py` | Safe reusable UI rendering helpers | | `kx_manager/ui/render.py` | Shared FastAPI HTML rendering helpers | | `kx_manager/ui/actions.py` | GUI action dispatcher | | `kx_manager/ui/action_views.py` | GUI action catalog and result rendering | | `kx_manager/ui/forms.py` | Public form parsing and validation facade | | `kx_manager/ui/page_views.py` | Thin page orchestrator and HTMLResponse owner | | `kx_manager/ui/page_forms.py` | Compatibility facade for older page form imports | ## 3.2 Page body files Actual page body ownership lives under `kx_manager/ui/page_parts/`. | File | Responsibility | | --------------------------------------- | ---------------------------------------- | | `kx_manager/ui/page_parts/__init__.py` | Flat page-body renderer registry | | `kx_manager/ui/page_parts/common.py` | Shared form, button, and payload helpers | | `kx_manager/ui/page_parts/dashboard.py` | Dashboard page body | | `kx_manager/ui/page_parts/capsules.py` | Capsule page body | | `kx_manager/ui/page_parts/instances.py` | Instance page body | | `kx_manager/ui/page_parts/security.py` | Security Gate page body | | `kx_manager/ui/page_parts/network.py` | Network page body | | `kx_manager/ui/page_parts/backups.py` | Backups page body | | `kx_manager/ui/page_parts/restore.py` | Restore page body | | `kx_manager/ui/page_parts/logs.py` | Logs page body | | `kx_manager/ui/page_parts/health.py` | Health page body | | `kx_manager/ui/page_parts/settings.py` | Settings page body | | `kx_manager/ui/page_parts/targets.py` | Target configuration page body | | `kx_manager/ui/page_parts/deploy.py` | Deployment action page body | | `kx_manager/ui/page_parts/about.py` | About page body | Rules: ```text page_views.py is the only page orchestrator. page_views.py owns route normalization, PageView lookup, and HTMLResponse construction. page_parts/*.py render page body fragments only. page_parts/*.py must not call html_response(...). page_parts/*.py must export render(context: Mapping[str, Any]) -> str. page_parts/targets.py must render target selection/configuration forms only. page_parts/deploy.py must render deployment operation forms only. page_forms.py must remain a compatibility facade only. Do not create kx_manager/ui/pages/ because kx_manager/ui/pages.py already exists. ``` ## 3.3 Form files | File | Responsibility | | --------------------------------- | --------------------------------- | | `kx_manager/ui/form_registry.py` | Action-to-form model registry | | `kx_manager/ui/form_targets.py` | Target/deployment form validation | | `kx_manager/ui/form_network.py` | Network profile form validation | | `kx_manager/ui/form_capsules.py` | Capsule form validation | | `kx_manager/ui/form_instances.py` | Instance form validation | | `kx_manager/ui/form_backups.py` | Backup/restore form validation | | `kx_manager/ui/form_core.py` | Core source/output folder forms | | `kx_manager/ui/form_helpers.py` | Shared validation helpers | | `kx_manager/ui/form_constants.py` | UI form defaults and enum imports | | `kx_manager/ui/form_errors.py` | Form validation exception | ## 3.4 Manager service files | File | Responsibility | | -------------------------------- | ------------------------------------------------------------ | | `kx_manager/services/builder.py` | Build/verify capsule service wrapper | | `kx_manager/services/targets.py` | Local/intranet/temporary-public/droplet target configuration | | `kx_manager/services/deploy.py` | Local/intranet/temporary-public/droplet deployment flow | ## 3.5 Backend alignment files | File | Responsibility | | ---------------------------------- | --------------------------------------- | | `kx_manager/client.py` | Agent API client | | `kx_manager/main.py` | Manager FastAPI app and UI registration | | `kx_manager/models.py` | Manager internal/view models | | `kx_manager/schemas.py` | Manager route schemas | | `kx_manager/routes/capsules.py` | Capsule Manager routes | | `kx_manager/routes/instances.py` | Instance Manager routes | | `kx_manager/routes/backups.py` | Backup/restore routes | | `kx_manager/routes/security.py` | Security Gate routes | | `kx_manager/routes/network.py` | Network profile routes | | `kx_manager/routes/logs.py` | Logs routes | | `kx_agent/api.py` | Agent API contracts | | `kx_builder/main.py` | Builder CLI entrypoint | | `kx_shared/konnaxion_constants.py` | Canonical constants/enums/defaults | ## 3.6 Droplet deployment critical files These files enforce the Droplet deploy contract: | File | Required responsibility | | ----------------------------------------- | --------------------------------------------------------------------- | | `kx_manager/ui/agent_execution_client.py` | HTTP/SCP/SSH execution adapter; SSH-local Agent transport for Droplet | | `kx_manager/services/deploy.py` | Deployment orchestration; canonical public host normalization | | `kx_agent/api.py` | Agent request schemas; network profile request contract | | `kx_agent/network/profiles.py` | Profile state application and validation | | `kx_agent/instances/env_writer.py` | Runtime env generation | | `kx_agent/instances/secrets.py` | Env/secrets persistence without freezing public host values forever | | `kx_agent/runtime/compose.py` | Runtime Compose and Traefik file-provider generation | | `kx_agent/runtime/healthchecks.py` | Container healthcheck commands | | `kx_builder/images.py` | Build/export runtime images | | `kx_builder/package.py` | Include runtime image archives in `.kxcap` | | `kx_builder/verify.py` | Fail verification when required image archives are missing | --- ## 4. Required UI Package Structure The target UI package must be: ```text kx_manager/ui/ __init__.py app.py actions.py action_views.py components.py forms.py form_backups.py form_capsules.py form_constants.py form_core.py form_errors.py form_helpers.py form_instances.py form_network.py form_registry.py form_targets.py page_forms.py page_views.py pages.py render.py state.py static.py streamlit_app.py page_parts/ __init__.py common.py dashboard.py capsules.py instances.py security.py network.py backups.py restore.py logs.py health.py settings.py targets.py deploy.py about.py ``` Rules: ```text app.py must be FastAPI-compatible. app.py must expose register(app). app.py must not require Streamlit. streamlit_app.py may require Streamlit. pages.py owns PageId and UiAction identity. static.py owns UI routes, action routes, labels, browser-only action links, and alias normalization. state.py owns normalized UI state. components.py and render.py own reusable rendering helpers. actions.py owns GUI action dispatch. action_views.py owns action catalog and result rendering. forms.py owns the public validation facade. form_registry.py maps canonical action names to form models. page_views.py owns page orchestration and HTMLResponse construction. page_parts/*.py own page bodies only. page_forms.py exists only for backward-compatible imports. ``` --- ## 5. Canonical Environment Variables | Variable | Default | Owner | Used by | | -------------------------- | -------------------------------------------------------------------------- | ------------------------ | ----------------------- | | `KX_ROOT` | `C:\mycode\Konnaxion\runtime` on Windows dev | Shared / Agent / Manager | Runtime root | | `KX_SOURCE_DIR` | `C:\mycode\Konnaxion\Konnaxion` | GUI / Builder | App source to package | | `KX_CAPSULE_OUTPUT_DIR` | `C:\mycode\Konnaxion\runtime\capsules` | GUI / Builder | Capsule output folder | | `KX_CAPSULE_FILE` | `C:\mycode\Konnaxion\runtime\capsules\konnaxion-v14-demo-2026.04.30.kxcap` | GUI / Builder | Capsule output file | | `KX_AGENT_HOST` | `127.0.0.1` | Agent / Manager client | Agent bind/connect host | | `KX_AGENT_PORT` | `8765` | Agent / Manager client | Agent bind/connect port | | `KX_AGENT_SCHEME` | `http` | Manager client | Agent URL scheme | | `KX_AGENT_API_PREFIX` | `/v1` | Manager client | Agent API prefix | | `KX_AGENT_URL` | `http://127.0.0.1:8765/v1` | Manager client | Agent base URL | | `KX_AGENT_TIMEOUT_SECONDS` | `30.0` | Manager client | Agent request timeout | | `KX_AGENT_TOKEN` | empty | Manager client | Optional auth token | | `KX_MANAGER_HOST` | `127.0.0.1` | Manager | Manager bind host | | `KX_MANAGER_PORT` | `8714` | Manager | Manager bind port | | `KX_MANAGER_URL` | `http://127.0.0.1:8714` | GUI / scripts | Manager base URL | ## 5.1 Public runtime env contract For `public_vps`, generated runtime env must use the canonical public host. Example: ```text host = 138.197.174.76.sslip.io ``` Required generated values: ```text KX_HOST=138.197.174.76.sslip.io KX_NETWORK_PROFILE=public_vps KX_EXPOSURE_MODE=public KX_PUBLIC_MODE_ENABLED=true DJANGO_ALLOWED_HOSTS=127.0.0.1,localhost,138.197.174.76.sslip.io,django-api,kx-demo-001-django-api DJANGO_CSRF_TRUSTED_ORIGINS=https://138.197.174.76.sslip.io,http://138.197.174.76.sslip.io NEXT_PUBLIC_API_BASE=https://138.197.174.76.sslip.io/api NEXT_PUBLIC_BACKEND_BASE=https://138.197.174.76.sslip.io ``` Forbidden for `public_vps` generated public runtime env: ```text KX_HOST=127.0.0.1 DJANGO_ALLOWED_HOSTS=127.0.0.1 only NEXT_PUBLIC_API_BASE=https://127.0.0.1/api NEXT_PUBLIC_BACKEND_BASE=https://127.0.0.1 Traefik Host(`127.0.0.1`) ``` --- ## 6. Canonical Development Paths | Name | Value | | ---------------- | ----------------------------------------------- | | Manager repo | `C:\mycode\Konnaxion\Konnaxion_Capsule_Manager` | | Konnaxion source | `C:\mycode\Konnaxion\Konnaxion` | | Runtime root | `C:\mycode\Konnaxion\runtime` | | Capsules dir | `C:\mycode\Konnaxion\runtime\capsules` | | Instances dir | `C:\mycode\Konnaxion\runtime\instances` | | Backups dir | `C:\mycode\Konnaxion\runtime\backups` | | Shared dir | `C:\mycode\Konnaxion\runtime\shared` | Canonical Linux runtime values remain: ```text /opt/konnaxion /opt/konnaxion/capsules /opt/konnaxion/instances /opt/konnaxion/backups /opt/konnaxion/shared ``` Windows development may set `KX_ROOT` to a Windows path. Canonical serialized appliance paths must remain POSIX where the runtime contract requires them. --- ## 7. Canonical Product Variables These values must come from `kx_shared.konnaxion_constants`. | Variable | Canonical value | | --------------- | --------------------------- | | `PRODUCT_NAME` | `Konnaxion` | | `APP_VERSION` | `v14` | | `PARAM_VERSION` | `kx-param-2026.04.30` | | `MANAGER_NAME` | `Konnaxion Capsule Manager` | | `AGENT_NAME` | `Konnaxion Agent` | | `BUILDER_NAME` | `Konnaxion Capsule Builder` | | `CLI_NAME` | `kx` | Do not redefine these in UI files. --- ## 8. Canonical Capsule Variables | Variable | Canonical value | | ------------------------- | ------------------------------------- | | `CAPSULE_EXTENSION` | `.kxcap` | | `DEFAULT_CHANNEL` | `demo` | | `DEFAULT_INSTANCE_ID` | `demo-001` | | `DEFAULT_CAPSULE_ID` | `konnaxion-v14-demo-2026.04.30` | | `DEFAULT_CAPSULE_VERSION` | `2026.04.30-demo.1` | | Default capsule filename | `konnaxion-v14-demo-2026.04.30.kxcap` | Default dev capsule output: ```text C:\mycode\Konnaxion\runtime\capsules\konnaxion-v14-demo-2026.04.30.kxcap ``` ## 8.1 Capsule image archive contract A capsule intended to start a runtime must include image archives under: ```text images/*.oci.tar ``` Required application image archives for the v14 demo runtime: ```text images/django-api.oci.tar images/frontend-next.oci.tar ``` The capsule may either include third-party images as OCI archives or explicitly declare them as allowed external base images, depending on security policy. At minimum, verification must fail when the manifest/runtime declares app services but `images/` contains only: ```text images/README.json ``` Builder verify must not return OK for a deployable public_vps capsule missing required runtime image archives. --- ## 9. Target Modes The GUI must support these target modes. | Target mode | Value | Profile | Exposure | Purpose | | ---------------- | ------------------ | ------------------ | ------------------ | --------------------- | | Local only | `local` | `local_only` | `private` | Same-machine dev/demo | | Intranet | `intranet` | `intranet_private` | `private` or `lan` | LAN/private use | | Droplet/VPS | `droplet` | `public_vps` | `public` | Remote public VPS | | Temporary public | `temporary_public` | `public_temporary` | `temporary_tunnel` | Time-limited demo | Target mode variables: | Variable | Allowed values | | -------------------- | -------------------------------------------------- | | `KX_TARGET_MODE` | `local`, `intranet`, `droplet`, `temporary_public` | | `KX_TARGET_PROFILE` | canonical `NetworkProfile` value | | `KX_TARGET_EXPOSURE` | canonical `ExposureMode` value | --- ## 10. Droplet Target Variables Droplet mode requires these values. | Variable | Example | Required | | ------------------------- | ------------------------------- | -------: | | `KX_DROPLET_NAME` | `konnaxion-prod-01` | yes | | `KX_DROPLET_HOST` | `203.0.113.10` | yes | | `KX_DROPLET_USER` | `root` | yes | | `KX_DROPLET_SSH_KEY_PATH` | `C:\Users\user\.ssh\id_ed25519` | yes | | `KX_DROPLET_KX_ROOT` | `/opt/konnaxion` | yes | | `KX_DROPLET_CAPSULE_DIR` | `/opt/konnaxion/capsules` | yes | | `KX_DROPLET_DOMAIN` | `app.example.com` | yes | | `KX_DROPLET_AGENT_URL` | non-loopback Agent URL only | optional | | `KX_DROPLET_SSH_PORT` | `22` | optional | Droplet mode must not assume password SSH. Use SSH key path or an explicit configured credential mechanism. Droplet GUI forms and buttons must submit: ```text target_mode = droplet network_profile = public_vps exposure_mode = public confirmed = true ``` Droplet operations must never inherit the private/intranet default payload. ## 10.1 Droplet Agent URL rules The Droplet Agent is private by default: ```text http://127.0.0.1:8765/v1 ``` This address is private to the Droplet. The Manager on Windows must reach it by SSH-local curl: ```powershell ssh root@ "curl http://127.0.0.1:8765/v1/health" ``` A loopback `KX_DROPLET_AGENT_URL` such as: ```text http://127.0.0.1:18765/v1 http://localhost:18765/v1 ``` must be treated as stale tunnel/localhost configuration and must not be used for direct Manager HTTP calls. In Droplet mode: ```text remote_agent_url blank -> SSH-local Agent transport remote_agent_url loopback -> SSH-local Agent transport remote_agent_url host != droplet_host -> SSH-local Agent transport remote_agent_url host == droplet_host -> direct HTTP allowed only if explicitly configured ``` ## 10.2 Droplet host normalization Manager and UI may collect the public host under names such as: ```text domain droplet_domain public_host host ``` Before calling Agent network APIs, Manager must normalize these to: ```text host ``` The Agent network profile API must not require or accept `domain` as the canonical runtime field. Correct mapping: ```text domain / droplet_domain / public_host / droplet_host -> host ``` --- ## 11. Canonical Docker Service Names Only these service names are valid: ```text traefik frontend-next django-api postgres redis celeryworker celerybeat flower media-nginx kx-agent ``` Forbidden aliases: ```text backend api web next frontend db database cache worker scheduler media agent ``` --- ## 12. Canonical Network Profiles | Profile | Value | Public by default | | ---------------- | ------------------ | ----------------: | | Local only | `local_only` | no | | Intranet private | `intranet_private` | no | | Private tunnel | `private_tunnel` | no | | Public temporary | `public_temporary` | no, explicit only | | Public VPS | `public_vps` | no, explicit only | | Offline | `offline` | no | Default: ```text DEFAULT_NETWORK_PROFILE = intranet_private ``` Public VPS rules: ```text public_vps requires explicit confirmation public_vps requires explicit public host public_vps must not default KX_HOST to 127.0.0.1 public_vps must not default Traefik Host() to 127.0.0.1 public_vps must not default Django allowed hosts to 127.0.0.1 only ``` --- ## 13. Canonical Exposure Modes | Mode | Value | | ---------------- | ------------------ | | Private | `private` | | LAN | `lan` | | VPN | `vpn` | | Temporary tunnel | `temporary_tunnel` | | Public | `public` | Default: ```text DEFAULT_EXPOSURE_MODE = private ``` Allowed profile/exposure combinations: ```text local_only -> private intranet_private -> private or lan private_tunnel -> private or vpn public_temporary -> temporary_tunnel public_vps -> public offline -> private ``` Rules: ```text public_temporary requires public_mode_expires_at public_temporary requires confirmation public_vps requires explicit confirmation public_vps requires host public exposure must never be default ``` --- ## 14. Canonical Instance States Only these values are valid: ```text created importing verifying ready starting running stopping stopped updating rolling_back degraded failed security_blocked ``` UI labels may be friendly. Stored values must remain canonical. --- ## 15. Canonical Security Gate Statuses Only these values are valid: ```text PASS WARN FAIL_BLOCKING SKIPPED UNKNOWN ``` Start gating must respect Security Gate status. --- ## 16. Canonical Backup Statuses Only these values are valid: ```text created running verifying verified failed expired deleted quarantined ``` --- ## 17. Canonical Restore Statuses Only these values are valid: ```text planned preflight creating_pre_restore_backup restoring_database restoring_media running_migrations running_security_gate running_healthchecks restored degraded failed rolled_back ``` --- ## 18. Canonical Rollback Statuses Only these values are valid: ```text planned running capsule_repointed data_restored healthchecking completed failed ``` --- ## 19. UI Page IDs `kx_manager/ui/pages.py` owns page IDs. The active FastAPI page route surface is: | Page | `PageId` value | Route | | --------- | -------------- | --------------- | | Dashboard | `dashboard` | `/ui` | | Capsules | `capsules` | `/ui/capsules` | | Instances | `instances` | `/ui/instances` | | Security | `security` | `/ui/security` | | Network | `network` | `/ui/network` | | Backups | `backups` | `/ui/backups` | | Restore | `restore` | `/ui/restore` | | Logs | `logs` | `/ui/logs` | | Health | `health` | `/ui/health` | | Settings | `settings` | `/ui/settings` | | Targets | `targets` | `/ui/targets` | | Deploy | `deploy` | `/ui/deploy` | | About | `about` | `/ui/about` | Subroutes such as `/ui/capsules/import`, `/ui/instances/detail`, and `/ui/instances/create` are not part of the current required FastAPI page route surface unless explicitly added later. Page responsibility split: ```text /ui/targets target configuration only set_target_local set_target_intranet set_target_temporary_public set_target_droplet /ui/deploy deployment operations only deploy_local deploy_intranet deploy_droplet check_droplet_agent copy_capsule_to_droplet start_droplet_instance ``` --- ## 20. UI Page Groups Only these page groups are valid: ```text overview operations safety system deployment ``` Mapping: | Group | Pages | | ------------ | ------------------------------------- | | `overview` | dashboard | | `operations` | capsules, instances, backups, restore | | `safety` | security, network | | `system` | logs, health, settings, about | | `deployment` | targets, deploy | --- ## 21. GUI FastAPI Route Contract `kx_manager/ui/app.py` must expose: ```python def register(app: FastAPI) -> None: ... ``` It must register: ```text GET /ui GET /ui/capsules GET /ui/instances GET /ui/security GET /ui/network GET /ui/backups GET /ui/restore GET /ui/logs GET /ui/health GET /ui/settings GET /ui/about GET /ui/targets GET /ui/deploy ``` Action routes are defined in DOC-17. --- ## 22. UI State Models `kx_manager/ui/state.py` owns display state normalization. Do not duplicate these models elsewhere. | UI model | Purpose | | ---------------------- | --------------------------------- | | `CapsuleUiState` | Capsule summary display | | `SecurityCheckUiState` | One Security Gate check | | `SecurityUiState` | Aggregate Security Gate state | | `NetworkUiState` | Network/exposure/public URL state | | `BackupUiState` | Latest backup summary | | `InstanceUiState` | Instance display summary | | `ManagerUiState` | Top-level UI state | Add target state models: | UI model | Purpose | | ---------------------- | ---------------------------------- | | `TargetModeUiState` | Selected target mode | | `DropletTargetUiState` | Droplet host/SSH/domain config | | `BuildTargetUiState` | Source/output/capsule build config | --- ## 23. UI Component Rules `kx_manager/ui/components.py` owns reusable UI fragments. Components may render: ```text badges cards metrics tables buttons links empty states definition lists action bars forms result panels log blocks ``` Component rules: ```text HTML output must be escaped by default. Stored values remain canonical. Display labels may be friendly. Components must not invent canonical values. Components must not execute actions. ``` --- ## 24. GUI Forms `kx_manager/ui/forms.py` must expose the public form validation API. Required form models: ```text BuildCapsuleForm VerifyCapsuleForm ImportCapsuleForm CreateInstanceForm UpdateInstanceForm InstanceActionForm LogsForm BackupForm RestoreForm RollbackForm NetworkProfileForm TargetModeForm LocalTargetForm IntranetTargetForm TemporaryPublicTargetForm DropletTargetForm DeployLocalForm DeployIntranetForm DeployDropletForm CheckDropletAgentForm CopyCapsuleToDropletForm StartDropletInstanceForm ``` Rules: ```text source_dir must exist capsule_output_dir must exist or be creatable capsule_file must end with .kxcap instance_id must be safe service must be canonical DockerService network_profile must be canonical NetworkProfile exposure_mode must be canonical ExposureMode public_temporary requires public_mode_expires_at public_temporary requires confirmation droplet mode requires droplet_host droplet mode requires droplet_user droplet mode requires ssh_key_path droplet mode requires remote_kx_root droplet mode requires remote_capsule_dir droplet mode requires domain droplet mode requires confirmation deploy_droplet requires capsule_file copy_capsule_to_droplet requires capsule_file start_droplet_instance requires instance_id restore_data rollback requires backup_id ``` Droplet form normalization: ```text domain / droplet_domain / public_host -> host for Agent network payloads remote_agent_url blank or loopback -> SSH-local Agent transport ``` --- ## 25. GUI Action Dispatcher `kx_manager/ui/actions.py` must own the action dispatcher. Required shape: ```python class GuiActionResult: ok: bool action: str message: str instance_id: str | None data: dict[str, Any] stdout: str | None stderr: str | None returncode: int | None ``` Required dispatcher function: ```python async def dispatch_gui_action(action: UiAction, payload: Mapping[str, Any]) -> GuiActionResult: ... ``` Rules: ```text Every action must be allowlisted. Unknown actions must be rejected. No shell=True. No arbitrary command text. All output must be captured and rendered safely. ``` --- ## 26. Builder Service `kx_manager/services/builder.py` owns local build/verify capsule operations. Required functions: ```python def build_capsule(request: BuildCapsuleRequest) -> BuildCapsuleResult: ... def verify_capsule(capsule_file: Path) -> VerifyCapsuleResult: ... ``` Temporary backend may call: ```text uv run kx-builder capsule build ... uv run kx-builder capsule verify ... ``` Final backend should call `kx_builder` Python APIs directly. ## 26.1 Builder image export contract Builder must be able to build/export runtime images needed by the capsule. For the v14 demo runtime, Builder must support at least: ```text konnaxion/django-api:v14 konnaxion/frontend-next:v14 ``` Frontend runtime image must not require network access at container start. Frontend image runtime command must be equivalent to: ```text node node_modules/next/dist/bin/next start -H 0.0.0.0 -p 3000 ``` Frontend runtime image must include: ```text package.json node_modules .next public next.config.* env.mjs ``` Forbidden frontend runtime behavior: ```text pnpm start that triggers Corepack download runtime fetch from registry.npmjs.org missing env.mjs ``` --- ## 27. Target Service `kx_manager/services/targets.py` owns target configuration. Required target modes: ```text local intranet droplet temporary_public ``` Required functions: ```python def validate_target_config(config: TargetConfig) -> None: ... def network_profile_for_target(target_mode: str) -> NetworkProfile: ... def exposure_mode_for_target(target_mode: str) -> ExposureMode: ... ``` --- ## 28. Deploy Service `kx_manager/services/deploy.py` owns deployment flows. Required functions: ```python def deploy_local(request: LocalDeployRequest) -> DeployResult: ... def deploy_intranet(request: IntranetDeployRequest) -> DeployResult: ... def deploy_droplet(request: DropletDeployRequest) -> DeployResult: ... ``` Deployment responsibilities: ```text build capsule verify capsule copy capsule if remote import capsule create or update instance set network profile start instance run Security Gate return status/health/log links ``` Droplet deployment responsibilities: ```text validate SSH config copy capsule to remote /opt/konnaxion/capsules ensure remote runtime folders contact private remote Agent through SSH-local curl by default import/update/start on remote target run remote health/security checks normalize domain/public_host/droplet_host into host for Agent network profile never send domain to Agent network profile unless Agent schema explicitly supports it ``` Deployment order: ```text validate request prepare capsule copy capsule to Droplet ensure remote runtime check Droplet Agent through SSH-local health probe Agent contract import capsule create/update instance set network profile with host run Security Gate start instance ``` --- ## 29. Normalized GUI Action Result Every GUI action must normalize to: ```json { "ok": true, "action": "start_instance", "instance_id": "demo-001", "message": "Instance started.", "state": "running", "security_status": "PASS", "restore_status": null, "rollback_status": null, "data": {} } ``` Command fallback result: ```json { "ok": false, "action": "build_capsule", "instance_id": null, "message": "Command failed.", "data": { "argv": ["uv", "run", "kx-builder", "capsule", "build"], "returncode": 1, "stdout": "...", "stderr": "..." } } ``` Droplet transport result data must include: ```json { "agent_transport": "ssh", "agent_health_url": "http://127.0.0.1:8765/v1/health", "remote_agent_url": "", "host": "138.197.174.76.sslip.io", "public_url": "https://138.197.174.76.sslip.io" } ``` when the Agent is private on the Droplet. --- ## 30. Required UI Labels Use these exact main nav labels: ```text Dashboard Capsules Instances Targets Deploy Security Network Backups Restore Logs Health Settings About ``` Use these exact primary labels: ```text Check Manager Check Agent Select Source Folder Select Output Folder Build Capsule Rebuild Capsule Verify Capsule Import Capsule List Capsules View Capsule Create Instance Update Instance Start Instance Stop Instance Restart Instance Instance Status View Logs Instance Health Open Instance Run Security Check Set Network Profile Disable Public Mode Create Backup List Backups Verify Backup Restore Backup Restore Backup New Test Restore Backup Rollback Set Local Target Set Intranet Target Set Droplet Target Set Temporary Public Target Deploy Local Deploy Intranet Deploy Droplet Check Droplet Agent Copy Capsule to Droplet Start Droplet Instance Open Manager Docs Open Agent Docs ``` Danger labels: ```text Stop Instance Restore Backup Restore Backup New Rollback Disable Public Mode Set Droplet Target Deploy Droplet Start Droplet Instance ``` --- ## 31. Browser Folder Selection Rule A local web GUI cannot reliably browse the full local filesystem like a native desktop app. Phase 1 must use: ```text text input for source folder text input for output folder validation that path exists or is creatable clear error messages ``` A future desktop wrapper may add native folder pickers. --- ## 32. Start Gating The GUI must not enable Start when: ```text state in importing, verifying, starting, stopping, updating, rolling_back, security_blocked security_status = FAIL_BLOCKING ``` Start may be enabled when: ```text state in created, ready, stopped, degraded security_status in PASS, WARN, UNKNOWN ``` If `security_status = UNKNOWN`, clicking Start must run Security Gate first or show a confirmation requiring Security Gate. --- ## 33. Restore / Rollback Gating These actions require confirmation: ```text restore_backup restore_backup_new rollback_instance ``` Rollback with data restore requires: ```text backup_id ``` --- ## 34. Public Exposure Gating If: ```text network_profile = public_temporary ``` then: ```text target_mode = temporary_public exposure_mode = temporary_tunnel public_mode_expires_at is required explicit confirmation is required ``` If: ```text network_profile = public_vps ``` then: ```text target_mode = droplet exposure_mode = public droplet_host is required droplet_user is required ssh_key_path is required remote_kx_root is required remote_capsule_dir is required domain is required host must resolve from domain/public_host/droplet_host explicit confirmation is required ``` The GUI must never allow this drift: ```text target_mode = intranet network_profile = public_vps exposure_mode = public ``` or: ```text target_mode = droplet network_profile = intranet_private exposure_mode = private ``` or: ```text target_mode = droplet network_profile = public_vps exposure_mode = public KX_HOST = 127.0.0.1 ``` --- ## 35. Runtime Compose and Traefik Contract Droplet/public_vps runtime must generate public routing through Traefik file provider. Traefik static command must enable file provider: ```text --providers.file.filename=/etc/traefik/dynamic/traefik-dynamic.yml --providers.file.watch=true --entrypoints.web.address=:80 --entrypoints.websecure.address=:443 --entrypoints.web.http.redirections.entrypoint.to=websecure --entrypoints.web.http.redirections.entrypoint.scheme=https ``` Generated dynamic file must route using the public host: ```yaml http: routers: kx-frontend: rule: "Host(``) && PathPrefix(`/`)" entryPoints: - websecure tls: {} service: kx-frontend priority: 1 kx-api: rule: "Host(``) && PathPrefix(`/api/`)" entryPoints: - websecure tls: {} service: kx-api priority: 100 kx-admin: rule: "Host(``) && PathPrefix(`/admin/`)" entryPoints: - websecure tls: {} service: kx-api priority: 100 services: kx-frontend: loadBalancer: servers: - url: "http://kx-demo-001-frontend-next:3000" kx-api: loadBalancer: servers: - url: "http://kx-demo-001-django-api:5000" ``` Traefik Docker labels may exist, but public_vps correctness must not depend only on labels if the runtime is using file provider. --- ## 36. Runtime Healthcheck Contract Healthchecks must use tools available inside the relevant container. Django/Gunicorn healthcheck must not require `wget` or `curl`. Allowed Django healthcheck: ```text python -c "import socket; sock=socket.create_connection(('127.0.0.1',5000),5); sock.close()" ``` Forbidden malformed healthcheck: ```text python -c "... sock.close()"api/health/ >/dev/null 2>&1 || exit 1 ``` Forbidden unless the image includes the tool: ```text wget -qO- http://127.0.0.1:5000/api/health/ curl http://127.0.0.1:5000/api/health/ ``` Media nginx healthcheck must either use an available tool/path or be disabled for stock `nginx:stable` if no reliable health endpoint/tool exists. Compose must not block frontend/celery startup because Django is marked unhealthy by a broken healthcheck while Gunicorn is running. --- ## 37. Required Tests Create or update: ```text tests/test_manager_ui_contract.py tests/test_manager_ui_routes.py tests/test_manager_ui_forms.py tests/test_manager_ui_action_coverage.py tests/test_manager_ui_target_modes.py tests/test_fastapi_ui_page_split.py tests/test_fastapi_ui_routes.py tests/test_ui_form_targets.py tests/test_ui_page_targets.py tests/test_ui_page_deploy.py tests/test_network_profiles.py tests/test_compose_generation.py tests/test_capsule_verify.py ``` Required checks: ```text GUI app exposes register(app) FastAPI UI import does not require Streamlit All UI page routes start with /ui All action routes start with /ui/actions All required labels exist All form validators reject invalid canonical values page_views.py is a thin page orchestrator page_parts/*.py export render(context) -> str page_parts/*.py do not call html_response(...) Droplet payload forces target_mode=droplet Droplet payload forces network_profile=public_vps Droplet payload forces exposure_mode=public Droplet target requires host/user/ssh_key/remote_root/remote_capsule_dir/domain Droplet domain/public_host is normalized to host for Agent network profile Droplet remote_agent_url blank uses SSH transport Droplet remote_agent_url loopback uses SSH transport Targets page does not render deployment action forms Deploy page renders deployment action forms Droplet operation buttons do not submit intranet payloads public_temporary requires expiration public_vps requires explicit public host public_vps never defaults KX_HOST to 127.0.0.1 public_vps never defaults Traefik Host() to 127.0.0.1 public_vps generated Django allowed hosts include public host public_vps generated frontend env points at public host Django healthcheck does not use missing wget/curl Django healthcheck is not malformed Builder capsule includes required app image archives Verify fails if required app image archives are missing rollback restore_data requires backup_id command fallback uses shell=False unknown action is rejected all UiAction values are mapped all mapped actions have buttons or links browser-only actions are links, not POST routes ``` Run: ```powershell uv run python -m compileall kx_manager/ui kx_manager/services kx_agent kx_builder tests uv run pytest -q ``` Current expected full-suite baseline after the GUI/page split and Droplet deploy fixes: ```text 548+ passed ``` The exact number may increase as new Droplet/image/runtime regression tests are added. --- ## 38. Launcher Contract `start_konnaxion_gui.bat` must set: ```bat set "KX_MANAGER_REPO=C:\mycode\Konnaxion\Konnaxion_Capsule_Manager" set "KX_RUNTIME_ROOT=C:\mycode\Konnaxion\runtime" set "KX_SOURCE_DIR=C:\mycode\Konnaxion\Konnaxion" set "KX_ROOT=%KX_RUNTIME_ROOT%" set "KX_AGENT_HOST=127.0.0.1" set "KX_AGENT_PORT=8765" set "KX_AGENT_URL=http://127.0.0.1:8765/v1" set "KX_MANAGER_HOST=127.0.0.1" set "KX_MANAGER_PORT=8714" set "KX_MANAGER_URL=http://127.0.0.1:8714" ``` It must open: ```text http://127.0.0.1:8714/ui ``` --- ## 39. Anti-Drift Rules ## 39.1 Imports Canonical product, profile, exposure, service, state, and default values should come from: ```python from kx_shared.konnaxion_constants import ... ``` Target-mode logic must come from: ```python from kx_manager.services.targets import ... ``` UI route, action, label, and alias constants must come from: ```python from kx_manager.ui.static import ... ``` Page body helpers should come from: ```python from kx_manager.ui.page_parts.common import ... ``` UI state/view files may import DTOs from: ```python from kx_manager.models import ... from kx_manager.schemas import ... ``` UI action execution must call: ```python from kx_manager.client import KonnaxionAgentClient ``` or a Manager service wrapper that uses this client. Droplet action execution may use: ```python from kx_manager.ui.agent_execution_client import ... ``` as the approved HTTP/SCP/SSH execution adapter. ## 39.2 No duplicated canonical enums Do not hardcode these outside their owner modules: ```text InstanceState values NetworkProfile values ExposureMode values SecurityGateStatus values BackupStatus values RestoreStatus values RollbackStatus values DockerService values UiAction values PageId values TargetMode values ``` ## 39.3 No unmapped buttons Every GUI button must resolve to exactly one of: ```text UiAction Manager route KonnaxionAgentClient method Agent API endpoint Builder service function Deploy service function approved CLI fallback browser link ``` If a button cannot be traced through that chain, it must not exist. ## 39.4 Page split rule The page split must remain flat: ```text page_views.py thin orchestrator only page_parts/*.py page body builders only page_parts/common.py shared form/button/payload helpers page_parts/targets.py target configuration forms only page_parts/deploy.py deployment operation forms only form_targets.py POST validation and target/deploy normalization static.py route/action/alias constants ``` Targets/deploy split invariant: ```text /ui/targets must not render Deploy Local, Deploy Intranet, Deploy Droplet, Check Droplet Agent, Copy Capsule to Droplet, or Start Droplet Instance forms. /ui/deploy must render those deployment forms and must reuse the same canonical payload helpers used by target validation. ``` Do not add `kx_manager/ui/pages/` because `kx_manager/ui/pages.py` already exists. ## 39.5 Droplet anti-drift rules Never allow these generated runtime states for `public_vps`: ```text KX_HOST=127.0.0.1 Traefik Host(`127.0.0.1`) DJANGO_ALLOWED_HOSTS=127.0.0.1 only NEXT_PUBLIC_API_BASE=https://127.0.0.1/api NEXT_PUBLIC_BACKEND_BASE=https://127.0.0.1 frontend runtime command that downloads pnpm capsule with images/README.json only Docker image where source files are overwritten by migration files Django healthcheck using unavailable wget/curl ``` --- ## 40. Done Definition The GUI technical contract is satisfied when: ```text A user can open http://127.0.0.1:8714/ui, select the Konnaxion source folder, select the capsule output folder, build a .kxcap, verify it, import it, create or update an instance, set local/intranet/droplet target, deploy local/intranet/droplet from /ui/deploy, start it, view status/health/logs/security, create backups, restore or rollback when needed, without typing CLI commands. ``` Droplet/public_vps done condition: ```text Droplet Agent remains private on 127.0.0.1:8765. Manager reaches Droplet Agent through SSH-local curl. No temporary tunnel is required. Capsule includes required app image archives. Runtime images load on the Droplet. Generated env uses public host. Generated Traefik routes use public host. Frontend returns HTTP 200 at https://. Django is reachable through Traefik. Django is healthy. Postgres and Redis are healthy. Celery worker and beat run. No internal app/db/cache ports are publicly exposed. ``` Production-safe condition: ```text All privileged actions go through Manager/Agent APIs or approved service wrappers. No arbitrary shell execution exists. No public exposure is allowed without explicit confirmation. Temporary public mode requires expiration. Security Gate failures block startup. All UI routes remain local-only by default. Full pytest passes. ``` ``` ``` ================================================================================================ FILE: docs/DOC-17_Konnaxion_GUI_Action_Coverage_Contract.md AUTHORITY: reference CONTENT_ROLE: knowledge CONTENT_SHA256: 62a12d92349211df0508b888ce8042ac4f3cfd1f03993c856f6e88095a9d0df2 CONTENT_BYTES: 26791 ================================================================================================ doc_id: DOC-17 title: Konnaxion GUI Action Coverage Contract project: Konnaxion app_version: v14 param_version: kx-param-2026.04.30 status: technical-contract owner: Konnaxion last_updated: 2026-05-01 depends_on: - DOC-16_Konnaxion_Manager_GUI_Technical_Contract.md - DOC-17A_Konnaxion_GUI_Action_Payload_Contract.md - DOC-17B_Konnaxion_GUI_Action_UI_Test_Contract.md - DOC-18_Konnaxion_GUI_Target_Modes.md --- # DOC-17 — Konnaxion GUI Action Coverage Contract ## 1. Purpose This document defines the complete GUI action coverage contract for the Konnaxion Capsule Manager. It exists to prevent drift between: ```text kx_manager/ui/pages.py kx_manager/ui/app.py kx_manager/ui/actions.py kx_manager/ui/action_models.py kx_manager/ui/action_constants.py kx_manager/ui/action_helpers.py kx_manager/ui/action_backends.py kx_manager/ui/action_dispatch.py kx_manager/ui/forms.py kx_manager/ui/form_targets.py kx_manager/ui/form_registry.py kx_manager/ui/static.py kx_manager/ui/page_views.py kx_manager/ui/page_forms.py kx_manager/ui/page_parts/* kx_manager/ui/action_views.py kx_manager/ui/render.py kx_manager/ui/state.py kx_manager/ui/components.py kx_manager/client.py kx_manager/services/builder.py kx_manager/services/targets.py kx_manager/services/deploy.py kx_manager/routes/* kx_agent/api.py kx_cli/* kx_builder/* tests/test_manager_ui_contract.py tests/test_manager_ui_action_coverage.py tests/test_manager_ui_routes.py tests/test_manager_ui_forms.py tests/test_fastapi_ui_page_split.py tests/test_manager_ui_target_modes.py tests/test_ui_form_targets.py tests/test_ui_page_targets.py tests/test_ui_page_deploy.py ```` Every GUI button must map to a known action. Every action must map to one of: ```text Manager route Manager service wrapper KonnaxionAgentClient method Agent API endpoint Builder operation Deploy operation approved CLI fallback browser link ``` If a GUI button cannot be traced through this contract, it must not exist. Payload shape, alias normalization, Droplet action normalization, and normalized result shape live in: ```text DOC-17A_Konnaxion_GUI_Action_Payload_Contract.md ``` UI button placement, safety gating, labels, tests, and acceptance criteria live in: ```text DOC-17B_Konnaxion_GUI_Action_UI_Test_Contract.md ``` --- ## 2. Coverage Rule The GUI must cover the complete operator workflow: ```text check services select Konnaxion source folder select capsule output folder build capsule rebuild capsule verify capsule import capsule inspect capsules create instance update instance start instance stop instance restart instance inspect status inspect logs inspect health run Security Gate set network profile disable public mode create backup list backups verify backup restore backup restore backup into new instance test restore backup rollback instance set local target set intranet target set temporary public target set Droplet target deploy local deploy intranet bootstrap Droplet Agent check Droplet Agent copy capsule to Droplet deploy Droplet start Droplet instance open docs open runtime ``` The GUI must not be a visual-only scaffold. It must be usable instead of normal operator commands for the supported workflow. Droplet deployment has a first-time bootstrap prerequisite: ```text If the target Droplet does not already have Konnaxion Agent installed and running, the GUI must offer bootstrap_droplet_agent before check_droplet_agent. ``` --- ## 3. Canonical GUI Action Names `kx_manager/ui/pages.py` owns GUI action identity. Replace or align `UiAction` with the following complete action set: ```python class UiAction(StrEnum): CHECK_MANAGER = "check_manager" CHECK_AGENT = "check_agent" SELECT_SOURCE_FOLDER = "select_source_folder" SELECT_CAPSULE_OUTPUT_FOLDER = "select_capsule_output_folder" BUILD_CAPSULE = "build_capsule" REBUILD_CAPSULE = "rebuild_capsule" VERIFY_CAPSULE = "verify_capsule" IMPORT_CAPSULE = "import_capsule" LIST_CAPSULES = "list_capsules" VIEW_CAPSULE = "view_capsule" CREATE_INSTANCE = "create_instance" UPDATE_INSTANCE = "update_instance" START_INSTANCE = "start_instance" STOP_INSTANCE = "stop_instance" RESTART_INSTANCE = "restart_instance" INSTANCE_STATUS = "instance_status" VIEW_LOGS = "view_logs" VIEW_HEALTH = "view_health" OPEN_INSTANCE = "open_instance" ROLLBACK_INSTANCE = "rollback_instance" CREATE_BACKUP = "create_backup" LIST_BACKUPS = "list_backups" VERIFY_BACKUP = "verify_backup" RESTORE_BACKUP = "restore_backup" RESTORE_BACKUP_NEW = "restore_backup_new" TEST_RESTORE_BACKUP = "test_restore_backup" RUN_SECURITY_CHECK = "run_security_check" SET_NETWORK_PROFILE = "set_network_profile" DISABLE_PUBLIC_MODE = "disable_public_mode" SET_TARGET_LOCAL = "set_target_local" SET_TARGET_INTRANET = "set_target_intranet" SET_TARGET_DROPLET = "set_target_droplet" SET_TARGET_TEMPORARY_PUBLIC = "set_target_temporary_public" DEPLOY_LOCAL = "deploy_local" DEPLOY_INTRANET = "deploy_intranet" DEPLOY_DROPLET = "deploy_droplet" BOOTSTRAP_DROPLET_AGENT = "bootstrap_droplet_agent" CHECK_DROPLET_AGENT = "check_droplet_agent" COPY_CAPSULE_TO_DROPLET = "copy_capsule_to_droplet" START_DROPLET_INSTANCE = "start_droplet_instance" OPEN_MANAGER_DOCS = "open_manager_docs" OPEN_AGENT_DOCS = "open_agent_docs" ``` Required GUI action count: ```text 42 ``` Required non-browser POST action count: ```text 39 ``` Required browser-only action count: ```text 3 ``` Browser-only actions: ```text open_instance open_manager_docs open_agent_docs ``` --- ## 4. Action Coverage Matrix | GUI Action | Required | Primary Backend | Agent Endpoint | CLI / External Fallback | | ------------------------------ | -------: | -------------------------- | ----------------------------------- | ---------------------------------------------------- | | `check_manager` | yes | Manager health route | none | HTTP GET `/health` | | `check_agent` | yes | Manager client health call | `GET /v1/health` | HTTP GET Agent health | | `select_source_folder` | yes | UI form value | none | text input validation | | `select_capsule_output_folder` | yes | UI form value | none | text input validation | | `build_capsule` | yes | Builder service | none | `uv run kx-builder capsule build ...` | | `rebuild_capsule` | yes | Builder service | none | remove old + build | | `verify_capsule` | yes | Builder or Agent verify | `POST /v1/capsules/verify` | `uv run kx-builder capsule verify ` | | `import_capsule` | yes | Manager client | `POST /v1/capsules/import` | `uv run kx capsule import ` | | `list_capsules` | yes | Manager capsule route | none | `uv run kx capsule list` if available | | `view_capsule` | yes | Manager capsule route | none | `uv run kx capsule status ` if available | | `create_instance` | yes | Manager client | `POST /v1/instances/create` | `uv run kx instance create ` | | `update_instance` | yes | Manager client | `POST /v1/instances/update` | `uv run kx instance update ` | | `start_instance` | yes | Manager client | `POST /v1/instances/start` | `uv run kx instance start ` | | `stop_instance` | yes | Manager client | `POST /v1/instances/stop` | `uv run kx instance stop ` | | `restart_instance` | yes | composed action | stop + start | stop then start | | `instance_status` | yes | Manager client | `POST /v1/instances/status` | `uv run kx instance status ` | | `view_logs` | yes | Manager client | `POST /v1/instances/logs` | `uv run kx instance logs ` | | `view_health` | yes | Manager client | `POST /v1/instances/health` | `uv run kx instance health ` | | `open_instance` | yes | browser link | none | open runtime URL | | `rollback_instance` | yes | Manager client | `POST /v1/instances/rollback` | `uv run kx instance rollback ` | | `create_backup` | yes | Manager client | `POST /v1/instances/backup` | `uv run kx instance backup ` | | `list_backups` | yes | Manager backup route | none | `uv run kx backup list` | | `verify_backup` | yes | Manager backup route | none | `uv run kx backup verify ` | | `restore_backup` | yes | Manager client | `POST /v1/instances/restore` | `uv run kx instance restore ` | | `restore_backup_new` | yes | Manager client | `POST /v1/instances/restore-new` | `uv run kx instance restore-new ...` | | `test_restore_backup` | yes | Manager backup route | none | `uv run kx backup test-restore ` | | `run_security_check` | yes | Manager client | `POST /v1/security/check` | `uv run kx security check ` | | `set_network_profile` | yes | Manager client | `POST /v1/network/set-profile` | `uv run kx network set-profile ` | | `disable_public_mode` | yes | Manager client | `POST /v1/network/set-profile` | set private/intranet profile | | `set_target_local` | yes | Target service | none | local config write | | `set_target_intranet` | yes | Target service | none | intranet config write | | `set_target_droplet` | yes | Target service | none | Droplet config write | | `set_target_temporary_public` | yes | Target service | none | temporary public config write | | `deploy_local` | yes | Deploy service | Manager/Agent sequence | approved CLI sequence | | `deploy_intranet` | yes | Deploy service | Manager/Agent sequence | approved CLI sequence | | `deploy_droplet` | yes | Deploy service | remote Agent / approved remote path | `scp`/SFTP + approved remote operation | | `bootstrap_droplet_agent` | yes | Deploy service | none before bootstrap | approved SSH/SCP bootstrap only | | `check_droplet_agent` | yes | Deploy service | remote Agent health | SSH-local health check or HTTP health check | | `copy_capsule_to_droplet` | yes | Deploy service | none | `scp` or SFTP library | | `start_droplet_instance` | yes | Deploy service | remote Agent start | remote approved operation | | `open_manager_docs` | yes | browser link | none | open Manager `/docs` | | `open_agent_docs` | yes | browser link | none | open Agent `/docs` | --- ## 5. Backend Priority Each GUI action must use the strongest available backend in this order: ```text 1. Manager API / service call 2. KonnaxionAgentClient method 3. Agent API endpoint 4. Builder Python API 5. Deploy service / target service 6. Approved CLI fallback 7. Browser link ``` CLI fallback is allowed only as a temporary bridge. CLI fallback rules: ```text shell=False fixed command executable fixed subcommand list validated user input only no arbitrary shell text no arbitrary Docker command no arbitrary service name no arbitrary host path except approved source/capsule/runtime paths stdout captured stderr captured returncode captured result normalized ``` Remote fallback rules for Droplet: ```text no password in command string SSH key path must be validated remote host must be explicit remote user must be explicit remote root must be explicit remote capsule directory must be under remote root remote command must be allowlisted capsule copy target must be remote capsule directory no arbitrary remote command text no shell=True with untrusted input ``` Bootstrap fallback rules for Droplet: ```text bootstrap_droplet_agent must require explicit Droplet confirmation bootstrap_droplet_agent must use the configured droplet_host bootstrap_droplet_agent must use the configured droplet_user bootstrap_droplet_agent must use the configured ssh_key_path bootstrap_droplet_agent must use the configured ssh_port bootstrap_droplet_agent must use the configured remote_kx_root bootstrap_droplet_agent must create only approved Konnaxion runtime directories bootstrap_droplet_agent must install/start only the Konnaxion Agent service bootstrap_droplet_agent must bind the Agent to 127.0.0.1:8765 by default bootstrap_droplet_agent must not expose Agent port 8765 publicly bootstrap_droplet_agent must verify Agent health through SSH-local loopback bootstrap_droplet_agent must return stdout, stderr, returncode, and normalized result data ``` --- ## 6. Required FastAPI GUI Routes `kx_manager/ui/app.py` must expose: ```python def register(app: FastAPI) -> Any: ... ``` The function must register all routes below. --- ## 6.1 Page routes | Method | Route | Purpose | | ------ | --------------- | ------------------------------------------- | | `GET` | `/ui` | Dashboard | | `GET` | `/ui/capsules` | Capsule operations | | `GET` | `/ui/instances` | Instance operations | | `GET` | `/ui/security` | Security Gate | | `GET` | `/ui/network` | Network profiles | | `GET` | `/ui/backups` | Backup operations | | `GET` | `/ui/restore` | Restore/rollback | | `GET` | `/ui/logs` | Logs | | `GET` | `/ui/health` | Health | | `GET` | `/ui/settings` | Settings | | `GET` | `/ui/targets` | Local/intranet/public/Droplet target config | | `GET` | `/ui/deploy` | Local/intranet/Droplet deployment actions | | `GET` | `/ui/about` | Product/about page | --- ## 6.2 Action routes | Method | Route | GUI Action | | ------ | ------------------------------------------ | ------------------------------ | | `POST` | `/ui/actions/check-manager` | `check_manager` | | `POST` | `/ui/actions/check-agent` | `check_agent` | | `POST` | `/ui/actions/select-source-folder` | `select_source_folder` | | `POST` | `/ui/actions/select-capsule-output-folder` | `select_capsule_output_folder` | | `POST` | `/ui/actions/build-capsule` | `build_capsule` | | `POST` | `/ui/actions/rebuild-capsule` | `rebuild_capsule` | | `POST` | `/ui/actions/verify-capsule` | `verify_capsule` | | `POST` | `/ui/actions/import-capsule` | `import_capsule` | | `POST` | `/ui/actions/list-capsules` | `list_capsules` | | `POST` | `/ui/actions/view-capsule` | `view_capsule` | | `POST` | `/ui/actions/create-instance` | `create_instance` | | `POST` | `/ui/actions/update-instance` | `update_instance` | | `POST` | `/ui/actions/start-instance` | `start_instance` | | `POST` | `/ui/actions/stop-instance` | `stop_instance` | | `POST` | `/ui/actions/restart-instance` | `restart_instance` | | `POST` | `/ui/actions/instance-status` | `instance_status` | | `POST` | `/ui/actions/view-logs` | `view_logs` | | `POST` | `/ui/actions/view-health` | `view_health` | | `POST` | `/ui/actions/rollback-instance` | `rollback_instance` | | `POST` | `/ui/actions/create-backup` | `create_backup` | | `POST` | `/ui/actions/list-backups` | `list_backups` | | `POST` | `/ui/actions/verify-backup` | `verify_backup` | | `POST` | `/ui/actions/restore-backup` | `restore_backup` | | `POST` | `/ui/actions/restore-backup-new` | `restore_backup_new` | | `POST` | `/ui/actions/test-restore-backup` | `test_restore_backup` | | `POST` | `/ui/actions/run-security-check` | `run_security_check` | | `POST` | `/ui/actions/set-network-profile` | `set_network_profile` | | `POST` | `/ui/actions/disable-public-mode` | `disable_public_mode` | | `POST` | `/ui/actions/set-target-local` | `set_target_local` | | `POST` | `/ui/actions/set-target-intranet` | `set_target_intranet` | | `POST` | `/ui/actions/set-target-droplet` | `set_target_droplet` | | `POST` | `/ui/actions/set-target-temporary-public` | `set_target_temporary_public` | | `POST` | `/ui/actions/deploy-local` | `deploy_local` | | `POST` | `/ui/actions/deploy-intranet` | `deploy_intranet` | | `POST` | `/ui/actions/deploy-droplet` | `deploy_droplet` | | `POST` | `/ui/actions/bootstrap-droplet-agent` | `bootstrap_droplet_agent` | | `POST` | `/ui/actions/check-droplet-agent` | `check_droplet_agent` | | `POST` | `/ui/actions/copy-capsule-to-droplet` | `copy_capsule_to_droplet` | | `POST` | `/ui/actions/start-droplet-instance` | `start_droplet_instance` | Browser-only actions: | GUI Action | Route / URL source | | ------------------- | ----------------------------------------------------- | | `open_instance` | Runtime URL from payload/result | | `open_manager_docs` | Manager `/docs` | | `open_agent_docs` | Agent docs URL, normally `http://127.0.0.1:8765/docs` | Browser-only actions must not register POST `/ui/actions/...` routes. --- ## 6.3 Page/action ownership Target selection and deployment execution must be separated. `/ui/targets` owns only target configuration forms: ```text set_target_local set_target_intranet set_target_droplet set_target_temporary_public ``` `/ui/deploy` owns deployment and Droplet operation forms: ```text deploy_local deploy_intranet deploy_droplet bootstrap_droplet_agent check_droplet_agent copy_capsule_to_droplet start_droplet_instance ``` The POST action routes do not change. Deployment actions still submit to canonical `/ui/actions/...` routes. `/ui/targets` must not render the deployment action grid. `/ui/deploy` may reuse the same canonical payload helpers as `/ui/targets`, but it must preserve these invariants: ```text local deployment submits target_mode=local intranet deployment submits target_mode=intranet Droplet deployment submits target_mode=droplet Droplet deployment submits network_profile=public_vps Droplet deployment submits exposure_mode=public Droplet deployment submits confirmed=true Droplet deployment requires domain Droplet domain is not silently invented from droplet_host bootstrap_droplet_agent does not require or submit capsule_file check_droplet_agent does not require or submit capsule_file ``` Droplet operation order on `/ui/deploy` must be: ```text 1. Bootstrap Droplet Agent 2. Check Droplet Agent 3. Copy Capsule to Droplet 4. Deploy Droplet 5. Start Droplet Instance ``` `Start Droplet Instance` is a recovery/follow-up action and is not the primary first-time deployment path. --- ## 7. Required Agent Endpoints Agent API base: ```text http://127.0.0.1:8765/v1 ``` | Method | Path | Action | | ------ | ------------------------ | -------------------------------------------- | | `GET` | `/health` | `check_agent` | | `GET` | `/agent/info` | Agent metadata | | `POST` | `/capsules/import` | `import_capsule` | | `POST` | `/capsules/verify` | `verify_capsule` | | `POST` | `/instances/create` | `create_instance` | | `POST` | `/instances/start` | `start_instance` | | `POST` | `/instances/stop` | `stop_instance` | | `POST` | `/instances/status` | `instance_status` | | `POST` | `/instances/logs` | `view_logs` | | `POST` | `/instances/backup` | `create_backup` | | `POST` | `/instances/restore` | `restore_backup` | | `POST` | `/instances/restore-new` | `restore_backup_new` | | `POST` | `/instances/update` | `update_instance` | | `POST` | `/instances/rollback` | `rollback_instance` | | `POST` | `/instances/health` | `view_health` | | `POST` | `/security/check` | `run_security_check` | | `POST` | `/network/set-profile` | `set_network_profile`, `disable_public_mode` | Remote Droplet Agent endpoints use the same API path with the remote Agent base URL after the remote Agent has been bootstrapped. `bootstrap_droplet_agent` is a pre-Agent operation. It must not require a working remote Agent endpoint before it runs. --- ## 8. Required Client Methods `kx_manager/client.py` must expose or keep equivalent methods: ```text health() agent_info() import_capsule() verify_capsule() create_instance() start_instance() stop_instance() instance_status() instance_logs() backup_instance() restore_instance() restore_new_instance() update_instance() rollback_instance() instance_health() security_check() set_network_profile() ``` Additional Manager-local methods or service wrappers required by GUI: ```text build_capsule() rebuild_capsule() list_capsules() view_capsule() list_backups() verify_backup() test_restore_backup() restart_instance() disable_public_mode() select_source_folder() select_capsule_output_folder() set_target_local() set_target_intranet() set_target_droplet() set_target_temporary_public() deploy_local() deploy_intranet() deploy_droplet() bootstrap_droplet_agent() check_droplet_agent() copy_capsule_to_droplet() start_droplet_instance() ``` If these are not part of `KonnaxionAgentClient`, they must be implemented as Manager-local services or route helpers. `bootstrap_droplet_agent()` must be implemented as a Manager-local deploy service/helper because it runs before the remote Agent exists. --- ## 9. Companion Contracts Payload and normalization rules: ```text DOC-17A_Konnaxion_GUI_Action_Payload_Contract.md ``` UI button coverage, safety rules, labels, tests, and acceptance: ```text DOC-17B_Konnaxion_GUI_Action_UI_Test_Contract.md ``` --- ## 10. Final Rule Every GUI action must be traceable through this chain: ```text button/label -> UiAction -> form model -> action route or browser link -> action dispatcher -> Manager service / client / route -> Agent endpoint / Builder service / Deploy service / CLI fallback -> normalized GuiActionResult -> rendered result panel ``` If any link in that chain is missing, the action is incomplete. Droplet actions have one extra invariant: ```text button/form -> Droplet payload builder -> target_mode=droplet -> network_profile=public_vps -> exposure_mode=public -> confirmed=true -> required Droplet fields -> validated action payload -> dispatch ``` Droplet actions must never inherit the private/intranet default payload. Droplet bootstrap has one extra invariant: ```text button/form -> bootstrap_droplet_agent -> target_mode=droplet -> network_profile=public_vps -> exposure_mode=public -> confirmed=true -> required Droplet SSH fields -> no capsule_file required -> SSH/SCP allowlisted bootstrap -> install/start Konnaxion Agent on 127.0.0.1:8765 -> verify remote Agent health through SSH-local loopback -> normalized GuiActionResult ``` `bootstrap_droplet_agent` must not open the Agent API publicly. ================================================================================================ FILE: docs/DOC-17A_Konnaxion_GUI_Action_Payload_Contract.md AUTHORITY: reference CONTENT_ROLE: knowledge CONTENT_SHA256: 6530d2d097b87e8617ecf1766ff758144b4114b67d5f4626679d635c51c2f445 CONTENT_BYTES: 22002 ================================================================================================ doc_id: DOC-17A title: Konnaxion GUI Action Payload Contract project: Konnaxion app_version: v14 param_version: kx-param-2026.04.30 status: technical-contract owner: Konnaxion last_updated: 2026-05-02 depends_on: - DOC-16_Konnaxion_Manager_GUI_Technical_Contract.md - DOC-17_Konnaxion_GUI_Action_Coverage_Contract.md - DOC-17B_Konnaxion_GUI_Action_UI_Test_Contract.md - DOC-18_Konnaxion_GUI_Target_Modes.md --- # DOC-17A — Konnaxion GUI Action Payload Contract ## 1. Purpose This document defines the canonical request payloads, normalization rules, target-mode gates, Droplet operation payloads, and payload validation expectations for the Konnaxion Capsule Manager GUI. This contract exists so every GUI action submits a safe, complete, deterministic payload to the Manager action dispatcher. The GUI must never allow a Droplet operation to inherit local, intranet, private, or temporary-public defaults. --- ## 2. Global Payload Rules Every GUI action payload must include: ```text action ```` Every instance-scoped operation must include: ```text instance_id ``` Every target/deploy operation must include: ```text target_mode network_profile exposure_mode ``` Boolean values may arrive from HTML forms as strings. Payload validation must normalize: ```text "true", "1", "yes", "on" -> true "false", "0", "no", "off" -> false ``` Empty strings must be treated as absent unless the field explicitly allows an empty value. Sensitive values such as SSH key paths may be accepted and displayed, but secret values, passwords, tokens, private keys, and generated credentials must be redacted in logs and UI results. --- ## 3. Required Request Payloads ### 3.1 Set Local Target ```json { "action": "set_target_local", "target_mode": "local", "network_profile": "local_only", "exposure_mode": "private", "instance_id": "demo-001", "runtime_root": "C:\\mycode\\Konnaxion\\runtime", "capsule_dir": "C:\\mycode\\Konnaxion\\runtime\\capsules" } ``` `set_target_local` must reject Droplet fields. It must not submit: ```text droplet_host droplet_user ssh_key_path remote_kx_root remote_capsule_dir domain droplet_domain remote_agent_url ``` --- ### 3.2 Set Intranet Target ```json { "action": "set_target_intranet", "target_mode": "intranet", "network_profile": "intranet_private", "exposure_mode": "private", "instance_id": "demo-001", "host": "konnaxion.local", "runtime_root": "C:\\mycode\\Konnaxion\\runtime", "capsule_dir": "C:\\mycode\\Konnaxion\\runtime\\capsules" } ``` Allowed exposure values: ```text private lan ``` `set_target_intranet` must reject Droplet fields. --- ### 3.3 Set Temporary Public Target ```json { "action": "set_target_temporary_public", "target_mode": "temporary_public", "network_profile": "public_temporary", "exposure_mode": "temporary_tunnel", "public_mode_enabled": true, "public_mode_expires_at": "2026-05-02T23:59:00-04:00", "instance_id": "demo-001", "confirmed": true } ``` `temporary_public` requires: ```text public_mode_expires_at confirmed = true ``` It must not be accepted without an expiration. --- ### 3.4 Set Droplet Target ```json { "action": "set_target_droplet", "target_mode": "droplet", "network_profile": "public_vps", "exposure_mode": "public", "public_mode_enabled": true, "instance_id": "demo-001", "droplet_name": "konnaxion-droplet", "droplet_host": "203.0.113.10", "host": "203.0.113.10", "droplet_user": "root", "ssh_user": "root", "user": "root", "ssh_key_path": "C:\\Users\\rejea\\.ssh\\id_ed25519", "ssh_port": "22", "remote_kx_root": "/opt/konnaxion", "remote_root": "/opt/konnaxion", "runtime_root": "/opt/konnaxion", "remote_capsule_dir": "/opt/konnaxion/capsules", "capsule_dir": "/opt/konnaxion/capsules", "domain": "203.0.113.10.sslip.io", "droplet_domain": "203.0.113.10.sslip.io", "remote_agent_url": "", "confirmed": true } ``` `set_target_droplet` must reject missing `confirmed`. Droplet target mode requires: ```text target_mode = droplet network_profile = public_vps exposure_mode = public droplet_host is present droplet_user is present ssh_key_path is present ssh_port is present remote_kx_root is present remote_capsule_dir is present domain is present confirmed = true ``` `remote_capsule_dir` must be under `remote_kx_root`. `remote_agent_url` should normally be blank. Blank means the Manager must reach the private Droplet Agent through SSH-local curl: ```text ssh root@ "curl http://127.0.0.1:8765/v1/health" ``` --- ### 3.5 Bootstrap Droplet Agent ```json { "action": "bootstrap_droplet_agent", "target_mode": "droplet", "network_profile": "public_vps", "exposure_mode": "public", "public_mode_enabled": true, "instance_id": "demo-001", "droplet_name": "konnaxion-droplet", "droplet_host": "203.0.113.10", "host": "203.0.113.10", "droplet_user": "root", "ssh_user": "root", "user": "root", "ssh_key_path": "C:\\Users\\rejea\\.ssh\\id_ed25519", "ssh_port": "22", "remote_kx_root": "/opt/konnaxion", "remote_root": "/opt/konnaxion", "runtime_root": "/opt/konnaxion", "remote_capsule_dir": "/opt/konnaxion/capsules", "capsule_dir": "/opt/konnaxion/capsules", "domain": "203.0.113.10.sslip.io", "droplet_domain": "203.0.113.10.sslip.io", "remote_agent_url": "", "confirmed": true } ``` `bootstrap_droplet_agent` is a first-time Droplet preparation action. It must: ```text connect to the Droplet over SSH create the canonical /opt/konnaxion runtime layout install or refresh the Konnaxion Manager/Agent code install required runtime dependencies install or refresh the Konnaxion Agent systemd service start the Agent bound to 127.0.0.1:8765 verify http://127.0.0.1:8765/v1/health from inside the Droplet ``` It must not require: ```text capsule_file capsule_path ``` It must not expose Agent port `8765` publicly. Bootstrap currently requires `droplet_user=root` because it may install packages, write `/etc/systemd/system/konnaxion-agent.service`, reload systemd, enable the service, and start it. A successful bootstrap result must include enough data to verify: ```text remote_kx_root remote_manager_dir remote_agent_health_url = http://127.0.0.1:8765/v1/health systemd_service = konnaxion-agent.service ``` --- ### 3.6 Check Droplet Agent ```json { "action": "check_droplet_agent", "target_mode": "droplet", "network_profile": "public_vps", "exposure_mode": "public", "public_mode_enabled": true, "instance_id": "demo-001", "droplet_name": "konnaxion-droplet", "droplet_host": "203.0.113.10", "host": "203.0.113.10", "droplet_user": "root", "ssh_key_path": "C:\\Users\\rejea\\.ssh\\id_ed25519", "ssh_port": "22", "remote_kx_root": "/opt/konnaxion", "remote_capsule_dir": "/opt/konnaxion/capsules", "domain": "203.0.113.10.sslip.io", "droplet_domain": "203.0.113.10.sslip.io", "remote_agent_url": "", "confirmed": true } ``` `check_droplet_agent` must not require: ```text capsule_file capsule_path ``` When `remote_agent_url` is blank, the check must use SSH-local curl against: ```text http://127.0.0.1:8765/v1/health ``` from inside the Droplet. --- ### 3.7 Copy Capsule to Droplet ```json { "action": "copy_capsule_to_droplet", "target_mode": "droplet", "network_profile": "public_vps", "exposure_mode": "public", "public_mode_enabled": true, "instance_id": "demo-001", "capsule_file": "C:\\mycode\\Konnaxion\\runtime\\capsules\\konnaxion-v14-demo-2026.04.30.kxcap", "capsule_path": "C:\\mycode\\Konnaxion\\runtime\\capsules\\konnaxion-v14-demo-2026.04.30.kxcap", "droplet_name": "konnaxion-droplet", "droplet_host": "203.0.113.10", "host": "203.0.113.10", "droplet_user": "root", "ssh_key_path": "C:\\Users\\rejea\\.ssh\\id_ed25519", "ssh_port": "22", "remote_kx_root": "/opt/konnaxion", "remote_capsule_dir": "/opt/konnaxion/capsules", "domain": "203.0.113.10.sslip.io", "droplet_domain": "203.0.113.10.sslip.io", "remote_agent_url": "", "confirmed": true } ``` `copy_capsule_to_droplet` requires: ```text capsule_file ``` It must copy the capsule to: ```text /opt/konnaxion/capsules/.kxcap ``` --- ### 3.8 Deploy Droplet ```json { "action": "deploy_droplet", "target_mode": "droplet", "network_profile": "public_vps", "exposure_mode": "public", "public_mode_enabled": true, "instance_id": "demo-001", "capsule_file": "C:\\mycode\\Konnaxion\\runtime\\capsules\\konnaxion-v14-demo-2026.04.30.kxcap", "capsule_path": "C:\\mycode\\Konnaxion\\runtime\\capsules\\konnaxion-v14-demo-2026.04.30.kxcap", "droplet_name": "konnaxion-droplet", "droplet_host": "203.0.113.10", "host": "203.0.113.10", "droplet_user": "root", "ssh_key_path": "C:\\Users\\rejea\\.ssh\\id_ed25519", "ssh_port": "22", "remote_kx_root": "/opt/konnaxion", "remote_capsule_dir": "/opt/konnaxion/capsules", "domain": "203.0.113.10.sslip.io", "droplet_domain": "203.0.113.10.sslip.io", "remote_agent_url": "", "confirmed": true } ``` `deploy_droplet` requires: ```text capsule_file ``` It must run the full workflow: ```text verify local capsule copy capsule to Droplet ensure remote runtime directories check private Droplet Agent import capsule through SSH-local Agent transport create or update instance set public_vps network profile run Security Gate start instance ``` --- ### 3.9 Start Droplet Instance ```json { "action": "start_droplet_instance", "target_mode": "droplet", "network_profile": "public_vps", "exposure_mode": "public", "public_mode_enabled": true, "instance_id": "demo-001", "capsule_file": "C:\\mycode\\Konnaxion\\runtime\\capsules\\konnaxion-v14-demo-2026.04.30.kxcap", "droplet_name": "konnaxion-droplet", "droplet_host": "203.0.113.10", "host": "203.0.113.10", "droplet_user": "root", "ssh_key_path": "C:\\Users\\rejea\\.ssh\\id_ed25519", "ssh_port": "22", "remote_kx_root": "/opt/konnaxion", "remote_capsule_dir": "/opt/konnaxion/capsules", "domain": "203.0.113.10.sslip.io", "droplet_domain": "203.0.113.10.sslip.io", "remote_agent_url": "", "confirmed": true } ``` `start_droplet_instance` requires: ```text capsule_file ``` The file is required so the GUI keeps the same capsule context as deploy/copy operations. --- ## 4. Canonical Droplet Action Sets Use the same sets in: ```text kx_manager/ui/form_targets.py tests kx_manager/ui/page_parts/targets.py kx_manager/ui/page_parts/deploy.py ``` ```python DROPLET_ACTIONS: frozenset[str] = frozenset( { "set_target_droplet", "bootstrap_droplet_agent", "deploy_droplet", "check_droplet_agent", "copy_capsule_to_droplet", "start_droplet_instance", } ) DROPLET_OPERATION_ACTIONS: frozenset[str] = frozenset( { "bootstrap_droplet_agent", "deploy_droplet", "check_droplet_agent", "copy_capsule_to_droplet", "start_droplet_instance", } ) DROPLET_CAPSULE_REQUIRED_ACTIONS: frozenset[str] = frozenset( { "deploy_droplet", "copy_capsule_to_droplet", "start_droplet_instance", } ) ``` For these operation actions, force/default: ```python target_mode = "droplet" network_profile = "public_vps" exposure_mode = "public" confirmed = True ``` `set_target_droplet` must still reject missing `confirmed`. Operation actions may force confirmation because they are explicit Droplet operation forms. `bootstrap_droplet_agent` and `check_droplet_agent` must not require `capsule_file`. `deploy_droplet`, `copy_capsule_to_droplet`, and `start_droplet_instance` must require `capsule_file`. --- ## 5. Droplet Alias Normalization Droplet forms may submit compatibility aliases. Normalize these aliases before validation: ```text ssh_user -> droplet_user user -> droplet_user remote_root -> remote_kx_root runtime_root -> remote_kx_root capsule_dir -> remote_capsule_dir droplet_domain -> domain ``` For Agent network/profile calls: ```text domain -> host droplet_domain -> host ``` Do not send `domain` to Agent endpoints unless that endpoint explicitly accepts it. --- ## 6. Remote Agent URL Rules Blank `remote_agent_url` means: ```text use SSH-local curl to http://127.0.0.1:8765/v1 inside the Droplet ``` The GUI must ignore stale local tunnel URLs for Droplet payloads: ```text http://127.0.0.1:18765/v1 http://localhost:18765/v1 ``` Those URLs point to the Manager machine, not the Droplet. The GUI may use direct HTTP only when `remote_agent_url` is explicitly configured to a real, non-loopback Agent endpoint that matches the selected remote target. The preferred secure mode is still: ```text Agent private on 127.0.0.1:8765 inside Droplet Manager calls Agent through SSH-local curl ``` The Agent port `8765` must not be opened publicly. --- ## 7. Deploy Page Rendering Rules `kx_manager/ui/page_parts/deploy.py` should render deployment and operation actions: ```text deploy_local deploy_intranet bootstrap_droplet_agent check_droplet_agent copy_capsule_to_droplet deploy_droplet start_droplet_instance ``` Droplet operation cards must appear in this operator workflow order: ```text 1. Bootstrap Droplet Agent 2. Check Droplet Agent 3. Copy Capsule to Droplet 4. Deploy Droplet 5. Start Droplet Instance ``` For these actions, use full Droplet operation forms, not hidden-only buttons: ```text bootstrap_droplet_agent check_droplet_agent copy_capsule_to_droplet deploy_droplet start_droplet_instance ``` `deploy_droplet`, `copy_capsule_to_droplet`, and `start_droplet_instance` must include visible `capsule_file`. `bootstrap_droplet_agent` and `check_droplet_agent` do not require `capsule_file` and must not submit `capsule_file`, even as hidden input. `deploy_local` and `deploy_intranet` may remain compact button forms, but their payloads must come from: ```text local_payload(context) intranet_payload(context) ``` The deploy page contract puts Droplet operations on: ```text /ui/deploy ``` not on: ```text /ui/targets ``` Therefore `bootstrap_droplet_agent` belongs on `/ui/deploy`. --- ## 8. Target Page Rendering Rules `/ui/targets` must render target-selection forms only: ```text set_target_local set_target_intranet set_target_temporary_public set_target_droplet ``` `/ui/targets` must not render deployment/operation forms: ```text deploy_local deploy_intranet bootstrap_droplet_agent check_droplet_agent copy_capsule_to_droplet deploy_droplet start_droplet_instance ``` --- ## 9. Test Payload Alignment Tests that build base payloads for Droplet actions must include `bootstrap_droplet_agent` in the Droplet action set. ```python if action in { "set_target_droplet", "bootstrap_droplet_agent", "deploy_droplet", "check_droplet_agent", "copy_capsule_to_droplet", "start_droplet_instance", }: base.update( { "target_mode": "droplet", "network_profile": "public_vps", "exposure_mode": "public", "droplet_name": "ubuntu-s-1vcpu-2gb-tor1", "droplet_host": "203.0.113.10", "host": "203.0.113.10", "droplet_user": "root", "ssh_key_path": str(ssh_key_path), "ssh_port": "22", "remote_kx_root": "/opt/konnaxion", "runtime_root": "/opt/konnaxion", "remote_capsule_dir": "/opt/konnaxion/capsules", "capsule_dir": "/opt/konnaxion/capsules", "domain": "203.0.113.10.sslip.io", "droplet_domain": "203.0.113.10.sslip.io", "confirmed": "true", } ) ``` For actions in: ```text bootstrap_droplet_agent check_droplet_agent ``` tests must assert: ```text capsule_file is not required capsule_path is not required capsule_file is not submitted, even as hidden input ``` For actions in: ```text deploy_droplet copy_capsule_to_droplet start_droplet_instance ``` tests must assert: ```text capsule_file is required capsule_file is visible in the form ``` --- ## 10. Required UI Labels Use these exact labels: ```text Check Manager Check Agent Select Source Folder Select Output Folder Build Capsule Rebuild Capsule Verify Capsule Import Capsule List Capsules View Capsule Create Instance Update Instance Start Instance Stop Instance Restart Instance Instance Status View Logs Instance Health Open Instance Rollback Create Backup List Backups Verify Backup Restore Backup Restore Backup New Test Restore Backup Run Security Check Set Network Profile Disable Public Mode Set Local Target Set Intranet Target Set Droplet Target Set Temporary Public Target Deploy Local Deploy Intranet Bootstrap Droplet Agent Deploy Droplet Check Droplet Agent Copy Capsule to Droplet Start Droplet Instance Open Manager Docs Open Agent Docs ``` Danger labels must include: ```text Bootstrap Droplet Agent Deploy Droplet Copy Capsule to Droplet Start Droplet Instance Disable Public Mode Rollback Restore Backup Restore Backup New ``` `Bootstrap Droplet Agent` is a danger/privileged operation because it can install packages, write systemd service files, enable a service, and start services on the target host. --- ## 11. Droplet Bootstrap Gating `bootstrap_droplet_agent` is allowed only when: ```text target_mode = droplet network_profile = public_vps exposure_mode = public droplet_host is present droplet_user is present ssh_key_path is present ssh_port is present remote_kx_root is present remote_capsule_dir is present domain is present confirmed = true ``` `bootstrap_droplet_agent` must reject private/intranet/default payloads. `bootstrap_droplet_agent` must not require `capsule_file`. `bootstrap_droplet_agent` must not expose Agent port `8765` publicly. A successful bootstrap result must include enough data to verify: ```text remote_kx_root remote_manager_dir remote_agent_health_url = http://127.0.0.1:8765/v1/health systemd_service = konnaxion-agent.service ``` --- ## 12. Public Exposure / Droplet Gating Public exposure is allowed only when: ```text target_mode = droplet network_profile = public_vps exposure_mode = public confirmed = true domain is present ``` Temporary public exposure is allowed only when: ```text target_mode = temporary_public network_profile = public_temporary exposure_mode = temporary_tunnel public_mode_expires_at is present confirmed = true ``` Private/local/intranet payloads must not include public Droplet fields. Droplet payloads must never inherit: ```text target_mode = intranet network_profile = intranet_private exposure_mode = private ``` The following submitted payload must never reach dispatch uncorrected: ```json { "action": "copy_capsule_to_droplet", "target_mode": "intranet", "network_profile": "intranet_private", "exposure_mode": "private" } ``` Validated output for Droplet operation actions must normalize to: ```json { "target_mode": "droplet", "network_profile": "public_vps", "exposure_mode": "public", "confirmed": true } ``` with all required Droplet fields present. --- ## 13. Action-Specific Capsule Requirements Must require `capsule_file`: ```text deploy_droplet copy_capsule_to_droplet start_droplet_instance ``` Must not require `capsule_file`: ```text bootstrap_droplet_agent check_droplet_agent ``` Must not submit `capsule_file`, even hidden: ```text bootstrap_droplet_agent check_droplet_agent ``` --- ## 14. Normalized Result Shape All GUI action results must normalize to: ```json { "ok": true, "action": "action_name", "instance_id": "demo-001", "message": "Human-readable message.", "data": {}, "stdout": null, "stderr": null, "returncode": null } ``` Droplet bootstrap success must include: ```json { "remote_kx_root": "/opt/konnaxion", "remote_manager_dir": "/opt/konnaxion/manager", "remote_agent_health_url": "http://127.0.0.1:8765/v1/health", "systemd_service": "konnaxion-agent.service", "agent_transport": "ssh" } ``` --- ## 15. Required Tests Create or update: ```text tests/test_manager_ui_action_coverage.py tests/test_manager_ui_routes.py tests/test_manager_ui_forms.py tests/test_fastapi_ui_page_split.py tests/test_manager_ui_target_modes.py tests/test_ui_form_targets.py tests/test_ui_page_targets.py tests/test_ui_page_deploy.py ``` The test set must verify: ```text bootstrap_droplet_agent action exists bootstrap_droplet_agent label exists bootstrap_droplet_agent route exists bootstrap_droplet_agent form model exists bootstrap_droplet_agent appears on /ui/deploy bootstrap_droplet_agent does not appear on /ui/targets bootstrap_droplet_agent appears before check/deploy in Droplet workflow order bootstrap_droplet_agent submits canonical droplet/public_vps/public values bootstrap_droplet_agent requires confirmation bootstrap_droplet_agent does not require capsule_file bootstrap_droplet_agent does not submit capsule_file check_droplet_agent does not require capsule_file deploy/copy/start require capsule_file Droplet operation actions never inherit intranet defaults Droplet operation actions include required SSH and remote root fields ``` --- ## 16. Required Commands Run: ```powershell uv run python -m compileall kx_manager/ui kx_manager/services tests uv run pytest -q ``` Expected result: ```text pytest passes ``` --- ## 17. Done Definition This contract is satisfied when: ```text /ui/deploy renders Bootstrap Droplet Agent first in the Droplet workflow bootstrap_droplet_agent has a POST route bootstrap_droplet_agent validates Droplet/public_vps/public payloads bootstrap_droplet_agent rejects private/intranet/default payloads bootstrap_droplet_agent does not require capsule_file bootstrap_droplet_agent starts the remote Agent privately on 127.0.0.1:8765 check/deploy/copy/start continue to use the same canonical Droplet payload normalization remote_agent_url blank means SSH-local Agent transport no Droplet operation opens port 8765 publicly pytest passes ``` ================================================================================================ FILE: docs/DOC-17B_Konnaxion_GUI_Action_UI_Test_Contract.md AUTHORITY: reference CONTENT_ROLE: knowledge CONTENT_SHA256: f66c6d0f3c80e59ae1ee20e9bb2737b43fb9ee4be347200cebaf07dddf04b74d CONTENT_BYTES: 14113 ================================================================================================ doc_id: DOC-17B title: Konnaxion GUI Action UI and Test Contract project: Konnaxion app_version: v14 param_version: kx-param-2026.04.30 status: technical-contract owner: Konnaxion last_updated: 2026-05-01 depends_on: - DOC-16_Konnaxion_Manager_GUI_Technical_Contract.md - DOC-17_Konnaxion_GUI_Action_Coverage_Contract.md - DOC-17A_Konnaxion_GUI_Action_Payload_Contract.md - DOC-18_Konnaxion_GUI_Target_Modes.md --- # DOC-17B — Konnaxion GUI Action UI and Test Contract ## 1. Purpose This document defines the GUI button coverage, safety gating, canonical labels, required tests, and acceptance criteria for the Konnaxion Capsule Manager GUI. Action identity, backend ownership, route coverage, Agent endpoints, and client method requirements are defined in: ```text DOC-17_Konnaxion_GUI_Action_Coverage_Contract.md ```` Payload shape, alias normalization, Droplet action normalization, and normalized action result shape are defined in: ```text DOC-17A_Konnaxion_GUI_Action_Payload_Contract.md ``` This document exists to ensure the GUI is usable as an operator surface and not only as a visual scaffold. --- ## 2. UI Button Coverage Rule The GUI must provide all required actions across the page set. A button may appear on one primary page and optionally as a shortcut elsewhere. Every rendered button or form must submit one canonical `UiAction` or open one browser-only link. No GUI button may exist unless it maps to: ```text UiAction action route browser link validated form model action dispatcher handler normalized action result ``` --- ## 3. Dashboard Page Coverage The Dashboard should include shortcuts for: ```text Check Manager Check Agent Build Capsule Verify Capsule Import Capsule Create Instance Run Security Check Start Instance Open Manager Docs Open Agent Docs ``` Required canonical actions: ```text check_manager check_agent build_capsule verify_capsule import_capsule create_instance run_security_check start_instance open_manager_docs open_agent_docs ``` Browser-only actions on this page: ```text open_manager_docs open_agent_docs ``` --- ## 4. Settings Page Coverage The Settings page must include: ```text Select Source Folder Select Output Folder ``` Required canonical actions: ```text select_source_folder select_capsule_output_folder ``` --- ## 5. Capsules Page Coverage The Capsules page must include: ```text Build Capsule Verify Capsule Import Capsule List Capsules View Capsule ``` The Capsules page should include: ```text Rebuild Capsule ``` Required canonical actions: ```text build_capsule verify_capsule import_capsule list_capsules view_capsule rebuild_capsule ``` --- ## 6. Instances Page Coverage The Instances page must include: ```text Create Instance Update Instance Start Instance Stop Instance Restart Instance Instance Status View Logs Instance Health Rollback Open Instance ``` Required canonical actions: ```text create_instance update_instance start_instance stop_instance restart_instance instance_status view_logs view_health rollback_instance open_instance ``` Browser-only actions on this page: ```text open_instance ``` --- ## 7. Backups Page Coverage The Backups page must include: ```text Create Backup List Backups Verify Backup ``` Required canonical actions: ```text create_backup list_backups verify_backup ``` --- ## 8. Restore Page Coverage The Restore page must include: ```text Restore Backup Restore Backup New Test Restore Backup Rollback ``` Required canonical actions: ```text restore_backup restore_backup_new test_restore_backup rollback_instance ``` --- ## 9. Network Page Coverage The Network page must include: ```text Set Network Profile Disable Public Mode ``` Required canonical actions: ```text set_network_profile disable_public_mode ``` --- ## 10. Security Page Coverage The Security page must include: ```text Run Security Check ``` Required canonical actions: ```text run_security_check ``` --- ## 11. Targets Page Coverage The Targets page must include target configuration actions only: ```text Set Local Target Set Intranet Target Set Droplet Target Set Temporary Public Target ``` Required canonical actions: ```text set_target_local set_target_intranet set_target_droplet set_target_temporary_public ``` Deployment operation actions should be moved to a dedicated Deployment page when the Targets page layout becomes too large. --- ## 12. Deployment Page Coverage The Deployment page should include: ```text Deploy Local Deploy Intranet Deploy Droplet Check Droplet Agent Copy Capsule to Droplet Start Droplet Instance ``` Required canonical actions: ```text deploy_local deploy_intranet deploy_droplet check_droplet_agent copy_capsule_to_droplet start_droplet_instance ``` If `/ui/deployment` is introduced, update the route contract and tests accordingly. The Deployment page must keep Droplet operation controls explicit and visible for required public fields: ```text instance_id droplet_name droplet_host droplet_user ssh_key_path ssh_port remote_kx_root remote_capsule_dir domain confirmed ``` The `check_droplet_agent` form must not render `capsule_file`, including as a hidden input. The following actions require `capsule_file` or `capsule_path`: ```text deploy_droplet copy_capsule_to_droplet start_droplet_instance ``` --- ## 13. Safety Gating ### 13.1 Start button Start must be disabled when: ```text state in importing, verifying, starting, stopping, updating, rolling_back, security_blocked security_status = FAIL_BLOCKING ``` Start may be enabled when: ```text state in created, ready, stopped, degraded security_status in PASS, WARN, UNKNOWN ``` If `security_status = UNKNOWN`, clicking Start must run Security Gate first or require explicit confirmation. --- ### 13.2 Public exposure If: ```text network_profile = public_temporary ``` then: ```text target_mode = temporary_public exposure_mode = temporary_tunnel public_mode_expires_at is required confirmed = true ``` If: ```text network_profile = public_vps ``` then: ```text target_mode = droplet exposure_mode = public domain is required droplet_host is required confirmed = true ``` Public exposure must never be the default. --- ### 13.3 Destructive actions These actions require confirmation: ```text stop_instance restore_backup restore_backup_new rollback_instance disable_public_mode set_target_temporary_public set_target_droplet deploy_droplet start_droplet_instance ``` --- ### 13.4 Rollback If: ```text restore_data = true ``` then: ```text backup_id is required ``` --- ### 13.5 Droplet deployment Droplet deployment must be blocked unless: ```text target_mode = droplet network_profile = public_vps exposure_mode = public droplet_host is set droplet_user is set ssh_key_path exists remote_kx_root is set remote_capsule_dir is set remote_capsule_dir is under remote_kx_root domain is set confirmed = true ``` Droplet deployment must not inherit intranet defaults from the standard private payload builder. This submitted payload must never reach dispatch uncorrected: ```json { "action": "copy_capsule_to_droplet", "target_mode": "intranet", "network_profile": "intranet_private", "exposure_mode": "private" } ``` Validated output for that action must become: ```json { "action": "copy_capsule_to_droplet", "target_mode": "droplet", "network_profile": "public_vps", "exposure_mode": "public", "confirmed": true } ``` with required Droplet fields present. --- ## 14. Canonical Labels Use these exact user-facing labels: ```text Check Manager Check Agent Select Source Folder Select Output Folder Build Capsule Rebuild Capsule Verify Capsule Import Capsule List Capsules View Capsule Create Instance Update Instance Start Instance Stop Instance Restart Instance Instance Status View Logs Instance Health Open Instance Rollback Create Backup List Backups Verify Backup Restore Backup Restore Backup New Test Restore Backup Run Security Check Set Network Profile Disable Public Mode Set Local Target Set Intranet Target Set Droplet Target Set Temporary Public Target Deploy Local Deploy Intranet Deploy Droplet Check Droplet Agent Copy Capsule to Droplet Start Droplet Instance Open Manager Docs Open Agent Docs ``` --- ## 15. Required Tests Create or update: ```text tests/test_manager_ui_action_coverage.py tests/test_manager_ui_routes.py tests/test_manager_ui_forms.py tests/test_fastapi_ui_page_split.py tests/test_manager_ui_target_modes.py tests/test_ui_form_targets.py tests/test_ui_page_targets.py ``` If a dedicated Deployment page is introduced, also create or update: ```text tests/test_ui_page_deployment.py ``` --- ## 16. Required Action Coverage Tests Required action coverage tests: ```text test_all_uiactions_have_labels test_all_uiactions_have_route_or_link test_all_post_action_routes_start_with_ui_actions test_all_required_actions_exist test_no_extra_unmapped_actions_exist test_build_capsule_action_exists test_rebuild_capsule_action_exists test_restart_instance_action_exists test_instance_status_action_exists test_list_backups_action_exists test_test_restore_backup_action_exists test_check_manager_action_exists test_check_agent_action_exists test_open_docs_actions_exist test_target_actions_exist test_droplet_actions_exist test_deploy_actions_exist test_action_payloads_use_canonical_network_profiles test_action_payloads_use_canonical_exposure_modes test_action_payloads_use_canonical_docker_services test_public_temporary_requires_expiration test_public_vps_requires_confirmation test_rollback_restore_data_requires_backup_id test_droplet_deploy_requires_host_user_key_remote_root test_command_fallback_uses_shell_false test_fastapi_ui_register_exists test_streamlit_is_not_required_for_fastapi_ui_import ``` --- ## 17. Required Droplet Regression Tests Required Droplet regression tests: ```text test_targets_page_copy_capsule_to_droplet_form_uses_droplet_payload test_targets_page_droplet_operation_forms_do_not_submit_intranet_payload test_targets_page_droplet_operation_forms_keep_required_public_fields_visible test_droplet_payload_forces_public_vps_without_intranet_defaults test_droplet_action_payload_validation_forces_canonical_values test_droplet_payload_does_not_invent_domain_from_host test_droplet_validation_rejects_missing_domain test_droplet_capsule_required_actions_require_capsule_file test_check_droplet_agent_does_not_require_capsule_file test_droplet_operation_actions_force_canonical_public_vps_values ``` --- ## 18. Required Page Layout Regression Tests Required page layout tests: ```text test_targets_page_renders_target_configuration_only test_deployment_page_renders_deploy_actions test_deployment_page_renders_droplet_operations test_check_droplet_agent_form_has_no_capsule_file_input test_droplet_operation_forms_keep_public_fields_visible test_droplet_operation_forms_do_not_submit_intranet_payload ``` If Deployment actions remain on the Targets page temporarily, tests must still prove: ```text Droplet operation required fields are visible. check_droplet_agent does not submit capsule_file. Droplet operation forms do not submit intranet payloads. The page remains usable without hidden stale private target defaults. ``` --- ## 19. Required Commands Run: ```powershell uv run python -m compileall kx_manager/ui kx_manager/services tests uv run pytest -q ``` Expected result: ```text pytest passes ``` Current known-good baseline: ```text 613 passed ``` --- ## 20. Acceptance Criteria The GUI action coverage is complete when: ```text All required UiAction values exist. Required GUI action count is 41. Every UiAction has a label. Every non-browser UiAction maps to a POST route. Every browser-only UiAction maps to a link. Every action route is registered by kx_manager/ui/app.py. Every action validates canonical values. No GUI button exists without a mapped action. No mapped action lacks a GUI button. Local target mode is represented. Intranet target mode is represented. Temporary public target mode is represented. Droplet target mode is represented. Deployment operations are represented. Droplet operations never submit intranet payloads. Droplet domain is required and is not silently invented from IP/host. check_droplet_agent does not require or submit capsule_file. pytest passes. ``` The GUI is considered usable instead of commands when an operator can do this in browser: ```text Check Manager Check Agent Select Konnaxion source folder Select capsule output folder Build Capsule Verify Capsule Import Capsule Create Instance Update Instance Start Instance View Status View Health Run Security Check View Logs Create Backup Stop Instance Rollback or Restore when needed Deploy Local Deploy Intranet Deploy Droplet Check Droplet Agent Copy Capsule to Droplet Start Droplet Instance ``` without typing CLI commands. --- ## 21. Final Rule Every GUI action must be traceable through this chain: ```text button/label -> UiAction -> form model -> action route or browser link -> action dispatcher -> Manager service / client / route -> Agent endpoint / Builder service / Deploy service / CLI fallback -> normalized GuiActionResult -> rendered result panel ``` If any link in that chain is missing, the action is incomplete. Droplet actions have one extra invariant: ```text button/form -> Droplet payload builder -> target_mode=droplet -> network_profile=public_vps -> exposure_mode=public -> confirmed=true -> required Droplet fields -> validated action payload -> dispatch ``` Droplet actions must never inherit the private/intranet default payload. --- ## 22. Page Split Recommendation The preferred layout is: ```text /ui/targets target configuration only /ui/deployment deploy and Droplet operation actions ``` The route contract must be updated if `/ui/deployment` is added. The page split is accepted when: ```text Targets page is readable. Deployment actions are grouped separately. All required action buttons still exist. All action route tests pass. All form validation tests pass. No action coverage is lost. ``` ================================================================================================ FILE: docs/DOC-18_Konnaxion_GUI_Target_Modes.md AUTHORITY: reference CONTENT_ROLE: knowledge CONTENT_SHA256: 9642b502be6f219df0aba432029b49def5d029151630ad9cb67d8189c87bec19 CONTENT_BYTES: 29493 ================================================================================================ doc_id: DOC-18 title: Konnaxion Capsule Manager GUI Target Modes Contract project: Konnaxion app_version: v14 param_version: kx-param-2026.04.30 status: technical-contract owner: Konnaxion last_updated: 2026-05-03 depends_on: - DOC-16_Konnaxion_Manager_GUI_Technical_Contract.md - DOC-17_Konnaxion_GUI_Action_Coverage_Contract.md - DOC-17A_Konnaxion_GUI_Action_Payload_Contract.md - DOC-19_Konnaxion_GUI_Page_Split_Droplet_Payload_Contract.md --- # DOC-18 — Konnaxion Capsule Manager GUI Target Modes Contract ## 1. Purpose This document defines the GUI target modes used by the Konnaxion Capsule Manager. Target modes answer this operator question: ```text Where do I want this capsule to run? ```` The GUI must support: ```text local same-machine development private intranet deployment temporary public demo exposure remote Droplet/VPS deployment ``` Target mode selection must drive: ```text network_profile exposure_mode runtime root capsule output path deployment flow required form fields safety gates confirmation requirements Agent transport mode public host/domain propagation runtime env generation Traefik routing generation ``` The GUI must not treat target mode as a cosmetic label. It must enforce the correct canonical profile, exposure mode, deployment rules, host rules, and Agent transport. --- ## 2. Target Mode Values `kx_manager/services/targets.py` must own target-mode validation. Canonical target mode values: ```text local intranet temporary_public droplet ``` Recommended enum: ```python class TargetMode(StrEnum): LOCAL = "local" INTRANET = "intranet" TEMPORARY_PUBLIC = "temporary_public" DROPLET = "droplet" ``` Do not use alternate values such as: ```text dev demo lan_private vps server production cloud public_server ``` Those may be display labels, not stored values. --- ## 3. Target Mode Matrix | Target mode | Network profile | Exposure mode | Public mode | Runtime location | Agent transport | Purpose | | ------------------ | ------------------ | ------------------ | ----------------- | ------------------- | --------------- | ---------------------------------------- | | `local` | `local_only` | `private` | no | local machine | local HTTP | Same-machine development and maintenance | | `intranet` | `intranet_private` | `private` or `lan` | no | local/intranet host | local HTTP | Private LAN/internal use | | `temporary_public` | `public_temporary` | `temporary_tunnel` | yes, time-limited | local/intranet host | local HTTP | Short-lived public demo | | `droplet` | `public_vps` | `public` | yes, explicit | remote VPS/Droplet | SSH-local Agent | Public remote deployment | Default target mode: ```text intranet ``` Default profile/exposure: ```text network_profile = intranet_private exposure_mode = private ``` --- ## 4. Canonical Target Variables The GUI must use these variables consistently. | Variable | Meaning | | ------------------------ | ----------------------------------------------------- | | `KX_TARGET_MODE` | `local`, `intranet`, `temporary_public`, or `droplet` | | `KX_TARGET_PROFILE` | Canonical `NetworkProfile` value | | `KX_TARGET_EXPOSURE` | Canonical `ExposureMode` value | | `KX_TARGET_NAME` | Human-readable target name | | `KX_TARGET_HOST` | Target host/IP/domain where applicable | | `KX_TARGET_RUNTIME_ROOT` | Runtime root on the selected target | | `KX_TARGET_CAPSULE_DIR` | Capsule folder on selected target | | `KX_TARGET_INSTANCE_ID` | Instance ID to create/update/start | | `KX_TARGET_PUBLIC_URL` | Public URL when applicable | | `KX_TARGET_PRIVATE_URL` | Private/local URL when applicable | For public target modes, the GUI must resolve one canonical public host. Canonical public host precedence: ```text domain droplet_domain public_host host droplet_host ``` The Manager may store `domain`, but Agent network APIs must receive the canonical value as: ```text host ``` The Manager must not send `domain` to `/v1/network/set-profile` unless the Agent schema explicitly supports it. --- ## 5. Local Target ### 5.1 Purpose Local target is for same-machine development and maintenance. It must never expose Konnaxion to LAN, VPN, tunnel, or public traffic. ### 5.2 Required values ```text target_mode = local network_profile = local_only exposure_mode = private public_mode_enabled = false public_mode_expires_at = null ``` ### 5.3 Required paths Windows development defaults: ```text KX_ROOT = C:\mycode\Konnaxion\runtime KX_CAPSULE_OUTPUT_DIR = C:\mycode\Konnaxion\runtime\capsules ``` Canonical runtime layout: ```text runtime/ capsules/ instances/ backups/ shared/ ``` ### 5.4 Required GUI fields ```text Konnaxion source folder Capsule output folder Instance ID Capsule ID Capsule version ``` ### 5.5 Allowed GUI actions ```text build_capsule rebuild_capsule verify_capsule import_capsule create_instance update_instance start_instance stop_instance restart_instance instance_status view_health view_logs run_security_check create_backup restore_backup rollback_instance deploy_local ``` ### 5.6 Forbidden in local target ```text public_vps public_temporary temporary_tunnel public exposure droplet SSH fields domain requirement remote_agent_url SSH-local transport ``` --- ## 6. Intranet Target ### 6.1 Purpose Intranet target is for private LAN/internal use. It may be reachable from other machines on the same trusted network only if the selected exposure mode is `lan`. ### 6.2 Required values Default intranet: ```text target_mode = intranet network_profile = intranet_private exposure_mode = private public_mode_enabled = false public_mode_expires_at = null ``` Optional LAN exposure: ```text target_mode = intranet network_profile = intranet_private exposure_mode = lan public_mode_enabled = false public_mode_expires_at = null ``` ### 6.3 Required GUI fields ```text Konnaxion source folder Capsule output folder Instance ID Capsule ID Capsule version Private host/domain ``` Example private hosts: ```text konnaxion.local konnaxion.lan 192.168.1.50 ``` ### 6.4 Allowed GUI actions ```text build_capsule rebuild_capsule verify_capsule import_capsule create_instance update_instance set_network_profile start_instance stop_instance restart_instance instance_status view_health view_logs run_security_check create_backup restore_backup rollback_instance deploy_intranet ``` ### 6.5 Forbidden in intranet target ```text public_vps public_temporary without changing target mode temporary_tunnel public exposure droplet SSH fields remote_agent_url SSH-local transport ``` ### 6.6 Safety rule Internal services must never be directly exposed. Only the intended public/private entrypoint may be reachable. Forbidden direct service exposure: ```text frontend-next django-api postgres redis celeryworker celerybeat flower media-nginx kx-agent ``` --- ## 7. Temporary Public Target ### 7.1 Purpose Temporary public target is for short-lived demos or support access. It must have an expiration. It must never be default. ### 7.2 Required values ```text target_mode = temporary_public network_profile = public_temporary exposure_mode = temporary_tunnel public_mode_enabled = true public_mode_expires_at = required ``` ### 7.3 Required GUI fields ```text Konnaxion source folder Capsule output folder Instance ID Capsule ID Capsule version Generated or configured public host Public mode expiration Confirmation checkbox ``` ### 7.4 Required expiration `public_mode_expires_at` must be an ISO-8601 datetime. Example: ```text 2026-04-30T22:00:00Z ``` The GUI must reject temporary public target if expiration is missing. ### 7.5 Allowed GUI actions ```text build_capsule rebuild_capsule verify_capsule import_capsule create_instance update_instance set_network_profile disable_public_mode start_instance stop_instance restart_instance instance_status view_health view_logs run_security_check create_backup rollback_instance set_target_temporary_public ``` ### 7.6 Required warnings The GUI must show: ```text Temporary public exposure is enabled. An expiration is required. Internal services remain private. Disable public mode when the demo is complete. ``` ### 7.7 Safety gates Before applying this target: ```text public_mode_expires_at must be present exposure_mode must be temporary_tunnel network_profile must be public_temporary confirmation must be accepted Security Gate must run before start ``` --- ## 8. Droplet Target ### 8.1 Purpose Droplet target is for remote VPS deployment. It uses the canonical public VPS network profile. The Droplet Agent should remain private on the Droplet loopback interface: ```text 127.0.0.1:8765 ``` The Manager must reach the private Agent through SSH-local curl: ```text Manager on Windows -> ssh root@droplet_host -> curl http://127.0.0.1:8765/v1/... on the Droplet ``` The GUI must not require a temporary SSH tunnel for Droplet deployment. ### 8.2 Required values ```text target_mode = droplet network_profile = public_vps exposure_mode = public public_mode_enabled = true public_mode_expires_at = null remote_kx_root = /opt/konnaxion ``` ### 8.3 Required GUI fields ```text Droplet name Droplet host/IP SSH user SSH key path Remote KX_ROOT Remote capsule directory Domain Instance ID Capsule file Confirmation checkbox ``` Recommended defaults: ```text droplet_user = root remote_kx_root = /opt/konnaxion remote_capsule_dir = /opt/konnaxion/capsules ssh_port = 22 remote_agent_url = blank ``` ### 8.4 Optional GUI fields ```text Remote Agent URL SSH port Known hosts file Email for TLS Firewall profile ``` `Remote Agent URL` is optional and should normally be blank. Blank, loopback, stale tunnel, or mismatched Agent URLs must resolve to SSH-local transport. Examples that must use SSH-local transport in Droplet mode: ```text empty remote_agent_url http://127.0.0.1:18765/v1 http://localhost:18765/v1 http://203.0.113.10:8765/v1 remote_agent_url host does not match selected droplet_host ``` A direct `remote_agent_url` may be used only when it is explicitly configured, non-loopback, and points to the selected Droplet host. ### 8.5 Required Droplet variables | Variable | Example | | ------------------------ | ------------------------------- | | `KX_DROPLET_NAME` | `konnaxion-prod-01` | | `KX_DROPLET_HOST` | `203.0.113.10` | | `KX_DROPLET_USER` | `root` | | `KX_DROPLET_SSH_KEY` | `C:\Users\user\.ssh\id_ed25519` | | `KX_DROPLET_KX_ROOT` | `/opt/konnaxion` | | `KX_DROPLET_CAPSULE_DIR` | `/opt/konnaxion/capsules` | | `KX_DROPLET_DOMAIN` | `app.example.com` | | `KX_DROPLET_AGENT_URL` | blank by default | ### 8.6 Canonical Droplet public host For Droplet mode, the Manager must resolve: ```text canonical_public_host = domain or droplet_domain or public_host or droplet_host ``` The Agent `/v1/network/set-profile` request must receive: ```json { "instance_id": "demo-001", "network_profile": "public_vps", "exposure_mode": "public", "host": "app.example.com", "public_mode_enabled": true, "public_mode_expires_at": null } ``` The Manager must not send this to the Agent network endpoint: ```json { "domain": "app.example.com" } ``` unless the Agent schema explicitly supports `domain`. ### 8.7 Required generated runtime values For Droplet/public VPS runtime, the Agent must generate or update: ```text KX_HOST= KX_NETWORK_PROFILE=public_vps KX_EXPOSURE_MODE=public KX_PUBLIC_MODE_ENABLED=true ``` Django env must include: ```text DJANGO_ALLOWED_HOSTS=127.0.0.1,localhost,,django-api,kx--django-api DJANGO_CSRF_TRUSTED_ORIGINS=https://,http:// ``` Frontend env must include: ```text NEXT_PUBLIC_API_BASE=https:///api NEXT_PUBLIC_BACKEND_BASE=https:// ``` The generated public VPS runtime must not leave these values set to loopback: ```text KX_HOST=127.0.0.1 DJANGO_ALLOWED_HOSTS=127.0.0.1 only NEXT_PUBLIC_API_BASE=https://127.0.0.1/api NEXT_PUBLIC_BACKEND_BASE=https://127.0.0.1 Traefik Host(`127.0.0.1`) ``` ### 8.8 Traefik routing contract Droplet/public VPS runtime must route through Traefik on ports 80 and 443 only. The runtime may use Traefik file provider or labels, but file provider is preferred because it does not require mounting the Docker socket. Preferred Traefik dynamic config: ```yaml http: routers: kx-frontend: rule: "Host(`app.example.com`) && PathPrefix(`/`)" entryPoints: - websecure tls: {} service: kx-frontend priority: 1 kx-api: rule: "Host(`app.example.com`) && PathPrefix(`/api/`)" entryPoints: - websecure tls: {} service: kx-api priority: 100 kx-admin: rule: "Host(`app.example.com`) && PathPrefix(`/admin/`)" entryPoints: - websecure tls: {} service: kx-api priority: 100 services: kx-frontend: loadBalancer: servers: - url: "http://kx-demo-001-frontend-next:3000" kx-api: loadBalancer: servers: - url: "http://kx-demo-001-django-api:5000" ``` The generated Traefik runtime must not depend on Docker labels unless the Docker provider is configured and allowed. The generated Traefik runtime must not mount: ```text /var/run/docker.sock /run/docker.sock ``` unless explicitly approved by the Security Gate. ### 8.9 Healthcheck contract Django healthchecks must not depend on `wget`, `curl`, public DNS, Host header, or `/api/health/`. Required robust Django healthcheck: ```text python -c "import socket; sock=socket.create_connection(('127.0.0.1',5000),5); sock.close()" ``` Forbidden Django healthcheck fragments: ```text wget curl /api/health/ "api/health" Host header dependency ``` `media-nginx` must not use `wget` unless the selected image includes it. If no reliable built-in probe exists, either use an available tool or omit the healthcheck for stock `nginx:stable`. ### 8.10 Frontend runtime contract The frontend image/runtime must not require network access at container start. Forbidden runtime command: ```text pnpm start corepack ``` Required runtime behavior: ```text node node_modules/next/dist/bin/next start -H 0.0.0.0 -p 3000 ``` The frontend runtime image must include: ```text package.json node_modules .next public next.config.* env.mjs ``` ### 8.11 Capsule image archive contract Droplet deployments must not rely on images already existing on the VPS. A deployable `.kxcap` must include required image archives: ```text images/frontend-next.oci.tar images/django-api.oci.tar images/traefik.oci.tar images/media-nginx.oci.tar ``` Builder verification must fail if: ```text images/ contains only README.json required images/*.oci.tar are missing required image archives are not listed in checksums.txt manifest references image archives that are missing ``` The GUI must not show “Capsule verified” as success if the capsule cannot start on a clean Droplet because required runtime images are absent. ### 8.12 Allowed GUI actions ```text build_capsule rebuild_capsule verify_capsule copy_capsule_to_droplet check_droplet_agent import_capsule create_instance update_instance set_network_profile start_droplet_instance instance_status view_health view_logs run_security_check create_backup rollback_instance deploy_droplet ``` ### 8.13 Droplet deploy flow Droplet deployment must follow this order: ```text validate target config build capsule locally if requested verify capsule locally, including required image archives copy capsule to remote capsule directory ensure remote runtime directories exist check private Droplet Agent through SSH-local curl probe Agent contract/capabilities when available import capsule remotely through SSH-local Agent API create or update remote instance through SSH-local Agent API set public_vps profile through SSH-local Agent API run Security Gate through SSH-local Agent API start remote instance through SSH-local Agent API check remote health show public URL ``` ### 8.14 Droplet safety gates Droplet deployment must be blocked unless: ```text droplet_host is set droplet_user is set ssh_key_path exists remote_kx_root is set remote_capsule_dir is under remote_kx_root domain is set network_profile = public_vps exposure_mode = public confirmation is accepted capsule verifies successfully capsule includes required image archives ``` ### 8.15 Forbidden Droplet behavior ```text password embedded in command shell=True with untrusted input arbitrary remote command text from the GUI copying capsule outside remote capsule dir using non-canonical network profile using public exposure without confirmation exposing internal service ports directly requiring a temporary SSH tunnel for normal Droplet deploy calling http://127.0.0.1:18765/v1 from Manager as if it were the Droplet binding the Agent publicly on 0.0.0.0:8765 using Docker socket mounts for Traefik routing by default silently falling back to 127.0.0.1 for public_vps host config ``` --- ## 9. Target Configuration Model Create in: ```text kx_manager/services/targets.py ``` Recommended models: ```python from __future__ import annotations from dataclasses import dataclass from enum import StrEnum from pathlib import Path from kx_shared.konnaxion_constants import ExposureMode, NetworkProfile class TargetMode(StrEnum): LOCAL = "local" INTRANET = "intranet" TEMPORARY_PUBLIC = "temporary_public" DROPLET = "droplet" @dataclass(frozen=True, slots=True) class TargetConfig: target_mode: TargetMode network_profile: NetworkProfile exposure_mode: ExposureMode instance_id: str runtime_root: str capsule_dir: str host: str | None = None public_mode_expires_at: str | None = None confirmed: bool = False @dataclass(frozen=True, slots=True) class DropletTargetConfig(TargetConfig): droplet_name: str = "" droplet_host: str = "" droplet_user: str = "root" ssh_key_path: Path | None = None remote_kx_root: str = "/opt/konnaxion" remote_capsule_dir: str = "/opt/konnaxion/capsules" domain: str = "" remote_agent_url: str | None = None ssh_port: int = 22 ``` --- ## 10. Target Validation Rules Required validation function: ```python def validate_target_config(config: TargetConfig) -> None: ... ``` Validation rules: ```text target_mode must be canonical network_profile must match target_mode exposure_mode must be allowed for network_profile temporary_public requires public_mode_expires_at temporary_public requires confirmation public_vps requires confirmation droplet requires host, user, ssh key, remote root, remote capsule dir, and domain remote capsule dir must be under remote root local/intranet must not include droplet SSH fields public_vps must not use 127.0.0.1 as canonical host remote_agent_url blank/loopback/stale values must resolve to SSH-local transport ``` Profile mapping: ```python TARGET_PROFILE_MAP = { TargetMode.LOCAL: NetworkProfile.LOCAL_ONLY, TargetMode.INTRANET: NetworkProfile.INTRANET_PRIVATE, TargetMode.TEMPORARY_PUBLIC: NetworkProfile.PUBLIC_TEMPORARY, TargetMode.DROPLET: NetworkProfile.PUBLIC_VPS, } ``` Exposure mapping: ```python TARGET_DEFAULT_EXPOSURE_MAP = { TargetMode.LOCAL: ExposureMode.PRIVATE, TargetMode.INTRANET: ExposureMode.PRIVATE, TargetMode.TEMPORARY_PUBLIC: ExposureMode.TEMPORARY_TUNNEL, TargetMode.DROPLET: ExposureMode.PUBLIC, } ``` --- ## 11. GUI Form Contract `kx_manager/ui/forms.py` must expose forms for target modes. Required forms: ```text TargetModeForm LocalTargetForm IntranetTargetForm TemporaryPublicTargetForm DropletTargetForm DeployLocalForm DeployIntranetForm DeployDropletForm ``` ### 11.1 LocalTargetForm Fields: ```text target_mode instance_id runtime_root capsule_output_dir source_dir ``` ### 11.2 IntranetTargetForm Fields: ```text target_mode instance_id runtime_root capsule_output_dir source_dir host exposure_mode ``` Allowed exposure modes: ```text private lan ``` ### 11.3 TemporaryPublicTargetForm Fields: ```text target_mode instance_id runtime_root capsule_output_dir source_dir public_host public_mode_expires_at confirmed ``` Required: ```text public_mode_expires_at confirmed = true ``` ### 11.4 DropletTargetForm Fields: ```text target_mode instance_id source_dir capsule_file droplet_name droplet_host droplet_user ssh_key_path ssh_port remote_kx_root remote_capsule_dir domain remote_agent_url confirmed ``` Required: ```text droplet_host droplet_user ssh_key_path remote_kx_root remote_capsule_dir domain confirmed = true ``` Droplet form normalization: ```text domain -> canonical public host remote_agent_url blank/loopback/mismatched -> SSH-local Agent transport ``` The UI should display `remote_agent_url` as advanced/optional. --- ## 12. Target Page UI Contract `GET /ui/targets` must render: ```text Target mode selector Local target card Intranet target card Temporary public target card Droplet target card Current target summary Validation messages Deploy buttons Agent transport summary Public host summary ``` Required buttons: ```text Set Local Target Set Intranet Target Set Temporary Public Target Set Droplet Target Deploy Local Deploy Intranet Deploy Droplet Check Droplet Agent Copy Capsule to Droplet Start Droplet Instance ``` For Droplet target, the UI must show: ```text Agent transport: ssh Agent health URL: http://127.0.0.1:8765/v1/health on Droplet Public URL: https:// ``` when `remote_agent_url` is blank, loopback, stale, or ignored. --- ## 13. Deployment Result Contract Every deployment action must return normalized result data. ### 13.1 Local deployment result ```json { "ok": true, "action": "deploy_local", "instance_id": "demo-001", "message": "Local deployment completed.", "data": { "target_mode": "local", "network_profile": "local_only", "exposure_mode": "private", "capsule_file": "C:\\mycode\\Konnaxion\\runtime\\capsules\\konnaxion-v14-demo-2026.04.30.kxcap", "url": "https://127.0.0.1" } } ``` ### 13.2 Intranet deployment result ```json { "ok": true, "action": "deploy_intranet", "instance_id": "demo-001", "message": "Intranet deployment completed.", "data": { "target_mode": "intranet", "network_profile": "intranet_private", "exposure_mode": "private", "capsule_file": "C:\\mycode\\Konnaxion\\runtime\\capsules\\konnaxion-v14-demo-2026.04.30.kxcap", "url": "https://konnaxion.local" } } ``` ### 13.3 Temporary public deployment result ```json { "ok": true, "action": "set_target_temporary_public", "instance_id": "demo-001", "message": "Temporary public target configured.", "data": { "target_mode": "temporary_public", "network_profile": "public_temporary", "exposure_mode": "temporary_tunnel", "public_mode_expires_at": "2026-04-30T22:00:00Z", "public_url": "https://generated-demo.example" } } ``` ### 13.4 Droplet deployment result ```json { "ok": true, "action": "deploy_droplet", "instance_id": "demo-001", "message": "Droplet deployment completed.", "data": { "target_mode": "droplet", "network_profile": "public_vps", "exposure_mode": "public", "droplet_host": "203.0.113.10", "domain": "app.example.com", "host": "app.example.com", "remote_kx_root": "/opt/konnaxion", "remote_capsule_path": "/opt/konnaxion/capsules/konnaxion-v14-demo-2026.04.30.kxcap", "public_url": "https://app.example.com", "remote_agent_url": "", "agent_health_url": "http://127.0.0.1:8765/v1/health", "agent_transport": "ssh" } } ``` ### 13.5 Stale remote Agent result If the Agent rejects current schema fields such as `host`, `public_mode_enabled`, `verify`, `overwrite`, or `capsule_id`, the GUI must show a clear bootstrap-required result. ```json { "ok": false, "action": "deploy_droplet", "instance_id": "demo-001", "message": "Remote Droplet Agent is stale. Run Bootstrap Droplet Agent, then rerun Deploy Droplet.", "data": { "required_action": "bootstrap_droplet_agent", "stale_remote_agent_schema": true, "agent_transport": "ssh" } } ``` --- ## 14. Required Tests Create or update: ```text tests/test_manager_ui_forms.py tests/test_manager_ui_action_coverage.py tests/test_manager_ui_target_modes.py tests/test_compose_generation.py tests/test_capsule_verify.py ``` Required target mode tests: ```text test_target_mode_enum_values test_local_target_maps_to_local_only_private test_intranet_target_maps_to_intranet_private_private test_intranet_target_allows_lan test_temporary_public_maps_to_public_temporary_tunnel test_temporary_public_requires_expiration test_temporary_public_requires_confirmation test_droplet_maps_to_public_vps_public test_droplet_requires_host test_droplet_requires_user test_droplet_requires_ssh_key test_droplet_requires_remote_root test_droplet_requires_domain test_droplet_remote_capsule_dir_must_be_under_remote_root test_local_target_rejects_droplet_fields test_intranet_target_rejects_public_exposure test_invalid_target_mode_rejected ``` Required Droplet transport tests: ```text test_droplet_blank_remote_agent_url_uses_ssh_transport test_droplet_loopback_remote_agent_url_uses_ssh_transport test_droplet_tunnel_remote_agent_url_uses_ssh_transport test_droplet_mismatched_remote_agent_url_uses_ssh_transport test_droplet_direct_remote_agent_url_allowed_only_when_matching_host test_droplet_network_payload_sends_host_not_domain ``` Required runtime generation tests: ```text test_public_vps_requires_host test_public_vps_uses_public_host_not_loopback test_public_vps_traefik_file_provider_is_enabled test_public_vps_traefik_routes_use_public_host test_public_vps_frontend_environment_uses_public_backend_urls test_public_vps_django_environment_allows_public_host test_django_healthcheck_uses_socket_probe_not_wget_or_host_header test_media_nginx_healthcheck_does_not_require_wget test_frontend_command_does_not_require_runtime_pnpm_or_corepack ``` Required capsule verification tests: ```text test_minimal_capsule_fixture_has_required_image_archives test_build_checksum_entries_includes_required_image_archives test_verify_capsule_checksums_detects_missing_image_archive test_builder_verify_rejects_capsule_with_no_image_archives test_builder_verify_rejects_capsule_missing_one_required_image_archive test_builder_verify_rejects_image_archive_not_listed_in_checksums ``` Run: ```powershell uv run python -m compileall kx_manager/ui kx_manager/services kx_agent kx_builder tests uv run pytest -q ``` --- ## 15. Acceptance Criteria Target mode implementation is complete when: ```text The GUI exposes /ui/targets. The GUI can store/select local target. The GUI can store/select intranet target. The GUI can store/select temporary public target with expiration. The GUI can store/select droplet target with SSH/host/domain fields. Each target maps to canonical NetworkProfile and ExposureMode. Invalid target/profile/exposure combinations are rejected. Droplet deploy cannot run without required fields. Droplet deploy uses SSH-local Agent transport by default. Temporary public mode cannot run without expiration. public_vps runtime uses the public host, not 127.0.0.1. public_vps runtime generates correct Django allowed hosts. public_vps runtime generates correct frontend public backend URLs. public_vps runtime generates correct Traefik Host rules. Django healthcheck does not depend on wget/curl/public Host header. Capsule verification fails when required images/*.oci.tar are missing. pytest passes. ``` The GUI target modes are production-safe when: ```text No target mode executes arbitrary commands. No target mode exposes internal service ports. Public modes require explicit confirmation. Temporary public mode has expiration. Droplet mode uses validated host/user/key/root/capsule path/domain. Droplet mode keeps the Agent private by default. Droplet mode does not require temporary tunnels. All deployment results are normalized and rendered safely. ``` --- ## 16. Final Rule Target mode must be the single source of deployment intent. The GUI must never allow this drift: ```text target_mode = intranet network_profile = public_vps exposure_mode = public ``` or: ```text target_mode = droplet network_profile = intranet_private exposure_mode = private ``` or: ```text target_mode = droplet network_profile = public_vps exposure_mode = public KX_HOST = 127.0.0.1 ``` or: ```text target_mode = droplet Agent transport = http to 127.0.0.1:18765 on Manager ``` The selected target mode must determine the allowed profile, exposure options, public host propagation, Agent transport, runtime env, routing, and verification requirements. ================================================================================================ FILE: docs/DOC-19_Konnaxion_GUI_Page_Split_Droplet_Payload_Contract.md AUTHORITY: reference CONTENT_ROLE: knowledge CONTENT_SHA256: 3dbe5aa0d419acfc607555dcae509dcd4e0d5b002f6b172828ad68016add457f CONTENT_BYTES: 21458 ================================================================================================ # Konnaxion Manager GUI Shared Variable Contract Use this as the shared variable contract across parallel branches. Keep these names exact so `static.py`, `page_views.py`, `page_parts/*`, `page_forms.py`, `form_targets.py`, `actions.py`, and tests line up. ## 1. Canonical page split contract Every page-part module should export one renderer with this signature: ```python from collections.abc import Mapping from typing import Any def render(context: Mapping[str, Any]) -> str: ... ```` `page_views.py` imports those renderers and wires them into `PAGE_VIEWS`. ```python from collections.abc import Callable, Mapping from typing import Any PageBuilder = Callable[[Mapping[str, Any]], str] ``` No page-part file should call `html_response(...)`. Only `page_views.py` may wrap page content in `html_response(...)`. Deployment actions are split out of the Targets page and rendered by: ```text kx_manager/ui/page_parts/deploy.py ``` ## 2. Canonical route variables Use these routes in `static.py` and `page_views.py`. ```python UI_BASE_PATH = "/ui" UI_PAGE_ROUTES: tuple[str, ...] = ( "/ui", "/ui/capsules", "/ui/instances", "/ui/security", "/ui/network", "/ui/backups", "/ui/restore", "/ui/logs", "/ui/health", "/ui/settings", "/ui/targets", "/ui/deploy", "/ui/about", ) PAGE_ROUTES: tuple[str, ...] = UI_PAGE_ROUTES ``` Use this page map shape in `page_views.py`: ```python PAGE_VIEWS: dict[str, PageView] = { "/ui": PageView("/ui", "Dashboard", "...", dashboard.render), "/ui/capsules": PageView("/ui/capsules", "Capsules", "...", capsules.render), "/ui/instances": PageView("/ui/instances", "Instances", "...", instances.render), "/ui/security": PageView("/ui/security", "Security", "...", security.render), "/ui/network": PageView("/ui/network", "Network", "...", network.render), "/ui/backups": PageView("/ui/backups", "Backups", "...", backups.render), "/ui/restore": PageView("/ui/restore", "Restore", "...", restore.render), "/ui/logs": PageView("/ui/logs", "Logs", "...", logs.render), "/ui/health": PageView("/ui/health", "Health", "...", health.render), "/ui/settings": PageView("/ui/settings", "Settings", "...", settings.render), "/ui/targets": PageView("/ui/targets", "Targets", "...", targets.render), "/ui/deploy": PageView("/ui/deploy", "Deploy", "...", deploy.render), "/ui/about": PageView("/ui/about", "About", "...", about.render), } ``` Navigation must include: ```text /ui/deploy ``` ## 3. Canonical default variables Put these in: ```text kx_manager/ui/page_parts/common.py ``` ```python DEFAULT_PUBLIC_EXPIRATION = "2026-04-30T22:00:00Z" DEFAULT_PRIVATE_HOST = "konnaxion.local" DEFAULT_DROPLET_NAME = "konnaxion-droplet" DEFAULT_DROPLET_HOST = "" DEFAULT_DROPLET_USER = "konnaxion" DEFAULT_SSH_KEY_PATH = "" DEFAULT_SSH_PORT = 22 DEFAULT_REMOTE_KX_ROOT = "/opt/konnaxion" DEFAULT_REMOTE_CAPSULE_DIR = "/opt/konnaxion/capsules" DEFAULT_DROPLET_DOMAIN = "" DEFAULT_REMOTE_AGENT_URL = "" ``` Do not hardcode a real IP as a default. Let it come from submitted/context values. Do not silently invent `domain` from `droplet_host`. `domain` must be submitted explicitly by the UI form or caller. `remote_agent_url` defaults to blank. Blank means Droplet Agent uses SSH-local transport: ```text Manager on Windows -> ssh droplet_user@droplet_host -> curl http://127.0.0.1:8765/v1/... on the Droplet ``` Do not default Droplet Agent transport to a local forwarded tunnel URL such as: ```text http://127.0.0.1:18765/v1 ``` ## 4. Canonical payload builders These should live in: ```text kx_manager/ui/page_parts/common.py ``` ### 4.1 Default payload ```python from collections.abc import Mapping from typing import Any def default_payload(context: Mapping[str, Any]) -> dict[str, Any]: return { "instance_id": context.get("instance_id", DEFAULT_INSTANCE_ID), "capsule_id": context.get("capsule_id", DEFAULT_CAPSULE_ID), "capsule_version": context.get("capsule_version", DEFAULT_CAPSULE_VERSION), "capsule_file": context.get("capsule_file", DEFAULT_CAPSULE_FILE), "capsule_path": context.get( "capsule_path", context.get("capsule_file", DEFAULT_CAPSULE_FILE), ), "source_dir": context.get("source_dir", DEFAULT_SOURCE_DIR), "capsule_output_dir": context.get( "capsule_output_dir", DEFAULT_CAPSULE_OUTPUT_DIR, ), "target_mode": context.get("target_mode", "intranet"), "network_profile": context.get("network_profile", "intranet_private"), "exposure_mode": context.get("exposure_mode", "private"), "runtime_root": context.get("runtime_root", DEFAULT_RUNTIME_ROOT), "capsule_dir": context.get( "capsule_dir", f"{DEFAULT_RUNTIME_ROOT}\\capsules", ), "host": context.get("host", DEFAULT_PRIVATE_HOST), "domain": context.get("domain", ""), "runtime_url": context.get("runtime_url", "http://127.0.0.1"), } ``` ### 4.2 Local payload ```python def local_payload(context: Mapping[str, Any]) -> dict[str, Any]: payload = default_payload(context) payload.update( { "target_mode": "local", "network_profile": "local_only", "exposure_mode": "private", "host": "127.0.0.1", "domain": "", "confirmed": "true", } ) return payload ``` ### 4.3 Intranet payload ```python def intranet_payload(context: Mapping[str, Any]) -> dict[str, Any]: payload = default_payload(context) payload.update( { "target_mode": "intranet", "network_profile": "intranet_private", "exposure_mode": context.get("exposure_mode", "private"), "host": context.get("host", DEFAULT_PRIVATE_HOST), "domain": "", "confirmed": "true", } ) return payload ``` ### 4.4 Dedicated Droplet payload ```python def droplet_payload(context: Mapping[str, Any]) -> dict[str, Any]: capsule_file = ( context.get("capsule_file") or context.get("capsule_path") or DEFAULT_CAPSULE_FILE ) droplet_host = ( context.get("droplet_host") or context.get("host") or context.get("target_host") or DEFAULT_DROPLET_HOST ) domain = ( context.get("domain") or context.get("droplet_domain") or DEFAULT_DROPLET_DOMAIN ) remote_kx_root = ( context.get("remote_kx_root") or context.get("runtime_root") or context.get("remote_root") or context.get("droplet_kx_root") or DEFAULT_REMOTE_KX_ROOT ) remote_capsule_dir = ( context.get("remote_capsule_dir") or context.get("capsule_dir") or context.get("target_capsule_dir") or context.get("droplet_capsule_dir") or DEFAULT_REMOTE_CAPSULE_DIR ) return { "instance_id": context.get("instance_id", DEFAULT_INSTANCE_ID), "capsule_id": context.get("capsule_id", DEFAULT_CAPSULE_ID), "capsule_version": context.get("capsule_version", DEFAULT_CAPSULE_VERSION), "capsule_file": capsule_file, "capsule_path": capsule_file, "source_dir": context.get("source_dir", DEFAULT_SOURCE_DIR), "capsule_output_dir": context.get( "capsule_output_dir", DEFAULT_CAPSULE_OUTPUT_DIR, ), "target_mode": "droplet", "network_profile": "public_vps", "exposure_mode": "public", "public_mode_enabled": "true", "public_mode_expires_at": "", "droplet_name": context.get("droplet_name", DEFAULT_DROPLET_NAME), "droplet_host": droplet_host, "host": droplet_host, "droplet_user": ( context.get("droplet_user") or context.get("ssh_user") or context.get("user") or DEFAULT_DROPLET_USER ), "ssh_key_path": ( context.get("ssh_key_path") or context.get("droplet_ssh_key") or context.get("ssh_key") or DEFAULT_SSH_KEY_PATH ), "ssh_port": context.get("ssh_port", DEFAULT_SSH_PORT), "remote_kx_root": remote_kx_root, "runtime_root": remote_kx_root, "remote_capsule_dir": remote_capsule_dir, "capsule_dir": remote_capsule_dir, "domain": domain, "droplet_domain": domain, "remote_agent_url": ( context.get("remote_agent_url") or context.get("droplet_agent_url") or DEFAULT_REMOTE_AGENT_URL ), "confirmed": "true", } ``` Important: Droplet operation forms must use `droplet_payload(context)`, never `default_payload(context)`. Important: `droplet_payload(context)` may return `domain=""` when no domain was supplied. That is intentional. Validation must reject missing `domain`; the payload builder must not hide the missing value by inventing one from the IP. ## 5. Canonical Droplet action sets Use the same sets in `form_targets.py`, tests, `page_parts/targets.py`, and `page_parts/deploy.py`. ```python DROPLET_ACTIONS: frozenset[str] = frozenset( { "set_target_droplet", "deploy_droplet", "check_droplet_agent", "copy_capsule_to_droplet", "start_droplet_instance", } ) DROPLET_CAPSULE_REQUIRED_ACTIONS: frozenset[str] = frozenset( { "deploy_droplet", "copy_capsule_to_droplet", "start_droplet_instance", } ) ``` For these operation actions, force/default: ```python target_mode = "droplet" network_profile = "public_vps" exposure_mode = "public" confirmed = True ``` `set_target_droplet` must still reject missing `confirmed`. Operation actions may force confirmation because they are explicit Droplet operation forms. ## 6. Canonical target form names Use these exact form field names in the Droplet target form and operation forms: ```text target_mode network_profile exposure_mode instance_id capsule_file capsule_path droplet_name droplet_host droplet_user ssh_key_path ssh_port remote_kx_root remote_capsule_dir domain droplet_domain remote_agent_url confirmed ``` Required visible Droplet target fields: ```text instance_id droplet_name droplet_host droplet_user ssh_key_path ssh_port remote_kx_root remote_capsule_dir domain confirmed ``` Required visible Droplet operation fields when the action copies/deploys a capsule: ```text capsule_file ``` Aliases are allowed only as input aliases: ```text target_host -> droplet_host / host ssh_user -> droplet_user user -> droplet_user droplet_ssh_key -> ssh_key_path ssh_key -> ssh_key_path remote_root -> remote_kx_root droplet_kx_root -> remote_kx_root droplet_capsule_dir -> remote_capsule_dir target_capsule_dir -> capsule_dir droplet_domain -> domain droplet_agent_url -> remote_agent_url ``` ## 7. Canonical alias normalization additions In `static.py::normalize_payload_aliases(...)`, ensure these are present: ```python if data.get("droplet_host") and not data.get("host"): data["host"] = data["droplet_host"] if ( data.get("host") and not data.get("droplet_host") and data.get("target_mode") == "droplet" ): data["droplet_host"] = data["host"] if data.get("remote_kx_root") and not data.get("runtime_root"): data["runtime_root"] = data["remote_kx_root"] if ( data.get("runtime_root") and not data.get("remote_kx_root") and data.get("target_mode") == "droplet" ): data["remote_kx_root"] = data["runtime_root"] if data.get("remote_capsule_dir") and not data.get("capsule_dir"): data["capsule_dir"] = data["remote_capsule_dir"] if ( data.get("capsule_dir") and not data.get("remote_capsule_dir") and data.get("target_mode") == "droplet" ): data["remote_capsule_dir"] = data["capsule_dir"] if data.get("domain") and not data.get("droplet_domain"): data["droplet_domain"] = data["domain"] if data.get("droplet_domain") and not data.get("domain"): data["domain"] = data["droplet_domain"] if data.get("capsule_file") and not data.get("capsule_path"): data["capsule_path"] = data["capsule_file"] if data.get("capsule_path") and not data.get("capsule_file"): data["capsule_file"] = data["capsule_path"] ``` Do not add this fallback: ```python if not data.get("domain"): data["domain"] = data.get("droplet_host") or data.get("host") ``` That would bypass required-domain validation. ## 8. Canonical page-part imports Every page-part file should import shared helpers from `common.py`, not from `page_views.py`. Example: ```python from kx_manager.ui.page_parts.common import ( DEFAULT_DROPLET_DOMAIN, DEFAULT_DROPLET_HOST, DEFAULT_DROPLET_NAME, DEFAULT_DROPLET_USER, DEFAULT_REMOTE_AGENT_URL, DEFAULT_REMOTE_CAPSULE_DIR, DEFAULT_REMOTE_KX_ROOT, DEFAULT_SSH_KEY_PATH, DEFAULT_SSH_PORT, action_bar, action_form, button_form, capsule_file_field, confirmed_field, default_payload, droplet_operation_form, droplet_payload, field, instance_id_field, ) ``` Avoid underscored cross-module helpers in the new split. Use public helper names: ```text field action_form button_form action_bar default_payload droplet_payload droplet_operation_form ``` Do not use: ```text _field _action_form _button_form _action_bar _default_payload _droplet_payload _droplet_operation_form ``` ## 9. Compatibility `page_forms.py` `page_forms.py` should become a facade with this stable function: ```python from collections.abc import Mapping from typing import Any from kx_manager.ui.page_parts import render_page_body def render_page_forms(route: str, data: Mapping[str, Any] | None = None) -> str: return render_page_body(route, dict(data or {})) ``` It must not own page bodies anymore. ## 10. Target page rendering rules `page_parts/targets.py` should render only target configuration forms: ```text set_target_local set_target_intranet set_target_temporary_public set_target_droplet ``` The Droplet target form must render `domain` as required: ```python field("domain", "Domain", payload["domain"], required=True) ``` The Targets page must not render these deployment/operation actions anymore: ```text deploy_local deploy_intranet deploy_droplet check_droplet_agent copy_capsule_to_droplet start_droplet_instance ``` Those belong in: ```text page_parts/deploy.py ``` ## 11. Deploy page rendering rules `page_parts/deploy.py` should render deployment and operation actions: ```text deploy_local deploy_intranet deploy_droplet check_droplet_agent copy_capsule_to_droplet start_droplet_instance ``` For these actions, use full Droplet operation forms, not hidden-only buttons: ```text deploy_droplet check_droplet_agent copy_capsule_to_droplet start_droplet_instance ``` `deploy_droplet`, `copy_capsule_to_droplet`, and `start_droplet_instance` must include visible `capsule_file`. `check_droplet_agent` does not require `capsule_file` and must not submit `capsule_file`, even as hidden input. `deploy_local` and `deploy_intranet` may remain compact button forms, but their payloads must come from `local_payload(context)` and `intranet_payload(context)`. ## 12. Test payload alignment In tests, `action_payload(...)` must use Droplet values for all Droplet actions: ```python if action in { "set_target_droplet", "deploy_droplet", "check_droplet_agent", "copy_capsule_to_droplet", "start_droplet_instance", }: base.update( { "target_mode": "droplet", "network_profile": "public_vps", "exposure_mode": "public", "droplet_name": "ubuntu-s-1vcpu-2gb-tor1", "droplet_host": "203.0.113.10", "host": "203.0.113.10", "droplet_user": "konnaxion", "ssh_key_path": str(ssh_key_path), "ssh_port": "22", "remote_kx_root": "/opt/konnaxion", "runtime_root": "/opt/konnaxion", "remote_capsule_dir": "/opt/konnaxion/capsules", "capsule_dir": "/opt/konnaxion/capsules", "domain": "203.0.113.10.sslip.io", "droplet_domain": "203.0.113.10.sslip.io", "remote_agent_url": "", "confirmed": "true", } ) ``` Use `konnaxion` as SSH user in UI test payloads, matching the created Droplet user. Use blank `remote_agent_url` in canonical Droplet tests. Blank means private Agent over SSH-local transport. Only use a non-loopback `remote_agent_url` in tests explicitly covering direct public Agent mode. ## 13. Main invariant This must be true after the split: ```python assert droplet_payload(context)["target_mode"] == "droplet" assert droplet_payload(context)["network_profile"] == "public_vps" assert droplet_payload(context)["exposure_mode"] == "public" ``` This must never happen again: ```json { "action": "copy_capsule_to_droplet", "target_mode": "intranet" } ``` That submitted payload is the exact bug to prevent. This validation must remain true: ```python payload = droplet_payload({"droplet_host": "203.0.113.10"}) assert payload["domain"] == "" # Later validation must reject this until domain is supplied. ``` ## 14. Droplet Agent transport invariant Droplet mode must keep the Agent private by default: ```text remote_agent_url = "" agent_transport = "ssh" agent_health_url = "http://127.0.0.1:8765/v1/health" ``` Manager must execute Agent calls as: ```text ssh droplet_user@droplet_host "curl http://127.0.0.1:8765/v1/" ``` A loopback `remote_agent_url` such as this must not be treated as a direct HTTP transport: ```text http://127.0.0.1:18765/v1 http://localhost:18765/v1 http://0.0.0.0:8765/v1 ``` Those values should either be normalized to blank SSH-local mode or rejected by target validation. ## 15. Agent network payload invariant Manager must send Agent network profile payload using: ```text host ``` not: ```text domain droplet_domain public_host ``` `domain`, `droplet_domain`, and `public_host` are Manager/UI aliases only. Before calling Agent `/v1/network/set-profile`, normalize: ```python payload["host"] = payload.get("domain") or payload.get("droplet_domain") or payload.get("host") payload.pop("domain", None) payload.pop("droplet_domain", None) payload.pop("public_host", None) ``` The Agent may accept legacy aliases leniently, but the Manager should not rely on that. ## 16. Runtime public VPS invariant For `target_mode="droplet"` and `network_profile="public_vps"`, generated runtime files must contain the explicit domain/public host. Expected: ```text KX_HOST= DJANGO_ALLOWED_HOSTS=127.0.0.1,localhost,,django-api,kx--django-api NEXT_PUBLIC_API_BASE=https:///api NEXT_PUBLIC_BACKEND_BASE=https:// ``` Forbidden for public VPS: ```text KX_HOST=127.0.0.1 DJANGO_ALLOWED_HOSTS=127.0.0.1 NEXT_PUBLIC_API_BASE=https://127.0.0.1/api NEXT_PUBLIC_BACKEND_BASE=https://127.0.0.1 ``` ## 17. Traefik runtime invariant Runtime compose for public VPS must route by the public host. If Traefik uses file provider, the generated dynamic file must include: ```yaml http: routers: kx-frontend: rule: "Host(``) && PathPrefix(`/`)" entryPoints: - websecure tls: {} service: kx-frontend priority: 1 kx-api: rule: "Host(``) && PathPrefix(`/api/`)" entryPoints: - websecure tls: {} service: kx-api priority: 100 kx-admin: rule: "Host(``) && PathPrefix(`/admin/`)" entryPoints: - websecure tls: {} service: kx-api priority: 100 services: kx-frontend: loadBalancer: servers: - url: "http://kx--frontend-next:3000" kx-api: loadBalancer: servers: - url: "http://kx--django-api:5000" ``` If Traefik uses Docker labels, labels must be attached to the correct target services and `traefik.enable=true` must be present. Do not rely on labels when the runtime Traefik instance is configured only with file provider. ## 18. Healthcheck invariant Django healthcheck must not depend on tools missing from the image. Do not generate this: ```text wget -qO- http://127.0.0.1:5000/api/health/ ``` Use a Python socket check: ```text python -c "import socket; sock=socket.create_connection(('127.0.0.1',5000),5); sock.close()" ``` Do not generate malformed hybrid commands such as: ```text python -c "... sock.close()"api/health/ >/dev/null 2>&1 || exit 1 ``` ## 19. Builder/runtime image invariant A Droplet-deployable capsule must include runtime image archives. A verified capsule must not pass if it only contains: ```text images/README.json ``` The capsule must include required `.oci.tar` images or verification must fail. Required app-owned image archives: ```text images/frontend-next.oci.tar images/django-api.oci.tar ``` Any required proxy/runtime images declared as capsule-owned must also exist as image archives. The frontend runtime image must not download tooling at runtime. It must run Next.js directly: ```text node node_modules/next/dist/bin/next start -H 0.0.0.0 -p 3000 ``` The frontend runtime image must include: ```text package.json node_modules .next public next.config.* env.mjs ``` ================================================================================================ FILE: docs/DOC-20_Konnaxion_Package_Types_and_Artifact_Lifecycle.md AUTHORITY: reference CONTENT_ROLE: knowledge CONTENT_SHA256: 7f9bb8a4f2b393fb995f52a5116adbddf82f1806c6b2d2bbadacd48fbf288bbb CONTENT_BYTES: 22051 ================================================================================================ doc_id: DOC-20 title: Konnaxion Package Types and Artifact Lifecycle project: Konnaxion app_version: v14 param_version: kx-param-2026.04.30 status: draft owner: Konnaxion Architecture last_updated: 2026-05-03 depends_on: - DOC-00_Konnaxion_Canonical_Variables.md - DOC-03_Konnaxion_Capsule_Format.md - DOC-06_Konnaxion_Network_Profiles.md - DOC-07_Konnaxion_Security_Gate.md - DOC-08_Konnaxion_Runtime_Docker_Compose.md - DOC-10_Konnaxion_Builder_CLI.md --- # DOC-20 — Konnaxion Package Types and Artifact Lifecycle ## 1. Purpose This document defines the canonical package types used by Konnaxion and the lifecycle rules for creating, verifying, importing, exporting, signing, encrypting, deploying, and retiring those artifacts. Konnaxion package design separates four concerns: ```text runtime application content/data portable demo bundle backup/disaster recovery ```` The core rule is: ```text Runtime is portable. Data is portable. Secrets are local. Deployment configuration is generated on the target. ``` --- ## 2. Package Types Konnaxion uses four package classes: ```text .kxruntime Konnaxion runtime package .kxdata Konnaxion data/content package .kxportable Runtime + data all-in-one package .kxbackup Encrypted backup/disaster recovery package ``` Backward compatibility: ```text .kxcap legacy runtime capsule alias ``` `.kxcap` remains supported during migration, but new package workflows should use `.kxruntime`, `.kxdata`, and `.kxportable`. --- ## 3. Product Analogy The intended mental model is: ```text Konnaxion Runtime = reader/player Konnaxion Data Pack = film/content/database Konnaxion Portable = reader + film in one transport file Konnaxion Backup = protected disaster recovery archive ``` Equivalent analogy: ```text VLC / DVD player / console = .kxruntime movie / DVD / cartridge = .kxdata demo package = .kxportable secure backup = .kxbackup ``` --- ## 4. Responsibilities by Package Type | Package | Primary purpose | Runtime images | Database | Media | Secrets | | ------------- | --------------------------- | -------------: | -------: | ----: | -------------: | | `.kxruntime` | App/runtime reader | yes | no | no | no | | `.kxdata` | Content/database pack | no | yes | yes | no | | `.kxportable` | One-file demo/deploy bundle | yes | yes | yes | no | | `.kxbackup` | Encrypted backup/DR archive | optional | yes | yes | encrypted only | No portable package may contain unencrypted runtime secrets. --- ## 5. `.kxruntime` ## 5.1 Purpose A `.kxruntime` package contains the Konnaxion application runtime. It is the “reader” that knows how to run compatible Konnaxion data. ## 5.2 Contains ```text Django backend image Next.js frontend image runtime Docker Compose template Traefik dynamic routing template network profiles healthchecks Security Gate policies migrations runtime manifest checksums signature metadata ``` ## 5.3 Must Not Contain ```text customer database uploaded media Django secret key Postgres password Redis password Agent token SSH private keys TLS private keys OAuth client secrets external API keys target-machine env files ``` ## 5.4 Canonical Layout ```text manifest.yaml runtime/ docker-compose.capsule.yml traefik-dynamic.template.yml healthchecks/ profiles/ policies/ migrations/ images/ django-api.oci.tar frontend-next.oci.tar metadata/ build.json source-inventory.json checksums.txt signature.sig ``` Optional image archives: ```text images/media-nginx.oci.tar images/traefik.oci.tar images/postgres.oci.tar images/redis.oci.tar ``` If optional images are not packaged, the manifest must declare whether target-side pulling is allowed. --- ## 6. `.kxdata` ## 6.1 Purpose A `.kxdata` package contains portable Konnaxion content. It is the “film” that a Konnaxion runtime can load. ## 6.2 Contains ```text Postgres dump media archive schema version required app version required param version source instance metadata export metadata checksums signature optional encryption metadata ``` ## 6.3 Must Not Contain ```text runtime Docker images Django secret key Postgres password Redis password Agent token SSH private keys TLS private keys target-machine env files Docker Compose runtime state Traefik generated runtime state ``` ## 6.4 Canonical Layout ```text manifest.yaml db/ postgres.dump media/ media.tar.zst metadata/ source-instance.json schema-version.json app-version-required.json export.json checksums.txt signature.sig ``` Optional encrypted layout: ```text manifest.yaml payload.enc metadata/ encryption.json checksums.txt signature.sig ``` --- ## 7. `.kxportable` ## 7.1 Purpose A `.kxportable` package is a single-file bundle containing a runtime package and a data pack. It is intended for: ```text client demos offline transfer one-file VPS deployment sales demos training packs archival demo snapshots ``` ## 7.2 Contains ```text one .kxruntime one .kxdata bundle manifest checksums signature optional encryption metadata ``` ## 7.3 Must Not Contain ```text generated runtime secrets target machine env files SSH private keys TLS private keys Agent tokens ``` ## 7.4 Canonical Layout ```text manifest.yaml runtime/ konnaxion-reader-v14.kxruntime data/ demo-citoyen-2026.kxdata metadata/ bundle.json checksums.txt signature.sig ``` --- ## 8. `.kxbackup` ## 8.1 Purpose A `.kxbackup` package is for disaster recovery and controlled restoration. It may contain sensitive application data and must be encrypted. ## 8.2 Contains ```text database dump media archive backup metadata restore metadata checksums signature encryption metadata ``` ## 8.3 May Contain Depending on backup policy, it may contain more operational state than `.kxdata`, but machine secrets should still be excluded by default. ## 8.4 Required Encryption `.kxbackup` must be encrypted when it contains: ```text personal data private organizational data business data tokens stored inside application database tables sensitive media files ``` --- ## 9. Manifest Kind Values Every package must declare its kind. Allowed values: ```text konnaxion-runtime konnaxion-data-pack konnaxion-portable-bundle konnaxion-backup ``` Examples: ```yaml kind: konnaxion-runtime ``` ```yaml kind: konnaxion-data-pack ``` ```yaml kind: konnaxion-portable-bundle ``` ```yaml kind: konnaxion-backup ``` --- ## 10. Runtime Manifest Contract Example: ```yaml kind: konnaxion-runtime format_version: 1 runtime_id: konnaxion-reader-v14 app_version: v14 param_version: kx-param-2026.04.30 supported_schema_versions: - 2026.04.30 - 2026.05.02 images: django-api: archive: images/django-api.oci.tar image: konnaxion/django-api:v14 required: true frontend-next: archive: images/frontend-next.oci.tar image: konnaxion/frontend-next:v14 required: true runtime: compose_template: runtime/docker-compose.capsule.yml traefik_template: runtime/traefik-dynamic.template.yml profiles_dir: runtime/profiles policies_dir: runtime/policies healthchecks_dir: runtime/healthchecks security: signed: true checksums: checksums.txt contains_runtime_secrets: false ``` --- ## 11. Data Pack Manifest Contract Example: ```yaml kind: konnaxion-data-pack format_version: 1 data_pack_id: demo-citoyen-2026 title: Demo Citoyen 2026 app_version_required: v14 param_version_required: kx-param-2026.04.30 schema_version: 2026.05.02 database: engine: postgres dump: db/postgres.dump format: pg_dump_custom media: archive: media/media.tar.zst format: tar.zst security: signed: true encrypted: false checksums: checksums.txt contains_runtime_secrets: false contains_user_data: true export: exported_at: 2026-05-03T00:00:00Z source_instance_id: demo-001 anonymized: false ``` --- ## 12. Portable Bundle Manifest Contract Example: ```yaml kind: konnaxion-portable-bundle format_version: 1 bundle_id: demo-citoyen-2026-v14 runtime: file: runtime/konnaxion-reader-v14.kxruntime app_version: v14 param_version: kx-param-2026.04.30 data: file: data/demo-citoyen-2026.kxdata schema_version: 2026.05.02 security: signed: true encrypted: false checksums: checksums.txt contains_runtime_secrets: false first_boot_generates_secrets: true ``` --- ## 13. Backup Manifest Contract Example: ```yaml kind: konnaxion-backup format_version: 1 backup_id: demo-001-2026-05-03 source: instance_id: demo-001 app_version: v14 param_version: kx-param-2026.04.30 schema_version: 2026.05.02 database: engine: postgres dump: db/postgres.dump format: pg_dump_custom media: archive: media/media.tar.zst security: signed: true encrypted: true encryption_required: true checksums: checksums.txt contains_runtime_secrets: false contains_sensitive_data: true backup: created_at: 2026-05-03T00:00:00Z mode: disaster_recovery ``` --- ## 14. Secret Rules ## 14.1 Core Rule Runtime secrets are generated on the target machine. They must not be packaged into: ```text .kxruntime .kxdata .kxportable ``` ## 14.2 Forbidden Secret Files Packages must fail verification if they contain: ```text .env *.env agent.env django.env postgres.env redis.env runtime.env id_rsa id_ed25519 *.pem *.key *.p12 *.pfx ``` Allowed exceptions: ```text env-templates/*.template public keys public certificate chain files example env files with placeholders ``` ## 14.3 Forbidden Secret Content Packages must fail verification if unencrypted package contents contain: ```text DJANGO_SECRET_KEY= POSTGRES_PASSWORD= REDIS_PASSWORD= DATABASE_URL=postgres:// KX_AGENT_TOKEN= PRIVATE KEY BEGIN OPENSSH PRIVATE KEY BEGIN RSA PRIVATE KEY BEGIN EC PRIVATE KEY ``` `.kxbackup` may contain sensitive application data only when encrypted. --- ## 15. Signature Rules All package types must support signatures. Signature proves: ```text publisher identity integrity authenticity ``` Signature does not provide confidentiality. Every signed package must include: ```text checksums.txt signature.sig ``` Verification order: ```text read manifest verify checksums verify signature verify package policy verify package compatibility ``` --- ## 16. Encryption Rules Encryption is: ```text optional for .kxruntime recommended for .kxdata optional for .kxportable demo use required for sensitive .kxbackup ``` Supported encryption modes: ```text password-derived key recipient public key age X25519 ``` Encryption metadata example: ```yaml encryption: enabled: true method: age-x25519 recipients: - age1example... ``` Import must fail if encrypted package cannot be decrypted. --- ## 17. Compatibility Rules ## 17.1 Required Version Fields Every `.kxdata` must declare: ```text app_version_required param_version_required schema_version ``` Every `.kxruntime` must declare: ```text app_version param_version supported_schema_versions ``` ## 17.2 Compatibility Check A runtime may load a data pack only if: ```text runtime.app_version satisfies data.app_version_required runtime.param_version satisfies data.param_version_required runtime.supported_schema_versions includes data.schema_version ``` ## 17.3 Incompatible Import If incompatible, the Agent must block import and return: ```yaml ok: false reason: incompatible_runtime required_app_version: current_app_version: required_schema_version: supported_schema_versions: [...] ``` ## 17.4 Migration If a migration path exists, the Agent may offer: ```text import and migrate ``` Migration of production data must require explicit operator confirmation. --- ## 18. Artifact Lifecycle All Konnaxion packages follow this lifecycle: ```text build/export verify sign optionally encrypt store transfer import validate compatibility generate target secrets render target runtime start audit retire ``` Package state values: ```text created verified signed encrypted imported active deprecated revoked archived deleted ``` --- ## 19. Build Lifecycle ## 19.1 Runtime Build ```text 1. Build app images. 2. Export app images as OCI archives. 3. Write runtime templates. 4. Write runtime manifest. 5. Write checksums. 6. Sign package. 7. Return .kxruntime. ``` ## 19.2 Data Pack Export ```text 1. Validate source instance. 2. Enter export-safe mode. 3. Run pg_dump. 4. Archive media. 5. Write manifest. 6. Write metadata. 7. Write checksums. 8. Sign package. 9. Optionally encrypt. 10. Return .kxdata. ``` ## 19.3 Portable Build ```text 1. Verify runtime package. 2. Verify data pack. 3. Check compatibility. 4. Write bundle manifest. 5. Write checksums. 6. Sign bundle. 7. Optionally encrypt. 8. Return .kxportable. ``` ## 19.4 Backup Build ```text 1. Validate source instance. 2. Run backup preflight. 3. Dump database. 4. Archive media. 5. Write backup metadata. 6. Encrypt package. 7. Sign package. 8. Store backup. 9. Verify restoreability. ``` --- ## 20. Import Lifecycle ## 20.1 Runtime Import ```text 1. Verify package. 2. Verify no runtime secrets are present. 3. Load Docker images. 4. Store runtime metadata. 5. Register runtime version. ``` ## 20.2 Data Pack Import ```text 1. Verify package. 2. Decrypt if required. 3. Verify no runtime secrets are present. 4. Check runtime compatibility. 5. Create target instance. 6. Generate target secrets. 7. Start database services. 8. Restore Postgres dump. 9. Restore media. 10. Run migrations if required. 11. Render runtime config. 12. Start app services. 13. Run Security Gate. ``` ## 20.3 Portable Import ```text 1. Verify bundle. 2. Extract runtime package. 3. Extract data pack. 4. Verify runtime package. 5. Verify data pack. 6. Check compatibility. 7. Import runtime. 8. Import data pack. 9. Generate target secrets. 10. Render target runtime. 11. Start instance. 12. Run Security Gate. ``` ## 20.4 Backup Restore ```text 1. Verify backup. 2. Decrypt backup. 3. Verify restore policy. 4. Create restore target. 5. Generate target secrets unless policy says otherwise. 6. Restore DB and media. 7. Run migrations if approved. 8. Start in safe network profile. 9. Run Security Gate. ``` --- ## 21. Target Machine State Imported packages and instances must be stored under canonical paths: ```text /opt/konnaxion/ runtimes/ / data-packs/ imported/ portable/ imported/ backups/ instances/ / env/ state/ media/ postgres/ redis/ logs/ ``` Runtime secrets are stored only under instance or Agent env directories. --- ## 22. Manager Responsibilities The Konnaxion Capsule Manager is responsible for: ```text building packages verifying packages signing packages encrypting packages when requested uploading packages to target calling Agent APIs displaying package status showing import/export diagnostics coordinating deployments ``` The Manager must not: ```text directly edit target Docker runtime manually directly open firewalls embed secrets in packages require a local tunnel for private Droplet Agent access ``` For Droplet/VPS deployments, the Manager must use SSH-local Agent transport when the Agent listens on target loopback. --- ## 23. Agent Responsibilities The Konnaxion Agent is responsible for: ```text verifying uploaded packages importing runtime packages loading Docker images importing data packs restoring DB/media generating target secrets rendering Docker Compose runtime files rendering Traefik dynamic config starting/stopping instances running Security Gate writing audit logs ``` The Agent must reject packages that: ```text contain runtime secrets fail signature/checksum verification declare unsupported versions attempt to expose forbidden ports attempt to mount Docker socket attempt to run unknown services ``` --- ## 24. Builder Responsibilities The Konnaxion Builder is responsible for: ```text building runtime packages exporting runtime images as OCI tar archives building data packs from source instances building portable bundles writing manifests writing checksums signing packages verifying package completeness ``` The Builder must fail if: ```text required runtime images are missing manifest references missing files checksums are incomplete signature is required but no signing key is available forbidden secret files are included ``` --- ## 25. Security Gate Integration Security Gate must validate package and runtime behavior. Package-level checks: ```text manifest_valid checksums_valid signature_valid package_type_valid version_compatible no_forbidden_secret_files no_forbidden_secret_markers required_payloads_present ``` Runtime-level checks: ```text required_images_present compose_template_valid traefik_file_provider_required docker_socket_not_required dangerous_ports_blocked ``` Data-level checks: ```text db_dump_present db_dump_restoreable media_archive_valid schema_version_declared app_version_required_declared ``` Instance-level checks: ```text secrets_present secrets_not_default runtime_env_host_matches_profile traefik_dynamic_host_matches_profile frontend_public_env_matches_profile postgres_not_public redis_not_public no_privileged_containers no_host_network ``` --- ## 26. Audit Events Every package operation must write an audit event. Event types: ```text package_built package_verified package_signed package_encrypted package_uploaded package_imported data_pack_exported data_pack_imported portable_bundle_built portable_bundle_imported backup_created backup_restored package_rejected package_deleted ``` Canonical audit fields: ```yaml event_type: package_imported package_type: konnaxion-data-pack package_id: demo-citoyen-2026 instance_id: demo-001 actor: timestamp: result: PASS details: {} ``` --- ## 27. CLI Contract Builder commands: ```bash kx-builder runtime build \ --source-dir \ --output konnaxion-reader-v14.kxruntime kx-builder data-pack build \ --instance-id demo-001 \ --output demo-citoyen-2026.kxdata kx-builder portable build \ --runtime konnaxion-reader-v14.kxruntime \ --data demo-citoyen-2026.kxdata \ --output demo-citoyen-2026-v14.kxportable ``` Agent/CLI commands: ```bash kx runtime import konnaxion-reader-v14.kxruntime kx data-pack import demo-citoyen-2026.kxdata \ --instance-id demo-001 kx portable import demo-citoyen-2026-v14.kxportable \ --instance-id demo-001 \ --network-profile public_vps \ --host 138.197.174.76.sslip.io ``` Backup commands: ```bash kx backup create demo-001 \ --output demo-001-2026-05-03.kxbackup \ --encrypt kx backup restore demo-001-2026-05-03.kxbackup \ --instance-id restored-demo-001 ``` --- ## 28. GUI Contract The Manager GUI must expose a package module. Recommended page: ```text Packages ``` Tabs: ```text Runtime Data Packs Portable Bundles Backups ``` Runtime actions: ```text Build Runtime Verify Runtime Deploy Runtime Update Runtime ``` Data Pack actions: ```text Export Data Pack Verify Data Pack Import Data Pack Create Instance from Data Pack Anonymize Data Pack Encrypt Data Pack ``` Portable Bundle actions: ```text Build Portable Bundle Verify Portable Bundle Import Portable Bundle Deploy Portable Bundle to Droplet/VPS Split Bundle into Runtime + Data ``` Backup actions: ```text Create Backup Verify Backup Restore Backup Test Restore ``` --- ## 29. Backward Compatibility `.kxcap` compatibility rules: ```text .kxcap with runtime images -> treat as legacy .kxruntime .kxcap without runtime images -> fail strict verify or warn in legacy mode .kxcap with DB/media content -> split into .kxruntime + .kxdata or convert to .kxportable ``` Deprecation warning: ```text .kxcap is a legacy runtime capsule extension. Use .kxruntime for new runtime builds. ``` Strict mode should eventually require: ```text required images/*.oci.tar are present manifest declares package kind no runtime secrets are present ``` --- ## 30. Acceptance Criteria `.kxruntime` acceptance: ```text build succeeds required images are present verify fails when required images are missing no runtime secrets are present Agent can import runtime Agent can docker load app images ``` `.kxdata` acceptance: ```text export succeeds database dump exists media archive exists or no-media marker exists manifest declares app/schema compatibility verify fails if runtime secrets are detected Agent can import into new instance ``` `.kxportable` acceptance: ```text contains one valid runtime contains one valid data pack runtime/data compatibility passes import generates fresh secrets import starts app without manual Docker build ``` `.kxbackup` acceptance: ```text encrypted when sensitive verify succeeds test restore succeeds restore starts in safe network profile ``` --- ## 31. Final Rule Konnaxion package design must preserve this separation: ```text .kxruntime = the reader .kxdata = the content .kxportable = reader + content .kxbackup = protected recovery archive ``` No portable package may depend on source-machine runtime secrets. No target deployment may depend on source-machine host configuration. The Agent must generate secrets and deployment-specific configuration on the target machine. --- ## 21. Installed artifact and composition boundary (2026-09-08) Package type and artifact identity are separate dimensions. A runtime/data package may carry an installable artifact descriptor, but Capsule does not own product UX composition. Canonical installable artifact contract, registry, discovery and removal rules are defined in: ```text DOC-23_Capsule_Installed_Artifact_and_Composition_Contract.md ``` New runtime capsules built from source include `artifact.yaml`. Product-owned integrated UI manifests remain separate under `contributions/` and are only admitted/discovered by Capsule; they are composed by kOA Spaces. ================================================================================================ FILE: docs/DOC-22_SecurityDiag_Integration.md AUTHORITY: reference CONTENT_ROLE: knowledge CONTENT_SHA256: b316997c059e375f58e2ace0cef1d9b32e7320c71c6a524d1f6f0eaaa3f4b084 CONTENT_BYTES: 2566 ================================================================================================ --- doc_id: DOC-22 title: SecurityDiag Integration Contract status: implementation-ready last_updated: 2026-09-05 --- # DOC-22 — SecurityDiag Integration Contract ## Purpose SecurityDiag and Capsule Manager are complementary security layers. They MUST NOT duplicate privileged enforcement. ```text SecurityDiag = independent diagnostic / evidence / release qualification Capsule Manager = orchestration and operator UX Konnaxion Agent = privileged enforcement boundary ``` ## Canonical evidence exchange After every Agent Security Gate execution, the Agent writes a non-secret evidence snapshot to: ```text /opt/konnaxion/instances//state/security-gate.json ``` The evidence includes only gate status, per-check status, blocking failures, warnings, runtime-evidence metadata, capsule id and compose path. It MUST NOT include runtime secret values. SecurityDiag reads this file over its read-only SSH audit channel and cross-checks it against independent host evidence. A Capsule Manager `UNKNOWN`, `SKIPPED`, or `FAIL_BLOCKING` result is release-blocking when Capsule integration is required. ## No assumed security state The Agent Security Gate MUST NOT inject `True` for signature verification, image checksums, firewall state, backup readiness, admin privacy, PostgreSQL exposure, or Redis exposure. Those values must be derived from artifact/runtime/host evidence. ## Capsule signature trust Structural verification rejects malformed or placeholder `signature.sig`. Startup qualification additionally performs cryptographic verification against the trusted public key configured by `KX_CAPSULE_PUBLIC_KEY_FILE`, defaulting to: ```text /opt/konnaxion/agent/keys/capsule-signing-public.pem ``` A missing key or failed signature is blocking. ## Image trust For Agent startup, the signed capsule manifest is the source of truth for allowed runtime image references. A canonical service name does not by itself authorize an arbitrary image. ## Agent boundary SecurityDiag expects the Agent to: - bind only to loopback or a Unix socket; - use bearer-token authentication; - run as `kx-agent`; - keep its token and audit files restricted; - expose only allowlisted operations; - keep normal users out of the Docker group; - persist append-only audit evidence. ## Combined release decision ```text SecurityDiag technical gate PASS + Capsule Manager Security Gate PASS/WARN with no blocking/UNKNOWN checks + external exposure PASS + restore evidence PASS + incident-recovery attestations complete = SECURITY QUALIFIED FOR RELEASE ``` ================================================================================================ FILE: docs/DOC-23_Capsule_Installed_Artifact_and_Composition_Contract.md AUTHORITY: reference CONTENT_ROLE: knowledge CONTENT_SHA256: 6386d267daa718d048f333023d6dd4e4a210afd020727d39be60ef09783d9f63 CONTENT_BYTES: 9253 ================================================================================================ doc_id: DOC-23 title: Capsule Installed Artifact and Composition Contract project: Konnaxion Capsule app_version: v14 param_version: kx-param-2026.04.30 status: canonical owner: Konnaxion Architecture last_updated: 2026-09-08 depends_on: - DOC-02_Konnaxion_Capsule_Architecture.md - DOC-03_Konnaxion_Capsule_Format.md - DOC-20_Konnaxion_Package_Types_and_Artifact_Lifecycle.md --- # DOC-23 — Capsule Installed Artifact and Composition Contract ## 1. Architectural rule > Capsule manages the presence and lifecycle of an artifact; a product remains > owner of its product experience; a composition host may compose public > contributions; none becomes a business-runtime prerequisite for the others. Capsule answers: ```text What is installed? Which version? Which artifact class? Which public entrypoints exist? Which public integration manifest is available? Which dependencies/capabilities are required or provided? What is the lifecycle/readiness state? ``` Capsule does **not** answer: ```text How should an Orgo Case page render? Which Konnaxion navigation item belongs in which menu? How should a Koali inspector behave? How should Spaces compose product presentation state? ``` ## 2. Boundary ```text CAPSULE │ install / remove / discover / launch │ ┌─────────────┼─────────────┐ │ │ │ Orgo Konnaxion Kristal │ │ │ standalone standalone standalone │ │ │ └────── public contributions ──────┘ │ kOA Spaces integrated composition ``` ## 3. Artifact classes The canonical descriptor uses `artifact.kind`: ```text library product composition_host ``` Examples: ```text library koali-ui, interface-contracts product orgo, konnaxion, kristal composition_host koa-spaces ``` Only `product` artifacts are candidates for a product switcher projection. Libraries and composition hosts remain discoverable in the full registry. ## 4. Descriptor contract A source tree may provide: ```text capsule-artifact.yaml ``` The Builder validates it and packages the canonical public descriptor as: ```text artifact.yaml ``` Schema: ```text kx-artifact-descriptor/v1 ``` Example: ```yaml schema_version: kx-artifact-descriptor/v1 artifact: id: orgo version: 1.4.0 kind: product lifecycle: removable: true standalone: true runtime: backend: entrypoint: /orgo/api healthcheck: /orgo/health ui: standalone: enabled: true entrypoint: /orgo integrated: enabled: true manifest: koali-integration.yaml contract: koali-ui/v1 dependencies: required: - id: koali-ui version: ">=1" interface: public optional_integrations: - product: konnaxion capability: konnaxion.case-link capabilities: provides: - orgo.cases requires: - koali-ui-contract ``` The Builder copies a declared integrated manifest into `contributions/` and rewrites `artifact.yaml` to the packaged relative path. Capsule verifies file presence/trust/contract admission but does not parse product UX semantics. If `capsule-artifact.yaml` is absent, the current Konnaxion Builder emits a backward-compatible Konnaxion `product` descriptor automatically. ## 5. Runtime manifest versus artifact descriptor These are deliberately separate contracts: ```text manifest.yaml runtime topology, images, profiles, package/runtime metadata artifact.yaml installable identity, lifecycle, public entrypoints, dependencies, capabilities, public contribution reference contributions/* product-owned integration manifests ``` Do not move product routes/navigation/commands/inspectors into `manifest.yaml`. ## 6. Standalone and integrated independence The registry tracks separate projections: ```text runtime.status standalone_ui.status integration.status functional ``` An unavailable or rejected integration contribution does not make an otherwise working product unhealthy. Example: ```text runtime available standalone_ui available integration rejected functional true ``` Spaces may be absent and the product remains standalone-capable. ## 7. Installed registry The Agent owns the persistent registry: ```text /shared/registry/installed-artifacts.json ``` Schema: ```text kx-installed-artifact-registry/v1 ``` Every mutation increments: ```text generation ``` A composition host can refresh only when the generation changes. Manager/Agent discovery projections include: ```text GET /v1/artifacts GET /v1/artifacts?products_only=true GET /v1/artifacts?composition_candidates_only=true GET /v1/artifacts/{artifact_id} GET /v1/artifacts/{artifact_id}/integration-manifest ``` The ProductSwitcher must derive candidates from the installed registry. For an integrated ProductSwitcher, the canonical projection is `composition_candidates_only=true`: it contains only installed `product` artifacts whose public integration contribution was admitted. `products_only=true` remains the broader inventory of installed products. Neither projection may hard-code Orgo/Konnaxion/Kristal. ## 8. Integration admission A product can remain installed and functional while its integrated contribution is rejected. Admission requires at least: ```text artifact kind is product integrated UI enabled capsule verified/trusted manifest path stays inside extracted capsule manifest exists integration contract is allowlisted/supported ``` Default supported contract identifiers are currently: ```text koali-ui/v1 module-interface-manifest/v1 ``` They can be configured with: ```text KX_ALLOWED_INTEGRATION_CONTRACTS ``` Capsule does not turn the admitted manifest into navigation. Spaces does. ## 9. Dependency rules Required artifact dependencies must already be installed before registration. Required capabilities must have an installed provider. Private cross-artifact dependencies are forbidden in the descriptor: ```yaml # forbidden required: - id: konnaxion interface: private ``` Use a public artifact contract/capability instead: ```yaml required: - id: koali-ui interface: public ``` Optional product integration belongs under `optional_integrations` and does not make either product a prerequisite of the other. Code-level private imports between repositories/packages remain a CI/static architecture responsibility in addition to this manifest-level validation. ## 10. Removal contract Canonical CLI: ```text kx artifact remove ``` Removal is fail-closed. The Agent blocks removal when: ```text artifact.lifecycle.removable = false another installed artifact requires it its exclusively-provided capability is still required an active instance still references its capsule ``` When guards pass: ```text remove capsule/extracted runtime artifact remove registry entry increment registry generation preserve instance/business data by default ``` Optional integrations do not block removal. This implements the architectural sequence while refusing to destroy active runtime/data implicitly. Stopping/detaching active instances remains an explicit lifecycle action before artifact removal. ## 11. kOA Spaces contract Spaces consumes the registry and public manifests only: ```text Capsule installed registry ↓ composition_candidates_only projection ↓ public admitted contribution manifest ↓ kOA Spaces composition ↓ ProductSwitcher / surfaces / navigation / commands / inspectors ``` Spaces must not require a compile-time array such as: ```ts const products = [orgo, konnaxion, kristal] ``` ## 12. Mandatory invariants/tests ```text install Orgo alone → standalone remains functional install Orgo + Spaces → Orgo public contribution discoverable remove Spaces → Orgo remains functional install Orgo + Konnaxion + Spaces → both products discoverable remove Orgo → Konnaxion unaffected → Spaces can refresh from registry generation → Orgo disappears from products projection remove Konnaxion → Orgo unaffected missing optional integration → product remains functional private cross-artifact dependency → descriptor rejected shared koali-ui library → allowed → absent from products_only projection unknown/untrusted UI manifest → integration rejected → product remains functional required dependent exists → removal blocked ``` ## 13. Final ownership table ```text CAPSULE installation/removal/version/dependency resolution/runtime entrypoints/ standalone entrypoints/installed registry/manifest discovery/readiness projection kOA SPACES integrated frame/ProductSwitcher/surface selection/navigation composition/ commands/inspectors/presentation state PRODUCT business behavior/product routes/product surfaces/product commands/ product inspectors/product standalone app KOALI-UI shared shell primitives/design system/navigation primitives/context header/ command palette/inspector mechanics/responsive behavior ``` ================================================================================================ FILE: README.md AUTHORITY: reference CONTENT_ROLE: knowledge CONTENT_SHA256: 67da322c4a3e085d1385613d9d801238b01583d33aadbf654dcbb52eb204246f CONTENT_BYTES: 17256 ================================================================================================ # Konnaxion Capsule Manager Konnaxion Capsule Manager packages Konnaxion v14 into signed, portable `.kxcap` capsules and runs them through a local Manager, privileged Agent, Docker Compose runtime, private-by-default network profiles, Security Gate checks, backups, restores, rollback, GUI workflows, first-time Droplet bootstrap, and the canonical `kx` CLI. ## Purpose The project turns Konnaxion into a portable, secure, plug-and-play appliance system. ```text Konnaxion Source → Konnaxion Capsule Builder → Signed .kxcap Capsule → Konnaxion Capsule Manager → Konnaxion Agent → Docker Compose Runtime → Konnaxion Instance ```` ## Core Components * `kx_shared/` — canonical constants, paths, states, profiles, services, and validation * `kx_agent/` — privileged local service for runtime, security, network, backup, restore, rollback, and capsule verification actions * `kx_manager/` — user-facing API and local GUI layer * `kx_builder/` — capsule build, manifest, checksum, image, and signature tooling * `kx_cli/` — canonical `kx` operator/developer CLI * `profiles/` — approved network profiles * `policies/` — runtime and Security Gate policies * `templates/` — Docker Compose and environment templates * `docs/` — technical contracts and operator documentation * `tests/` — contract and integration tests ## Default Runtime Konnaxion runs through Docker Compose with canonical service names only: ```text traefik frontend-next django-api postgres redis celeryworker celerybeat flower media-nginx kx-agent ``` Forbidden aliases include `backend`, `api`, `frontend`, `db`, `cache`, `worker`, `scheduler`, and `agent`. ## Security Model Konnaxion is private by default. The system enforces: * signed capsules only * checksum-verified capsule contents * extracted capsule and archive verification * generated secrets on install * deny-by-default networking * Traefik-only HTTP/S entrypoint * no public PostgreSQL or Redis * no public Konnaxion Agent API * no Docker socket mounts * no privileged app containers * no host networking for app containers * canonical network profiles only * blocking Security Gate checks before startup * backup safety checks before restore and rollback workflows The Konnaxion Agent must bind to a local interface by default: ```text 127.0.0.1:8765 ``` Public VPS users must reach the runtime through Traefik on HTTP/S only: ```text 80 443 ``` Do not expose the Agent API port `8765` publicly. ## Network Profiles Supported canonical profiles: ```text local_only intranet_private private_tunnel public_temporary public_vps offline ``` Supported exposure modes: ```text private lan vpn temporary_tunnel public ``` Default: ```text network_profile = intranet_private exposure_mode = private ``` Temporary public mode requires an expiration. Public VPS mode requires explicit operator confirmation. ## GUI The Manager GUI is intended to run locally at: ```text http://127.0.0.1:8714/ui ``` The GUI contract covers: ```text select Konnaxion source folder select capsule output folder build capsule rebuild capsule verify capsule import capsule list capsules view capsule create instance update instance start instance stop instance restart instance view status view health view logs open instance run Security Gate set network profile disable public mode create backup list backups verify backup restore backup restore backup into new instance test restore backup rollback instance set local target set intranet target set temporary public target set droplet target deploy local deploy intranet deploy droplet bootstrap droplet agent check droplet agent copy capsule to droplet start droplet instance open Manager docs open Agent docs ``` The GUI must remain local-only by default and must not execute arbitrary shell commands. Every GUI action must map to an allowlisted Manager route, Agent API endpoint, Builder service, Deploy service, Target service, first-time Droplet bootstrap service, or browser-link result. Browser-only actions are rendered as links, not POST routes: ```text open_instance open_manager_docs open_agent_docs ``` GUI technical contracts: ```text docs/DOC-16_Konnaxion_Manager_GUI_Technical_Contract.md docs/DOC-17_Konnaxion_GUI_Action_Coverage_Contract.md docs/DOC-17A_Konnaxion_GUI_Action_Payload_Contract.md docs/DOC-18_Konnaxion_GUI_Target_Modes.md docs/DOC-19_Konnaxion_GUI_Page_Split_Droplet_Payload_Contract.md ``` ## GUI Theme and Assets Shared GUI styling is owned by: ```text kx_manager/ui/styles.py ``` Current primary theme color: ```text #1e6864 ``` The HTML rendering layer imports shared CSS from `kx_manager.ui.styles`, keeping `kx_manager/ui/render.py` focused on safe HTML rendering helpers. Optional local GUI assets, such as a logo, should live under: ```text kx_manager/ui/assets/ ``` Recommended logo path: ```text kx_manager/ui/assets/konnaxion-logo.svg ``` If static assets are mounted by the Manager, the logo is served from: ```text http://127.0.0.1:8714/ui/assets/konnaxion-logo.svg ``` ## Target Modes The GUI and Manager support these target modes: ```text local intranet temporary_public droplet ``` Target mapping: | Target mode | Network profile | Exposure mode | Purpose | | ------------------ | ------------------ | ------------------ | ------------------------------- | | `local` | `local_only` | `private` | Same-machine development | | `intranet` | `intranet_private` | `private` or `lan` | Private LAN/internal deployment | | `temporary_public` | `public_temporary` | `temporary_tunnel` | Time-limited public demo | | `droplet` | `public_vps` | `public` | Remote VPS/Droplet deployment | ## Droplet Runtime Layout Canonical hardened VPS/Droplet runtime paths: ```text /opt/konnaxion /opt/konnaxion/capsules /opt/konnaxion/instances /opt/konnaxion/backups /opt/konnaxion/shared /opt/konnaxion/releases /opt/konnaxion/manager /opt/konnaxion/agent ``` Purpose: ```text /opt/konnaxion/capsules signed .kxcap files copied to the Droplet /opt/konnaxion/instances installed instance state /opt/konnaxion/backups backup artifacts and metadata /opt/konnaxion/shared shared Manager/Agent state /opt/konnaxion/releases release metadata and installed release pointers /opt/konnaxion/manager remote Manager/Agent Python project code /opt/konnaxion/agent Agent runtime/config area ``` The `.kxcap` capsule is the application artifact. It is not the installer for the Manager/Agent control plane. The remote Konnaxion Agent must exist before a Droplet can import, verify, create, update, secure, or start a Konnaxion Instance. ## First-Time Droplet Bootstrap A new or partially prepared Droplet may have Docker and `/opt/konnaxion` folders but no remote Agent. The GUI action: ```text bootstrap_droplet_agent ``` is responsible for first-time remote control-plane setup. Expected bootstrap behavior: ```text 1. SSH to the Droplet using the configured Droplet target. 2. Create the canonical /opt/konnaxion folder layout. 3. Copy or install trusted Konnaxion Capsule Manager / Agent code to /opt/konnaxion/manager. 4. Install required Python runtime tooling such as uv. 5. Install or refresh dependencies. 6. Write a localhost-only systemd service for the Konnaxion Agent. 7. Start konnaxion-agent.service. 8. Verify http://127.0.0.1:8765/v1/health from inside the Droplet. ``` The Agent must remain private: ```text KX_AGENT_HOST=127.0.0.1 KX_AGENT_PORT=8765 ``` Do not require public access to: ```text http://:8765 ``` The GUI may use SSH to verify localhost Agent health from inside the Droplet. ## Droplet GUI Workflow Use the GUI workflow in this order: ```text 1. Capsules → Build Capsule using profile public_vps 2. Capsules → Verify Capsule 3. Targets → Set Droplet Target 4. Deploy → Bootstrap Droplet Agent 5. Deploy → Check Droplet Agent 6. Deploy → Copy Capsule to Droplet 7. Deploy → Deploy Droplet 8. Deploy → Start Droplet Instance, only if Deploy Droplet did not already start it ``` `Set Droplet Target` must be done once and persisted into GUI state. The Deploy page should prefill Droplet fields from the saved target. Required Droplet target fields: ```text target_mode=droplet network_profile=public_vps exposure_mode=public instance_id droplet_name droplet_host droplet_user ssh_key_path ssh_port remote_kx_root remote_capsule_dir domain confirmed=true ``` Recommended defaults: ```text instance_id=demo-001 droplet_user=root ssh_port=22 remote_kx_root=/opt/konnaxion remote_capsule_dir=/opt/konnaxion/capsules ``` For IP-only testing, a DNS helper domain may be used explicitly, for example: ```text 2.56.97.41.sslip.io ``` The GUI must not silently invent a domain from a Droplet IP. The operator must provide the domain value. ## Canonical CLI ```bash kx capsule build kx capsule verify kx capsule import kx instance create kx instance start kx instance stop kx instance status kx instance logs kx instance backup kx instance restore kx instance restore-new kx instance update kx instance rollback kx instance health kx backup list kx backup verify kx backup test-restore kx security check kx network set-profile ``` ## Development with uv Create and install the environment: ```powershell uv venv uv pip install -e ".[dev]" ``` Run compile and tests: ```powershell uv run python -m compileall kx_shared kx_agent kx_manager kx_builder kx_cli tests uv run pytest -q ``` Current expected baseline: ```text 500 passed 0 skipped ``` ## Run the Agent ```powershell uv run kx-agent run ``` Default Agent URL: ```text http://127.0.0.1:8765 ``` Useful endpoints: ```text http://127.0.0.1:8765/docs http://127.0.0.1:8765/v1/health http://127.0.0.1:8765/v1/agent/info ``` A `404` at `/` is normal because the Agent does not define a homepage route. ## Run the Manager ```powershell uv run kx-manager --host 127.0.0.1 --port 8714 ``` Default Manager URLs: ```text http://127.0.0.1:8714 http://127.0.0.1:8714/docs http://127.0.0.1:8714/ui ``` ## Local Launcher For local development, you can use a `.bat` launcher that starts both the Agent and Manager in separate terminal windows. Recommended file name: ```text StartKonnaxionLocal.bat ``` Recommended behavior: ```text start Agent on http://127.0.0.1:8765 start Manager on http://127.0.0.1:8714 open http://127.0.0.1:8714/ui ``` ## Windows Runtime Defaults For local Windows development: ```powershell $env:KX_ROOT="C:\mycode\Konnaxion\runtime" $env:KX_SOURCE_DIR="C:\mycode\Konnaxion\Konnaxion" $env:KX_AGENT_HOST="127.0.0.1" $env:KX_AGENT_PORT="8765" $env:KX_MANAGER_HOST="127.0.0.1" $env:KX_MANAGER_PORT="8714" ``` Runtime folders: ```text C:\mycode\Konnaxion\runtime\capsules C:\mycode\Konnaxion\runtime\instances C:\mycode\Konnaxion\runtime\backups C:\mycode\Konnaxion\runtime\shared ``` Canonical appliance runtime paths remain: ```text /opt/konnaxion /opt/konnaxion/capsules /opt/konnaxion/instances /opt/konnaxion/backups /opt/konnaxion/shared /opt/konnaxion/releases /opt/konnaxion/manager /opt/konnaxion/agent ``` ## Typical Local Workflow Build and verify a demo capsule: ```powershell uv run kx-builder capsule build ` --source-dir C:\mycode\Konnaxion\Konnaxion ` --output C:\mycode\Konnaxion\runtime\capsules\konnaxion-v14-demo-2026.04.30.kxcap ` --channel demo ` --capsule-id konnaxion-v14-demo-2026.04.30 ` --version 2026.04.30-demo.1 ` --profile intranet_private ` --force uv run kx-builder capsule verify C:\mycode\Konnaxion\runtime\capsules\konnaxion-v14-demo-2026.04.30.kxcap ``` Import and run locally or on the intranet profile: ```powershell uv run kx capsule import C:\mycode\Konnaxion\runtime\capsules\konnaxion-v14-demo-2026.04.30.kxcap uv run kx instance create demo-001 uv run kx security check demo-001 uv run kx instance start demo-001 uv run kx instance status demo-001 uv run kx instance health demo-001 ``` Create and verify a backup: ```powershell uv run kx instance backup demo-001 --class manual uv run kx backup list demo-001 uv run kx backup verify uv run kx backup test-restore ``` ## Typical Droplet Workflow Build and verify a public VPS capsule: ```powershell uv run kx-builder capsule build ` --source-dir C:\mycode\Konnaxion\Konnaxion ` --output C:\mycode\Konnaxion\runtime\capsules\konnaxion-v14-demo-2026.04.30.kxcap ` --channel demo ` --capsule-id konnaxion-v14-demo-2026.04.30 ` --version 2026.04.30-demo.1 ` --profile public_vps ` --force uv run kx-builder capsule verify C:\mycode\Konnaxion\runtime\capsules\konnaxion-v14-demo-2026.04.30.kxcap ``` Then use the GUI: ```text Targets → Set Droplet Target Deploy → Bootstrap Droplet Agent Deploy → Check Droplet Agent Deploy → Copy Capsule to Droplet Deploy → Deploy Droplet ``` Do not continue to `Copy Capsule to Droplet` until `Check Droplet Agent` succeeds. Do not continue to `Deploy Droplet` until the capsule exists locally and has been copied to the Droplet. ## Droplet Diagnostics On the Droplet console, use: ```bash echo "== WHOAMI ==" whoami hostname hostname -I echo echo "== KX DIRS ==" ls -ld /opt /opt/konnaxion /opt/konnaxion/agent /opt/konnaxion/manager /opt/konnaxion/capsules /opt/konnaxion/instances /opt/konnaxion/backups /opt/konnaxion/shared 2>&1 || true echo echo "== KX PROCESSES ==" ps aux | grep -Ei 'konnaxion|kx-agent|kx-manager|uvicorn' | grep -v grep || true echo echo "== LISTENING PORTS ==" ss -ltnp | grep -E ':8765|:8714|:80|:443' || true echo echo "== LOCAL AGENT HEALTH ==" curl -i --max-time 5 http://127.0.0.1:8765/v1/health || true echo echo "== SYSTEMD KX SERVICES ==" systemctl list-units --type=service --all | grep -Ei 'konnaxion|kx' || true echo echo "== DOCKER ==" docker --version 2>&1 || true docker compose version 2>&1 || true ``` A fresh or incomplete Droplet may show: ```text /opt/konnaxion/agent missing /opt/konnaxion/manager missing /opt/konnaxion/shared missing no Konnaxion processes curl to 127.0.0.1:8765 fails ``` That means `Bootstrap Droplet Agent` must run before `Check Droplet Agent`. ## Launch Readiness Before launch or test-drive: ```powershell uv run python -m compileall kx_manager kx_agent kx_builder kx_cli kx_shared tests uv run pytest -q uv run python -c "from kx_manager.ui.server import app; print(len(app.routes)); print('server ok')" ``` Expected Manager import output: ```text server ok ``` The exact route count may change when GUI actions are added. Launch local/intranet first. Do not enable `public_temporary`, `public_vps`, or Droplet deployment until the local capsule build, verify, import, create, Security Gate, start, health, backup, and restore-test flow passes end-to-end. For Droplet launch, do not deploy until: ```text Set Droplet Target succeeds Bootstrap Droplet Agent succeeds Check Droplet Agent succeeds Copy Capsule to Droplet succeeds Deploy Droplet succeeds Security Gate passes Instance health passes Backup and restore-test pass ``` ## Target Konnaxion as a signed, portable, private-by-default capsule system deployable on: ```text Konnaxion Box local host intranet server private tunnel temporary public demo hardened VPS/Droplet ``` ## Capsule build progress and persistent logs `Build Capsule` and `Rebuild Capsule` run as asynchronous Manager jobs. The browser is redirected immediately to `/ui/build-jobs/`, which displays status, phase, a progress bar, and the live log tail. The page refreshes every two seconds while the job is active. By default, build evidence is stored under: ```text /manager/build-jobs/ .json .log .progress.json latest-job.txt ``` On the standard Windows local layout this is: ```text C:\mycode\Konnaxion\runtime\manager\build-jobs\ ``` `StartCapsuleManager.bat` creates this directory before starting the Agent and Manager. Capsule builds are serialized by default with `KX_CAPSULE_BUILD_CONCURRENCY=1` to limit RAM pressure. The value can be raised explicitly when the host has sufficient capacity. ## Installed artifact registry and composition boundary Capsule now distinguishes `library`, `product`, and `composition_host` artifacts. New builds include a public `artifact.yaml` descriptor, imported artifacts are registered under `/shared/registry/installed-artifacts.json`, and the registry exposes a generation-based discovery projection for optional composition hosts such as kOA Spaces. Canonical contract: `docs/DOC-23_Capsule_Installed_Artifact_and_Composition_Contract.md`. Public discovery/removal CLI: ```text kx artifact list kx artifact show kx artifact remove ``` Product UX contributions remain owned by each product; Capsule validates and publishes their public manifest reference but does not construct navigation, routes, commands, or inspectors. ## Host passthrough direct-filter fix v9 The Manager direct Agent payload filter for `/instances/create` preserves `host` and related runtime-host fields. This fixes local instance creation where the GUI submitted `konnaxion.local` but the Agent received no host and fell back to `127.0.0.1`.