Hardening and Deploying Wize Wizard: From Strategy Workbench to Production System
A practical build story covering Wize Wizard’s strategy features, CI/CD hardening, D2 architecture, Playwright QA, Docker deployment, and the production problems solved along the way.
Hardening and Deploying Wize Wizard: From Strategy Workbench to Production System
Wize Wizard started with a simple question: what do you do when you know you need to move forward, but you do not yet know what the right move is?
That question turned into a much larger engineering project. Instead of building another checklist app, I wanted Wize Wizard to connect strategy, reasoning, uncertainty, execution, learning, and evidence in one workflow. Then I wanted the repository itself to meet the same standard: documented architecture, automated testing, security scanning, reproducible deployment, production health checks, and enough visual evidence that somebody could understand the system without reading every source file.
The interesting part was not that everything worked on the first try. It did not. The useful part was the process of turning each failure into another control in the system.

What Wize Wizard actually does
At the center of Wize Wizard are five strategic questions:
- What is Winning?
- Where Will I Play?
- What Tools Do I Need?
- What Management System Do I Need?
- What Skills Do I Need?
The application pushes those answers beyond vague intentions. A useful answer follows the pattern:
I need to __ so that I can ____.
That sounds simple, but it forces a distinction between an activity and a reason for doing the activity.
The reasoning continues through a Why chain:
Need / Goal → Wish → Dream → Fantasy
Each transition asks “Why?” again. The point is not to make the plan more dramatic. The point is to expose the deeper motivation behind a tactical choice.
Wize Wizard then connects that strategy to PERT estimation, stress testing, tasks, communications planning, Clay Tablets, a journal, learning material, market/finance/risk tools, and a final Project Plan & Scope.

A few definitions before getting into the engineering
CI/CD means Continuous Integration and Continuous Delivery or Deployment. Continuous Integration automatically validates changes as they enter the repository. Continuous Delivery/Deployment takes validated code toward a releasable or running production state.
CodeQL is static application security analysis. It analyzes code structure and data flow to detect classes of vulnerabilities.
Bandit is a Python-focused static security scanner. It catches suspicious patterns such as unsafe subprocess usage, risky SQL construction, insecure debug settings, and other Python security issues.
pip-audit checks installed Python dependencies against known vulnerability advisories. This is different from Bandit: Bandit looks at code patterns; pip-audit looks at vulnerable packages.
Dependabot watches dependency definitions and can propose upgrades when newer or security-relevant versions are available.
Trivy is a broader vulnerability scanner. In this project it is part of the supply-chain/security layer and can inspect filesystem/package/container-related risk.
Playwright drives a real browser. Unit tests can tell me a function returned the expected value; Playwright can tell me whether a user can actually log in, open Strategy, view PERT, reach the Handbook, use the admin area, and see a usable mobile layout.
D2 is diagram-as-code. Architecture diagrams live as source files beside the application, so architecture changes can be reviewed and versioned instead of living only in a drawing tool.
PERT stands for Program Evaluation and Review Technique. With optimistic O, most-likely M, and pessimistic P estimates, the classic expected duration is:
E = (O + 4M + P) / 6
A common standard deviation estimate is:
σ = (P - O) / 6
That lets Wize Wizard talk about uncertainty instead of pretending every task estimate is a single perfect number.
Hardening the repository
The goal was not to collect badges. The goal was to create independent checks that fail for different reasons.

