Blog Visual Asset Enrichment + Sprint 69 Deferred Work
Sprint 70: Blog Visual Asset Enrichment + Sprint 69 Deferred Work
Decisions
D1: Unify cloudflared SSoT to aether-gitops (Sprint 69 carryover)
Context: cloudflared was managed via direct kubectl apply with AlgoSu/infra/k3s/cloudflared.yaml, not under ArgoCD tracking (Sprint 69 G3). Simultaneously, an orphan manifest algosu/base/monitoring/cloudflared.yaml existed in aether-gitops but was unusable due to missing hotfix/probe/securityContext and different secret name.
Choice: Copy AlgoSu source manifest (robust SSoT) to aether-gitops algosu/base/cloudflared.yaml, add to kustomization.yaml resources, delete orphan manifest, delete AlgoSu source manifest. ArgoCD in-place adopts with zero downtime, bringing cloudflared under GitOps management.
Alternatives: (a) Promote orphan manifest to authoritative — risky due to required hotfix/probe/secret augmentation. (b) Maintain both manifests — permanent drift. Both rejected.
Context: Using cloudflare/cloudflared:latest violates CLAUDE.md Architect rules. The version actually fetched in production cluster is 2026.3.0, verified with 28h+ no-restart.
Choice: Pin cloudflare/cloudflared:2026.3.0 fixed tag in aether-gitops base. Same binary, RollingUpdate is seamless (<3 seconds).
Alternatives: Could go to latest stable (other than 2026.3.0), but production-verified version is first priority.
D3: Blog visualization design option — Option C (hybrid)
Context: PM feedback on system-architecture-overview converted to Mermaid in Sprint 70-5 Phase 3: "Architecture and structural visualizations need more visuals — can't tell what it's saying". Mermaid's simple boxes+arrows couldn't convey meaning, hierarchy, or information density.
Choice: Option C Hybrid — Repeated patterns (3-Tier matrix, hierarchy tree, Phase cards) as reusable React components; simple flows as existing Pipeline/ServiceGrid; sequences/complex branches (OAuth, Saga state) keep Mermaid. Balances design control, workload, and bundle size.
Alternatives: (B) Full handcrafted SVG — high workload, difficult to express OAuth sequences. (A) Advanced Mermaid — token integration difficult, low PM satisfaction probability. (D/E) External tools/React Flow — poor static export compatibility, not recommended.
Context: Direct lucide identifier references in MDX like icon={Crown} cause build failures (Crown is not defined). MDX JSX expressions require module scope imports; compileMDX only auto-injects React components via components option.
Choice: Define string-keyed registry of 30 lucide icons in src/components/blog/icons.ts, each component looks up with getIcon(name). Use icon="Crown" in MDX. No imports needed in any of the 6 MDX files.
Alternatives: (a) Add lucide import statement per MDX file — needed in all 6, poor maintainability. (b) compileMDX scope option — unclear in v5.0, poor type safety.
D5: Stable sort for 6 same-date posts — order auxiliary field
Context: All 6 series posts have date: "2026-04-09", leading to non-deterministic sort from Array.sort stable + fs.readdirSync alphabetical combination. Conflicts with user-intended series order.
Choice: Add order?: number to PostMeta, enhance sort to (date desc, order desc) composite. Assign order 1~6 to 6 posts (intro=1, sprint-journey=6). No change to display (date).
Alternatives: (a) Use ISO datetime to separate times — gray-matter Date object risk. (b) Artificially assign timestamps for each new post — poor maintainability.
When to Reuse: When migrating a resource managed only with kubectl apply to ArgoCD tracking. Copying the same namespace/name/spec to GitOps causes ArgoCD to adopt in-place (only adds annotations/labels) without RollingUpdate. Zero downtime. Note: even one character difference in spec causes recreation → backup with kubectl get -o yaml beforehand is essential.
When to Reuse: When MDX body needs to pass identifiers (icons/types) as props to React components in next-mdx-remote compileMDX. Instead of requiring import statements in MDX, receive as string key and do registry lookup inside the component. Only one place to modify when adding new icons.
When to Reuse: When multiple ASCII diagrams exist in blog/docs, classify by pattern (system topology/hierarchy tree/sequential pipeline/Phase milestone/sequence/state machine). Sequence and state machine fit Mermaid; the rest — handcrafted React components are superior for design control, dark mode, and accessibility. Component creation is worthwhile when the same pattern repeats across 3+ posts.
When to Reuse: When visual satisfaction is key to the work (blog design, UI components). Prioritize infrastructure + 1~2 sample posts in Phase 1 → PM review in production environment → if satisfied, batch process remaining. Don't commit Phase 1+2 work together — gate on sample review to quickly validate design hypotheses and minimize toolchain abandonment costs.
Symptom: After npm install lucide-react, import { Github } from 'lucide-react' → Module '"lucide-react"' has no exported member 'Github' build failure.
Root Cause: Current npm registry's [email protected] has 5822 exports, but Github itself is deprecated. Git-related icons like GitBranch, GitFork exist, but Github brand mark is excluded. LucideIcon type export also missing.
Fix: Remove Github import (replace GitHub Worker with GitBranch). Define LucideIcon type yourself (ComponentType<{className?, size?, strokeWidth?}>). Recommend pre-validating new lucide icons with node -e "console.log('Foo' in require('lucide-react'))".
Symptom: After writing <HierarchyNode icon={Crown}/> in MDX, build fails with ReferenceError: Crown is not defined at stringify. compileMDX's components option only injects components for direct usage (<Crown/>), not identifier references inside JSX expressions.
Root Cause: MDX is essentially a JS module and identifiers require module scope imports. compileMDX components is just JSX tag mapping sugar.
Fix: Accept prop as string key, not React identifier, and do registry lookup (getIcon(name)) inside the component. Adopts D4 pattern of this sprint. No import statements needed anywhere in 6 MDX files.
G3: nginx try_files pattern — 404 with trailing slash
Symptom: curl https://blog.algo-su.com/posts/system-architecture-overview/ → 404. Without trailing slash returns 200.
Root Cause: blog/nginx.conf's try_files $uri $uri.html $uri/ =404 goes to folder matching logic with trailing slash and fails fallback. Next.js export generates both out/posts/{slug}.html (file) and out/posts/{slug}/index.html (folder), but nginx pattern prioritizes file, so no-trailing-slash form with .html extension matching works correctly.
Fix: Use no-trailing-slash form when providing PM review URLs. Or future nginx try_files pattern can be enhanced to $uri $uri.html $uri/index.html =404 (separate task).
Symptom: In Sprint 70-5 Phase 3, system-architecture-overview migrated to Mermaid → sample push → production review → "need more visualization — can't tell what it's saying" feedback → Sprint 70-6 required creating 4 new component types, redoing work.
Root Cause: Design hypothesis (simple Mermaid flowchart) in Phase 1 infrastructure design stage didn't match PM's expectation of "rich visualization". Can't know in advance whether the design hypothesis strength matches PM expectations before sample review.
Fix: If design hypothesis strength is weak, quickly push sample 1 post to validate in production environment (rollback cost < guessing cost). In Sprint 70-6, Plan agent presented 5 options → PM selected Option C → then sample → satisfied → Phase 2. Clarifying PM intent in the options stage was key.