Jump to content

ICT:Dashboard autopurge architecture: Difference between revisions

From Costa Sano MediaWiki
Created page with "= ICT: Dashboard Auto‑Purge Architecture = This page documents why dashboards in this wiki require an automatic purge after saving a Page Forms form, why several intuitive approaches fail, and why the final solution works reliably. It is written for future administrators and maintainers of the Costa Sano Research infrastructure. == 1. The Problem == Dashboards such as '''Dashboard:Place''' display data stored in Cargo tables. After saving a form, the updated Car..."
 
No edit summary
Line 1: Line 1:
= ICT: Dashboard Auto‑Purge Architecture =
= ICT: Dashboard Auto‑Purge Architecture =


This page documents why dashboards in this wiki require an automatic purge after saving a Page Forms form, why several intuitive approaches fail, and why the final solution works reliably
This page documents why dashboards in this wiki require an automatic purge after saving a Page Forms form, why several intuitive approaches fail, and why the final solution works reliably.
It is written for future administrators and maintainers of the Costa Sano Research infrastructure.


== 1. The Problem ==
== 1. The Problem ==
Line 14: Line 13:
* Reverse proxies may cache responses   
* Reverse proxies may cache responses   
* Page Forms redirects do not trigger a purge   
* Page Forms redirects do not trigger a purge   
Users therefore see outdated dashboard data unless the page is manually purged.


A reliable, automatic purge mechanism is required.
A reliable, automatic purge mechanism is required.
Line 26: Line 23:


'''Conclusion:''' HTML refresh cannot be used.
'''Conclusion:''' HTML refresh cannot be used.
---


=== 2.2. Redirecting to <code>?action=purge</code> ===
=== 2.2. Redirecting to <code>?action=purge</code> ===
A redirect to:
A redirect to <code>?action=purge</code> always triggers MediaWiki’s confirmation dialog
 
<code>?action=purge</code>
 
always triggers MediaWiki’s confirmation dialog:
 
> Do you want to purge this page?
 
This dialog cannot be suppressed via GET requests.
This dialog cannot be suppressed via GET requests.


'''Conclusion:''' GET‑based purge is never silent.
'''Conclusion:''' GET‑based purge is never silent.
---


=== 2.3. Page Forms limitations ===
=== 2.3. Page Forms limitations ===
Page Forms does not provide:
Page Forms does not provide hooks or callbacks that run after saving. 
It cannot trigger a purge.


* after‑save hooks 
'''Conclusion:''' Page Forms cannot be used for purge logic.
* post‑redirect callbacks 
* purge triggers 
* button overrides 
 
There is no way to attach purge logic to the Save button.
 
'''Conclusion:''' Page Forms cannot trigger a purge.
 
---


=== 2.4. JavaScript redirect loops ===
=== 2.4. JavaScript redirect loops ===
If JavaScript redirects to <code>?action=purge</code>:
Redirecting to <code>?action=purge</code> causes:


# The purge dialog appears  
# Purge dialog   
# After confirmation, the page reloads  
# Page reload  
# The JS sees no marker indicating purge completion 
# JavaScript fires again   
# JS redirects again   
# Loop  
# Infinite loop  


'''Conclusion:''' Redirect‑based purge is unstable.
'''Conclusion:''' Redirect‑based purge is unstable.
---


=== 2.5. Query parameters being stripped ===
=== 2.5. Query parameters being stripped ===
Reverse proxies, skins, and canonical URL rewrites may strip unknown parameters such as:
Reverse proxies, skins, and canonical URL rewrites may strip unknown parameters such as <code>?purged=1</code>
 
This prevents loop‑detection.
<code>?purged=1</code>


This causes loops because the JS cannot detect that the purge already happened.
'''Conclusion:''' Only parameters MediaWiki preserves can be used.
 
'''Conclusion:''' Only parameters MediaWiki preserves can be used as markers.


== 3. Requirements for a Working Solution ==
== 3. Requirements for a Working Solution ==
Line 84: Line 56:
A correct solution must:
A correct solution must:


* purge silently (no dialog)  
* purge silently   
* avoid loops   
* avoid loops   
* work for all dashboards   
* work for all dashboards   
* survive reverse proxies and canonicalization  
* survive reverse proxies   
* be centralized   
* be centralized   
* be successor‑friendly   
* be successor‑friendly   
This leads to the final architecture.


