Hive
fix(server): cache marketing static assets
GitHub issue · Closed
What changed
This makes the production-like server environments load the static cache manifest from TuistWeb.Endpoint, which is where Phoenix reads it when generating digested static paths.
It also routes the homepage marketing images through Phoenix verified static paths instead of hardcoded /marketing/images/... strings. Those paths can now resolve to the digested files emitted by mix assets.deploy, including the ?vsn=d marker that enables long-lived static caching.
Finally, this adds targeted origin timing logs for /marketing/assets and /marketing/images, then adds a Marketing Static Assets row to the Page Load Application Performance Index (Apdex, https://www.apdex.org/) dashboard. The row tracks origin request rate and response-time percentiles for the assets this fix is meant to move to edge cache hits.
Why
A report from Brazil showed that tuist.dev was slow to open. External probes from Brazil reached nearby Cloudflare locations in São Paulo and Rio, so the network route to the edge looked reasonable. The expensive part was that first-page static assets were still returning dynamic, must-revalidate responses and waiting on the origin.
The homepage loads enough images, stylesheet, and JavaScript that repeated origin waits in the hundreds of milliseconds can turn into multi-second first loads, especially on colder browser and edge caches.
Root cause
The static manifest path was configured at the top-level :tuist application config instead of under TuistWeb.Endpoint. Because the endpoint did not receive the manifest configuration, static path generation did not consistently emit digested versioned paths for production assets.
The homepage also hardcoded several marketing image paths, which bypassed Phoenix static path generation entirely.
The existing dashboard only filtered request_kind="page_load" from Phoenix endpoint telemetry. Marketing static assets are served by Plug.Static before that telemetry and request-kind plug run, so the dashboard would not show the direct asset-origin effect of this change.
Approach
The fix keeps the asset pipeline unchanged and makes the production, staging, and canary endpoint configuration point at the existing priv/static/cache_manifest.json file. That lets Phoenix use the manifest generated by mix assets.deploy without introducing new caching rules or Cloudflare-specific behavior.
Homepage images now use verified static paths, matching the existing Phoenix pattern used for assets that need manifest-backed digests.
For observability, a lightweight plug emits info-level timing logs only for served marketing static assets. It uses request_kind="marketing_static_asset" so Grafana can chart the signal without broadening endpoint telemetry to every static file.
Impact
After deployment, marketing static assets should be requested through digested versioned paths and receive long-lived static cache headers. Cloudflare can then keep those assets at the Brazil edge after the first fill instead of revalidating the same immutable files against the origin on every load.
The extra logging is scoped to served marketing static assets, so it should not increase log volume for all static files. Once Cloudflare serves versioned assets from edge locations, the new dashboard row should show fewer asset responses reaching origin and lower latency for those that still do.
There is no customer data migration or runtime configuration migration.
Validation
- Ran
mix format --check-formatted config/prod.exs config/can.exs config/stag.exs lib/tuist_web/marketing/controllers/marketing_html/home.html.heex. - Ran
mix compile. - Ran
mix assets.deployand verified the generated manifest contains digested entries for the marketing stylesheet, JavaScript, and homepage images. - Verified an isolated Phoenix endpoint emits paths such as
/marketing/assets/bundle-...css?vsn=dand/marketing/images/home/dashboard-...webp?vsn=dwhen the cache manifest is configured onTuistWeb.Endpoint. - Ran
mix test test/tuist_web/plugs/marketing_static_asset_observability_plug_test.exs. - Ran
jq empty infra/grafana-dashboards/page-load-apdex.json. - Ran
jq -e '.spec.elements["panel-21"].spec.title == "Static Origin Request Rate" and .spec.elements["panel-22"].spec.title == "Static Origin Latency Percentiles (P50 / P95 / P99)" and ([.spec.layout.spec.rows[].spec.title] | index("Marketing Static Assets") != null)' infra/grafana-dashboards/page-load-apdex.json. - Ran
git diff --check. - Browser screenshot verification was attempted, but the local homepage returned
503because the local database was not available in this worktree.
Investigate, reproduce, or fix this item in an isolated repository. Each Flight preserves its outcome and agent session.
Start a Flight and preserve its objective, outcome, and session here.
No GitHub comments yet.