Pictures: avatar and logo tiles load eagerly with no size, and their stamped addresses are cached for only a day #1158

Closed
opened 2026-10-31 03:04:25 +00:00 by tiagoagueda · 0 comments
Owner

What exists today

core/templatetags/postulo.py:289-318 _tile() draws a picture as <span class="avatar ..."><img src="..." alt=""></span>: no loading="lazy", no decoding="async", unlike the flag tags in the same file (lines 197-240). It is used by {% avatar %} (354-368) and {% company_logo %} (371-387), which appear on every board card (applications/partials/application_card.html:40), in company and application tables, and in the masthead.

The addresses are stamped: avatar_url() (336-342) adds ?v=<profile.updated_at> and logo_url() (345-350) ?v=<company.logo_fetched_at>, so a new picture is a new address. Yet both views answer Cache-Control: private, max-age=86400 (accounts/views.py:388, jobs/views.py:1493), so after a day each one is asked for again. The ledger said "versioned logos cached only a day"; that holds for avatars too.

What would change

  • _tile() adds loading="lazy" decoding="async" to its <img>, and width/height matching the box is not needed because the box is sized by its classes. The masthead's own avatar is above the fold and is fetched at once either way (lazy images in view load immediately).
  • Both views answer private, max-age=31536000, immutable when the request carries a v equal to the current stamp, and keep today's day-long answer otherwise (a request with no or an old stamp).
  • One caveat to check while doing it: logo_url's stamp has one-second resolution and jobs/merging.py:641 copies another company's stamp onto the kept one; neither lets an old picture be served under a new address, but a test should pin that a changed logo changes the address.

What it saves or protects

small: long tables and boards of companies stop fetching off-screen logos on load, and a returning browser stops revalidating every logo and avatar once a day

Accessibility

none: the tiles are decorative (alt="", beside the name); the layout must not shift, which the tile's fixed size classes already ensure. tests/test_avatars.py and tests/test_logos.py cover the markup and the responses

Decided by the maintainer (2026-10-31)

stamped avatars and logos: private, max-age one year; loading=lazy and decoding=async on tiles

Decisions

  • A year in the private cache for stamped pictures? Recommended: yes, the address changes whenever the picture does; but it keeps a person's photograph on a shared computer's disk longer, so the user decides (the no-store on pages, #787, is about pages, not these).
  • Split? Recommended: one issue; both are two-line changes in the same pair of files.

Found by the efficiency and reliability audit of 2026-10-30 (finding A15; index postulo/postulo#1108). Checked against main at daee30b15 (2026-10-30).

## What exists today `core/templatetags/postulo.py:289-318` `_tile()` draws a picture as `<span class="avatar ..."><img src="..." alt=""></span>`: no `loading="lazy"`, no `decoding="async"`, unlike the flag tags in the same file (lines 197-240). It is used by `{% avatar %}` (354-368) and `{% company_logo %}` (371-387), which appear on every board card (`applications/partials/application_card.html:40`), in company and application tables, and in the masthead. The addresses are stamped: `avatar_url()` (336-342) adds `?v=<profile.updated_at>` and `logo_url()` (345-350) `?v=<company.logo_fetched_at>`, so a new picture is a new address. Yet both views answer `Cache-Control: private, max-age=86400` (`accounts/views.py:388`, `jobs/views.py:1493`), so after a day each one is asked for again. The ledger said "versioned logos cached only a day"; that holds for avatars too. ## What would change - `_tile()` adds `loading="lazy" decoding="async"` to its `<img>`, and `width`/`height` matching the box is not needed because the box is sized by its classes. The masthead's own avatar is above the fold and is fetched at once either way (lazy images in view load immediately). - Both views answer `private, max-age=31536000, immutable` when the request carries a `v` equal to the current stamp, and keep today's day-long answer otherwise (a request with no or an old stamp). - One caveat to check while doing it: `logo_url`'s stamp has one-second resolution and `jobs/merging.py:641` copies another company's stamp onto the kept one; neither lets an old picture be served under a new address, but a test should pin that a changed logo changes the address. ## What it saves or protects small: long tables and boards of companies stop fetching off-screen logos on load, and a returning browser stops revalidating every logo and avatar once a day ## Accessibility none: the tiles are decorative (`alt=""`, beside the name); the layout must not shift, which the tile's fixed size classes already ensure. `tests/test_avatars.py` and `tests/test_logos.py` cover the markup and the responses ## Decided by the maintainer (2026-10-31) stamped avatars and logos: private, max-age one year; loading=lazy and decoding=async on tiles ## Decisions - **A year in the private cache for stamped pictures?** Recommended: yes, the address changes whenever the picture does; but it keeps a person's photograph on a shared computer's disk longer, so the user decides (the `no-store` on pages, #787, is about pages, not these). - **Split?** Recommended: one issue; both are two-line changes in the same pair of files. --- Found by the efficiency and reliability audit of 2026-10-30 (finding A15; index postulo/postulo#1108). Checked against `main` at `daee30b15` (2026-10-30).
tiagoagueda added this to the 0.6.0 milestone 2026-10-31 03:04:25 +00:00
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
Postulo/postulo#1158
No description provided.