== 4. The Final, Working Solution ==
== 4. The Final, Working Solution ==


=== 4.1. Purge via the MediaWiki API ===
=== 4.1. Purge via the MediaWiki API ===
MediaWiki performs a silent purge only when:
Silent purge requires:
 
* the request is a POST 
* it includes a valid CSRF token 
* it uses the API module 


This avoids the confirmation dialog entirely.
* POST request 
 
* CSRF token 
---
* API module 


=== 4.2. Use a preserved query parameter ===
=== 4.2. Use a preserved query parameter ===
Line 111: Line 77:


<code>?mw_purged=1</code>
<code>?mw_purged=1</code>
to mark that the purge has already occurred.
---


=== 4.3. Centralize logic in <code>MediaWiki:Common.js</code> ===
=== 4.3. Centralize logic in <code>MediaWiki:Common.js</code> ===
This ensures:
One place, all dashboards.
 
* all dashboards benefit 
* no per‑page hacks 
* predictable behaviour 


== 5. The Working Code (Common.js) ==
== 5. The Working Code (Common.js) ==
Line 163: Line 121:
* API POST + CSRF token   
* API POST + CSRF token   
* No confirmation dialog   
* No confirmation dialog   
* No user interaction 


=== No loops ===
=== No loops ===
* <code>mw_purged=1</code> is preserved by MediaWiki  
* <code>mw_purged=1</code> is preserved   
* JS sees the marker and does not purge again  
* JS sees the marker and stops  


=== Works for all dashboards ===
=== Works for all dashboards ===
* Uses <code>wgPageName</code>   
* Uses <code>wgPageName</code>   
* No hardcoded page names 


=== Infrastructure‑safe ===
=== Infrastructure‑safe ===
Line 177: Line 133:
* Survives canonical URL rewrites   
* Survives canonical URL rewrites   
* Survives short URLs   
* Survives short URLs   
* Survives caching layers 


=== Successor‑friendly ===
=== Successor‑friendly ===
* One central rule   
* One central rule   
* No per‑page code  
* No per‑page hacks  
* Easy to understand and maintain  
 
== 7. Architecture Diagram ==
 
The following ASCII diagram shows the complete flow from saving a form to the final dashboard refresh.
 
<pre>
                +-----------------------+
                |  User saves form    |
                |  (Page Forms)        |
                +-----------+-----------+
                            |
                            v
                +-----------------------+
                | Page Forms redirect  |
                | to Dashboard:XYZ      |
                +-----------+-----------+
                            |
                            v
                +-----------------------+
                | Dashboard loads      |
                | Common.js executes    |
                +-----------+-----------+
                            |
                            | JS checks:
                            |  - Is this Dashboard:* ?
                            |  - Is mw_purged=1 absent?
                            v
                +-----------------------+
                | Request CSRF token    |
                | via API (GET)        |
                +-----------+-----------+
                            |
                            v
                +-----------------------+
                | Silent purge via API |
                | (POST + token)        |
                +-----------+-----------+
                            |
                            v
                +-----------------------+
                | Reload dashboard with |
                | ?mw_purged=1 marker  |
                +-----------+-----------+
                            |
                            v
                +-----------------------+
                | Dashboard loads fresh |
                | JS sees mw_purged=1  |
                | -> No purge triggered |
                +-----------------------+
</pre>


== 7. Summary ==
== 8. Summary ==


The final solution works because it respects all of MediaWiki’s constraints:
The final solution works because it respects all of MediaWiki’s constraints:
Line 195: Line 200:
* Only <code>mw_*</code> parameters survive reliably   
* Only <code>mw_*</code> parameters survive reliably   


By combining these insights, we achieve a stable, silent, automatic purge mechanism for all dashboards.
This produces a stable, silent, automatic purge mechanism for all dashboards.

Revision as of 21:38, 14 February 2026

ICT: Dashboard Auto‑Purge Architecture

This page documents why dashboards in this wiki require an automatic purge after saving a Page Forms form, why several intuitive approaches fail, and why the final solution works reliably.

1. The Problem

Dashboards such as Dashboard:Place display data stored in Cargo tables. After saving a form, the updated Cargo data does not appear immediately because:

  • Cargo updates are asynchronous
  • MediaWiki caches parser output
  • APCu/object cache may serve stale HTML
  • Reverse proxies may cache responses
  • Page Forms redirects do not trigger a purge