The pipeline ended up using several layers:
- Compile and automated tests for basic correctness.
- Bandit for Python security patterns.
- pip-audit for vulnerable Python dependencies.
- CodeQL for deeper static security analysis.
- Trivy for another supply-chain/vulnerability perspective.
- Dependabot for dependency update visibility.
- Playwright for browser-level behavioral QA.
- Docker health checks for runtime state.
- Backend and public HTTPS checks for deployment verification.
This matters because one green tool does not prove the whole application is healthy. A dependency scanner cannot tell me the login button is broken. Playwright cannot tell me that a dependency has a published CVE. A unit test does not prove Nginx can reach the production container. The strength comes from layering the controls.
The failures were part of the architecture
One of the first ugly problems was unresolved Git merge conflict markers. Files such as the database layer, models, application initialization, and README had conflicting sections. A repository can look mostly intact while still containing <<<<<<<, =======, and >>>>>>> markers that break builds or create ambiguous source.
The fix was not just to repair those files. A merge-marker scan became part of the validation mindset:
grep -RIn \
--exclude-dir=.git \
--exclude-dir=.venv \
-E '^(<<<<<<<|=======|>>>>>>>)' .
Another problem came from Bandit. Dynamic SQL used a table name inside a query. Even when the intended values were controlled, security tooling correctly treats dynamically assembled SQL as something that deserves scrutiny. The fix was a fixed query whitelist: known table names map to complete known SQL statements. That removed the dynamic query construction from the execution path.
Bandit also flagged development-style debugging. Production should not be running Flask with debug=True, so the application was hardened to run without the interactive debugger.
Then Trivy failed for a completely different reason: the GitHub Action version itself was wrong. The workflow referenced an invalid action version. Updating the workflow to a valid Trivy action release fixed the scanner stage. This was a useful reminder that CI/CD configuration is software too. The application can be correct while the automation around it is broken.
The deploy workflow exposed another class of problem. A final curl verification produced a transient connection failure. A deployment check that gives up on the first network wobble can mark a healthy deployment as failed. The final health verification was changed to use bounded retries, retry delays, connection timeouts, and --retry-all-errors.
That is an important distinction: resilience is not the same as ignoring failures. The check still fails if production stays unhealthy. It simply allows a newly restarted service enough time to settle.
Authentication hardening
The original bootstrap behavior could create a default administrator account. That is convenient in development and dangerous in production.
The hardened bootstrap requires:
WIZE_ADMIN_USERNAMEWIZE_ADMIN_PASSWORD- a password of at least 12 characters
A fresh installation without the required bootstrap configuration fails rather than silently creating an insecure default.
Production secrets stay in the environment, not in Git, documentation, screenshots, issues, or CI logs.
The production .env is protected with restrictive file permissions, and persistent application data has an explicit ownership model instead of using a broad chmod 777.
The production architecture
The public application is https://wizard.richmackos.com.
The request path is intentionally layered:

A browser reaches Nginx over HTTPS. Nginx terminates TLS and proxies to 127.0.0.1:5080. That loopback port maps into the wizard Docker container on port 8080, where Waitress serves the Flask application.
The SQLite database persists outside the disposable application filesystem:
- Host data:
/home/ubuntu/wizard/data - Container data:
/data - Database:
/data/wize.db
This is important. Rebuilding a container should not mean rebuilding the user's data.
The backend mapping is deliberately loopback-only:
127.0.0.1:5080:8080
The application server is therefore not intended to be directly exposed to the internet. Nginx remains the public edge.
Deployment became a three-layer health test
A successful docker compose up -d is not enough to call a release successful.
I verify three layers:
Layer 1: container health
Is Docker reporting the Wize Wizard container as running and healthy?
Layer 2: backend health
Can the production host reach:
http://127.0.0.1:5080/healthz
Layer 3: public health
Can an external client reach:
https://wizard.richmackos.com/healthz
That sequence catches different failures. A container can be running while the application inside it is broken. The backend can be healthy while Nginx is misconfigured. Nginx can work locally while DNS/TLS/public routing has a problem.
The Git flow
The Git workflow is intentionally boring, because boring release mechanics are easier to trust.
A normal change begins by fetching and checking the repository state:
git fetch origin
git status -sb
git branch --show-current
Before pushing, the local gate includes compilation, tests, security checks, and whitespace/conflict validation.
Documentation changes also render D2 diagrams. UI or route changes trigger Playwright QA and refreshed screenshots.
Only after reviewing the staged diff does the change get committed and pushed to main.
GitHub Actions then runs the repository gates and deployment workflow.
If a bad commit reaches main, the preferred rollback is a revert commit, not rewriting shared history:
git revert <BAD_COMMIT_SHA>
git push origin main
D2 turned architecture into source code
One of my favorite changes was moving architecture into D2.
Instead of a single diagram that becomes stale, Wize Wizard has diagrams for:
- system architecture
- strategy engine
- Why ladder
- project lifecycle
- PERT/risk
- communications
- security architecture
- data model
- CI/CD and production

The D2 source is version-controlled. The rendered documentation is regenerated from it.
For the blog workflow, I convert rendered SVG documentation to PNG before publication. That avoids inconsistent SVG handling across downstream publishing/rendering environments. PNG also gives the article a predictable visual asset for social cards and inline documentation.
The operational rule is simple: D2 is the source; PNG is the publication artifact.
Browser QA: test what a user actually sees
The Playwright harness covers the major application surfaces:
login, dashboard, Strategy, Five Strategic Questions, Why reasoning, PERT/stress, communications, lessons, Handbook, market, finance, risk, tasks, burndown, Clay Tablets, journal, final Project Plan, admin users, password changes, mobile layout, and the health endpoint.

