QDG Knowledge Base Read-only viewer QWebHub
workflow

Odin Deployment

Version 3 · Add current launchers, SHA-256 deployment, shared assets, and scoped restart procedures.

Odin Deployment

Purpose

QWebHub and its sibling modules deploy to Odin through local Windows BAT launchers backed by the shared Python FTP helper. The FTP password is stored once in the Windows user environment and is never written into a repository, BAT file, wiki page, or deployment command.

One-time credential setup

Store the password for future processes with a placeholder command such as:

setx ODIN_FTP_PASSWORD "<password>"

Open a new terminal after running setx; it does not update terminals that are already open. Do not replace the placeholder in documentation or commit the real value anywhere.

The launchers map ODIN_FTP_PASSWORD to the generic helper environment, and the Python FTP helpers also read ODIN_FTP_PASSWORD directly. If it is unavailable, the helpers fall back to a secure interactive prompt.

Deployment launchers

Scope Launcher
QWebHub only QWebHub\deploy_odin.bat
QProcess only QProcess\deploy_odin.bat
QDBAdmin only AdminManagement\QDBAdmin\deploy_odin.bat
QDG KB Viewer only QDG KB Viewer\deploy_odin.bat
Gary Breeding Reports only Gary Breeding Report\deploy_odin.bat
Hub, all supported modules, then shared assets QWebHub\deploy_all_to_odin.bat

For each deployment launcher:

  • Double-clicking uploads changed files.
  • Passing --dry-run lists files without uploading.
  • Passing --apply explicitly uploads changed files.
  • Passing --apply --force uploads all selected files even when server file sizes match.

Examples:

Set-Location <QWebHub repository>
.\deploy_odin.bat --dry-run
.\deploy_odin.bat --apply --force

The QWebHub launcher includes scripts\reload_qwebhub.py. QProcess deploys its active application package and templates with local diagnostic/test exclusions. QDG KB Viewer deploys its application package, templates, static source, manage.py, and requirements.

SHA-256 deployment behaviour

QWebHub owns the deployment engine used by supported module launchers. Each remote project root has a versioned .odin-deploy-manifest.json. Upload decisions compare local SHA-256 values with that manifest rather than relying on file size or timestamps.

Uploads use 1–8 workers per project (default 4), one FTP connection per worker, and one bounded retry with a fresh connection after a transient disconnect. The manifest is published only after every planned upload succeeds. A failed file leaves the manifest unchanged, so a later run safely schedules the incomplete deployment again. deploy_all_to_odin.bat remains project-sequential and stops at the first failed project. It supplies shared non-secret FTP host and username defaults; the password remains only in ODIN_FTP_PASSWORD.

Useful read-only modes:

deploy_odin --check
deploy_odin --dry-run
deploy_odin --verify-remote

--offline-dry-run inventories local files without connecting but cannot accurately identify remote changes. --verify-remote downloads selected remote files and verifies their hashes without writing.

Shared static assets

QWebHub collects shared CSS from Global Memory/CSS and optimized 200×200 web icons from Global Assests/Icons. Larger Admin Images files are source artwork and are deliberately excluded from shared static discovery.

Collect static files and restart QWebHub

After uploading application or CSS changes, use the QWebHub button Collect static files and restart QWebHub. It sends a CSRF-protected POST to /operations/reload/, schedules a detached helper, runs manage.py collectstatic --noinput, stops if collection fails, then starts the narrowly scoped Odin task \QWebHub\Restart. That task recycles the IIS application pool currently hosting QWebHub; it does not run iisreset or give the web process unrestricted IIS privileges.

The operation is temporarily available to everyone behind Odin's site-level authentication. Restrict it to the existing administrator permission/group once QDBAdmin administrator accounts are provisioned.

Verification

  1. Open a new terminal and confirm the variable exists without printing its value:

    if ($env:ODIN_FTP_PASSWORD) { 'ODIN_FTP_PASSWORD is available' }
    
  2. Run the intended launcher with --dry-run and verify the destination and file list.

  3. Run the launcher normally or with --apply.

  4. For QWebHub, confirm /healthz/ returns successfully after the server-side restart workflow.

  5. Confirm QDG KB Viewer cards and static styling render correctly after collection/restart.

Security rules

  • Never put the password value in a BAT file, Python file, JSON configuration, Git history, prompt, log, or wiki page.
  • Keep credential-bearing local launchers ignored with exact paths or narrow patterns.
  • Before committing deployment changes, inspect every BAT and JSON configuration file for credentials and remove any tracked sensitive file from the Git index while preserving the local copy.
  • Rotate the credential if it appears in source control, command output, or another exposed location.
Updated by Codex on Aug. 20, 2026, 7:24 a.m. · Task: Document QWebHub v1.2.2 theme and deployment delivery · Commit: 0509d036b5134568451a380834937832d44bb810