A reliable, automatic purge mechanism is required.

2. Why Simple Solutions Do Not Work

2.1. HTML <meta> refresh

MediaWiki sanitizes <meta> tags, even inside #tag:html. The tag is displayed as text and never executed.

Conclusion: HTML refresh cannot be used.

2.2. Redirecting to ?action=purge

A redirect to ?action=purge always triggers MediaWiki’s confirmation dialog. This dialog cannot be suppressed via GET requests.

Conclusion: GET‑based purge is never silent.

2.3. Page Forms limitations

Page Forms does not provide hooks or callbacks that run after saving. It cannot trigger a purge.

Conclusion: Page Forms cannot be used for purge logic.

2.4. JavaScript redirect loops

Redirecting to ?action=purge causes:

  1. Purge dialog
  2. Page reload
  3. JavaScript fires again
  4. Loop

Conclusion: Redirect‑based purge is unstable.

2.5. Query parameters being stripped

Reverse proxies, skins, and canonical URL rewrites may strip unknown parameters such as ?purged=1. This prevents loop‑detection.

Conclusion: Only parameters MediaWiki preserves can be used.

3. Requirements for a Working Solution

A correct solution must:

  • purge silently
  • avoid loops
  • work for all dashboards
  • survive reverse proxies
  • be centralized
  • be successor‑friendly

4. The Final, Working Solution

4.1. Purge via the MediaWiki API

Silent purge requires:

  • POST request
  • CSRF token
  • API module

4.2. Use a preserved query parameter

MediaWiki never strips parameters beginning with mw_. We use:

?mw_purged=1

4.3. Centralize logic in MediaWiki:Common.js

One place, all dashboards.

5. The Working Code (Common.js)

$(function () {
    const title = mw.config.get('wgPageName');

    if (title && title.startsWith('Dashboard:')) {

        // Only purge once
        if (!location.search.includes('mw_purged=1')) {

            new mw.Api().get({
                action: 'query',
                meta: 'tokens',
                type: 'csrf'
            }).done(function (data) {

                const token = data.query.tokens.csrftoken;

                new mw.Api().post({
                    action: 'purge',
                    titles: title,
                    token: token
                }).always(function () {

                    // Reload the dashboard normally, marked as purged
                    const url = mw.util.getUrl(title, { mw_purged: 1 });
                    location.replace(url);
                });
            });
        }
    }
});

6. Why This Works

Silent purge

  • API POST + CSRF token
  • No confirmation dialog

No loops

  • mw_purged=1 is preserved
  • JS sees the marker and stops

Works for all dashboards

  • Uses wgPageName

Infrastructure‑safe

  • Survives reverse proxies
  • Survives canonical URL rewrites
  • Survives short URLs

Successor‑friendly

  • One central rule
  • No per‑page hacks

7. Architecture Diagram

The following ASCII diagram shows the complete flow from saving a form to the final dashboard refresh.

                +-----------------------+
                |   User saves form     |
                |   (Page Forms)        |
                +-----------+-----------+
                            |
                            v
                +-----------------------+
                | Page Forms redirect   |
                | to Dashboard:XYZ      |
                +-----------+-----------+
                            |
                            v
                +-----------------------+
                | Dashboard loads       |
                | Common.js executes    |
                +-----------+-----------+
                            |
                            | JS checks:
                            |   - Is this Dashboard:* ?
                            |   - Is mw_purged=1 absent?
                            v
                +-----------------------+
                | Request CSRF token    |
                | via API (GET)         |
                +-----------+-----------+
                            |
                            v
                +-----------------------+
                | Silent purge via API  |
                | (POST + token)        |
                +-----------+-----------+
                            |
                            v
                +-----------------------+
                | Reload dashboard with |
                | ?mw_purged=1 marker   |
                +-----------+-----------+
                            |
                            v
                +-----------------------+
                | Dashboard loads fresh |
                | JS sees mw_purged=1   |
                | -> No purge triggered |
                +-----------------------+

8. Summary

The final solution works because it respects all of MediaWiki’s constraints:

  • Purge must be done via API POST
  • CSRF token is required
  • GET purge always shows a dialog
  • Page Forms cannot trigger purge
  • Unknown query parameters may be stripped
  • Only mw_* parameters survive reliably

This produces a stable, silent, automatic purge mechanism for all dashboards.