A previous full production run reached 21 PASS, 0 WARN, 0 FAIL. I treat that as a historical baseline, not a permanent guarantee. Any meaningful UI, authentication, routing, reporting, or deployment change can justify running it again.
The screenshots are also documentation evidence. They make the README and Wiki show the real product rather than describing an interface nobody can see.
Communications planning is more than counting people
Wize Wizard also models communication complexity.
For n people, the raw number of possible pairwise communication channels is:
n(n - 1) / 2
That grows quickly.
But real teams do not necessarily communicate as an unstructured complete graph. Wize Wizard can organize contributors around management groups, Product Leads, stable buddy pairs, and an additional coordination-management layer for remainders. The idea is to expose the communication cost while still allowing a deliberate operating structure.
From strategy to a Project Plan
The final report is not supposed to be a decorative summary. It acts as a Project Plan & Scope.
It brings together:
- executive purpose
- the five Need Goals
- Why chains
- PERT estimates and stress ranges
- execution tasks
- communications structure
- assumptions
- journal evidence
- Handbook checks
- readiness gates
- next actions
That is the larger idea behind Wize Wizard: reasoning should eventually become execution evidence.
What I learned from the hardening process
The biggest lesson was that repository hardening is not one task.
It is a chain.
A secure bootstrap does not guarantee a safe dependency tree. A clean dependency tree does not guarantee correct code. Correct code does not guarantee the browser workflow works. A passing browser test does not guarantee the deployment is reachable. A reachable deployment does not guarantee the database is persistent. Good architecture does not help future maintainers if it is not documented.
That is why the final operating cycle looks like this:
CHANGE → VALIDATE → SECURE → VISUALIZE → QA → COMMIT → PUSH → CI/CD → HEALTH CHECK → DOCUMENT → RELEASE
Each stage answers a different question.
Did the code compile?
Did the tests pass?
Did security tooling find something?
Does the architecture still match reality?
Can a user operate it?
Can Git reproduce the change?
Can automation validate it?
Did production actually become healthy?
Can somebody understand what was built afterward?
The final result
Wize Wizard is now more than the Flask application that started the project. It is a strategy and execution workbench with a production operating model around it.
The product has structured strategic reasoning, Why chains, PERT uncertainty, communications planning, tasks, evidence, learning, analytical tools, and a final project plan.
The repository has layered CI/CD and security checks.
The documentation has version-controlled D2 architecture and real QA screenshots.
The production system has Docker isolation, persistent SQLite data, Nginx/TLS, protected environment configuration, and multi-layer health verification.
And maybe most importantly, the failures are no longer just things that happened while building it. Most of them became checks, rules, or documentation that make the next deployment less fragile than the last one.
Complete Visual Documentation Gallery
The images below are the visual evidence used by the repository documentation.
For blog compatibility, every publication asset in this gallery is PNG. The D2
source remains version-controlled in the repository, but SVG is not used as a
blog publication format.
D2 Architecture Diagrams
Cicd Production

Communications

Data Model

Pert Risk

Project Lifecycle

Security Architecture

Strategy Engine

System Architecture

Why Ladder

Playwright QA Screenshots
00 Login

02 Strategy Whys

03 Strategy

04 Strategic Questions Whys

05 Pert Stress

06 Communications

07 12 Lessons

08 Market

09 Finance

10 Risk

11 Handbook

12 Final Project Plan

13 Admin Users

14 Wize Wizard

15 Tasks Burndown

16 Clay Tablets

17 Journal

18 Change Password

90 Mobile Home

Wiki Images
Diagrams Cicd Production

Diagrams Communications

Diagrams Data Model

Diagrams Pert Risk

Diagrams Project Lifecycle

Diagrams Security Architecture

Diagrams Strategy Engine

Diagrams System Architecture

Diagrams Why Ladder

Qa 03 Strategy

Qa 04 Strategic Questions Whys

Qa 05 Pert Stress

Qa 06 Communications

Qa 07 12 Lessons

Qa 11 Handbook

Qa 12 Final Project Plan

Qa 15 Tasks Burndown

Qa 16 Clay Tablets

Qa 17 Journal

Cloud infrastructure, AI systems, automation, and developer tools.
Visit richmackos.com →