Validation: Catalog tab — app portfolio with App Store links
Verdict: FAIL
Ticket
#50 — Catalog tab: app portfolio with App Store links — Adds portfolio description header, App Store link buttons with
data-turbo="false" for external navigation, app_store_url column and HTTPS validation on CatalogEntry model.Environment
Production cluster, namespace
intelligentstaffingsystems, URL https://intelligentstaffingsystems.ai.Running pod image:
harbor.tail5b443a.ts.net/intelligentstaffingsystems/app:93b9a79b (10 commits behind PR #84 merge). ArgoCD status: Synced / Degraded.Tiers Executed
- Tier 1 (Local — code inspection): Full source review of all changed files. Docker tests skipped per issue #65.
- Tier 3 (Production): kubectl pod status, ArgoCD sync/health, endpoint curl, pipeline status.
Checks
| # | Criterion | How Verified | Result | Evidence |
|---|---|---|---|---|
| 1 | Pipeline green for merge commit | Woodpecker pipeline #85 (PR #84 merge) and #90 (CI fix) | FAIL | Pipeline #85: security + test failed. Pipeline #90: security passed, test failed (<code>minitest/mock</code> LoadError — systemic gem issue). Build-and-push SKIPPED on both. |
| 2 | New image tag propagated to pod | <code>kubectl get pods -n intelligentstaffingsystems</code> | FAIL | Running pod uses image <code>:93b9a79b</code> (commit from before PR #84). No new image was pushed because CI failed. |
| 3 | Pod running and ready | <code>kubectl get pods --all-namespaces</code> | PARTIAL | Old pod <code>-6d6896dd95-ls9k4</code> is Running (0 restarts, 11h). New pod <code>-8474c67bc8-nxphp</code> is Init:CrashLoopBackOff (13 restarts) due to <code>PLACEHOLDER_POSTGRES_HOST</code> DB connection error. |
| 4 | Health endpoint returns 200 | <code>curl https://intelligentstaffingsystems.ai/up</code> | PASS | Returns HTTP 200. Root URL also returns 200. <code>/catalog</code> returns 302 (redirect to login — expected for unauthenticated). |
| 5 | Portfolio description at top of catalog page | Source: <code>app/views/catalog/index.html.erb</code> lines 14-18 | CODE PASS | Header has <code>.catalog-intro</code> with text: "These are real apps we have built and shipped to the App Store... Everything you see here is customizable to your exact needs." |
| 6 | Description communicates target audience | Source: <code>index.html.erb</code> line 17 | CODE PASS | Text mentions "sports program, a local shop, or a service with monthly subscribers" and "the app that runs your business." |
| 7 | Cards display with App Store link via app_store_url column | Source: <code>_catalog_entry.html.erb</code> lines 25-30, migration, model | CODE PASS | Migration adds <code>app_store_url:string</code>. Model validates HTTPS format (<code>allow_blank: true</code>). Partial renders <code>.catalog-app-store-link</code> when <code>safe_app_store_url(entry)</code> returns a URL. |
| 8 | App Store links use <code>data-turbo="false"</code> for external navigation | Source: <code>_catalog_entry.html.erb</code> line 26, <code>show.html.erb</code> line 51 | CODE PASS | Both index card partial and show page use <code>data: { turbo: "false" }, target: "_blank", rel: "noopener noreferrer"</code>. |
| 9 | Responsive card grid layout | Source: <code>catalog.css</code> lines 114-118, 427-430 | CODE PASS | Mobile: <code>grid-template-columns: 1fr</code>. Desktop (600px+): <code>repeat(2, 1fr)</code>. |
| 10 | All three roles see identical content | Source: <code>catalog_controller.rb</code> (no role checks), tests lines 21-37 | CODE PASS | Controller has no role restrictions. Tests verify lead, client, admin all get 200. |
| 11 | Detail page shows expanded description, screenshots, tech stack | Source: <code>show.html.erb</code> | CODE PASS | Gallery section, description via <code>simple_format</code>, tech tags in sidebar, App Store link in sidebar. |
| 12 | Endpoint tests: role access (lead/client/admin 200, signed-out redirect) | Source: <code>catalog_controller_test.rb</code> | CODE PASS | Tests at lines 8-37 cover all four cases. Additional tests for content, App Store links, data-turbo attributes. |
| 13 | Model tests: CatalogEntry validations including app_store_url | Source: <code>catalog_entry_test.rb</code> | CODE PASS | Tests at lines 112-137: optional field, blank allowed, HTTPS accepted, non-HTTPS rejected, arbitrary text rejected. |
Regression Check
- Production root URL returns 200 — existing deployment is healthy.
- The
/uphealth endpoint returns 200. - The currently running pod (old image) has 0 restarts and has been stable for 11 hours.
- No regression in existing deployment, but the NEW deployment attempt is CrashLooping due to database config.
Discovered Issues
- CI test infrastructure broken —
minitest/mockLoadError. Pipeline #90 test step fails withcannot load such file -- minitest/mock (LoadError). This is a systemic issue (not PR #84 specific) that blocks ALL CI pipelines from reaching build-and-push. Theminitest-mockgem needs to be added to Gemfile or the Ruby 3.4 bundled gems configuration needs updating. This blocks deployment of ALL merged changes. - ArgoCD Degraded —
PLACEHOLDER_POSTGRES_HOST. New ReplicaSet pod-8474c67bc8-nxphpcrashes in init container withActiveRecord::DatabaseConnectionError: There is an issue connecting with your hostname: PLACEHOLDER_POSTGRES_HOST. The deployment has a placeholder database host that was never replaced with the real value. This is a kustomize/secrets configuration issue inpal-e-deployments. - Image 10 commits behind. The running image (
:93b9a79b) is from before Sprint B PRs #82, #83, #84, and the CI fix commit. None of the Sprint B features are live in production.
Failure Summary
The code implementation is correct and complete — all acceptance criteria are satisfied at the source level. However, the changes have not been deployed to production because:
- CI pipeline fails at the test step (
minitest/mockLoadError), preventing image build-and-push. - No new image exists in Harbor for commits after
93b9a79. - ArgoCD is degraded due to database connection misconfiguration in the deployment overlay.
Both discovered issues (#1 CI gem fix, #2 deployment secrets) must be resolved before any Sprint B work can be validated in production. The ticket cannot move to done until the changes are confirmed live.