Skip to content

Redesign how game systems and the Foundry module update: automatic, pinned, or approve-first #685

Open
1 of 3 issues completed

Description

@keyxmakerx

AutoPinOnInstall already reads each campaign's pin mode: only 'preserve' freezes a campaign at its previous version when a new module version installs, so the default empty mode and 'promote' both leave the campaign tracking the latest installed version — the 'Auto-update (track latest installed)' label is already true for every campaign. A writer (campaigns.SetFoundryModulePinMode) and a validator (foundry_vtt.IsValidPinMode) already exist for that mode, but no route or UI control calls the writer, so no campaign can actually be put into 'preserve' mode today. What's left is a small UI control (and a route, if one doesn't already reach the setter) so an owner can choose 'preserve', or closing this issue if that option isn't wanted.

Decided (2026-09-23): option B. The label promises "track latest", so the behaviour should do that; keep "preserve" as the second, explicitly named mode.

References: keyxmakerx/Cordinator#21, Cordinator reports/chronicle/2026-05-20-c-updater-cluster.md, internal/plugins/foundry_vtt/owner_tab.templ:161

Where this came from
  • Cordinator/plans/BACKLOG.md line 761 — Open bug queue > C-UPDATER-CLUSTER item 21 — operator decision needed
    • Checked against main on 2026-09-23: internal/plugins/foundry_vtt/owner_tab.templ:161 still shows 'Auto-update (track latest installed)'; pin_mode.go stores preserve/promote/pinned (Chunk 1) but service.go:35-41 says AutoPinOnInstall still follows preserve-state regardless of pin_mode (Chunk 2 held since 2026-05-20).

Old tracking IDs (so a search for them lands here): C-FMC-6, C-FMC-CHUNK-2, C-UPDATER-CLUSTER

Activity

  1. keyxmakerx commented on Sep 25, 2026

    @keyxmakerx
    OwnerAuthor

    Checked against main on 2026-09-25 while cleaning up comments. The description above is out of date:

    • AutoPinOnInstall already reads the pin mode. Only "preserve" freezes a campaign at the previous version. An empty mode (the default) or "promote" does nothing, so the campaign keeps tracking the latest installed version. The "Auto-update (track latest installed)" label is therefore already true for every campaign.
    • What's missing is a way to choose "preserve". The mode has a writer, campaigns.SetFoundryModulePinMode (through foundryCampaignSettingsAdapter in internal/app/routes.go), and a validator, foundry_vtt.IsValidPinMode, but no route or control calls either. Nothing in the product can set it today.

    So option B has shipped on the server side. What's left is a small UI control plus a route if the operator wants "preserve" to be selectable, or closing this issue if not.


    Generated by Claude Code

  2. keyxmakerx commented on Sep 25, 2026

    @keyxmakerx
    OwnerAuthor

    Decided 2026-09-25 on the sign-off page. Redesign the whole update flow instead of adding a second dropdown to today's card. It's part of the admin redesign (#681, item A2).

    The operator's requirements:

    • It covers game-system packages and the Foundry module alike.
    • Admins and campaign owners can each choose one of three ways:
      • follow the newest version automatically;
      • stay on a chosen version;
      • approve each update before it applies.
    • A complete overhaul is fine as long as no current function is lost.

    It needs a new mockup before building.


    Generated by Claude Code

  3. changed the title [-]Make 'Auto-update' pinning actually move campaigns to new versions[/-] [+]Redesign how game systems and the Foundry module update: automatic, pinned, or approve-first[/+] on Sep 25, 2026
  4. keyxmakerx commented on Sep 25, 2026

    @keyxmakerx
    OwnerAuthor

    Signed 2026-09-25 on the sign-off page (card "ui-685", version 3). Part of the admin redesign #681, item A2.

    What was approved

    • One update setting for game-system packages and the Foundry module alike. Admins set it per package and campaign owners per campaign.
    • The three choices: automatic, pinned to a version, or approve first.
    • The admin view shows which campaigns are on which version and mode, with notify, force and approve actions. It also flags unused versions and handles long package lists.
    • Cleanup of unused versions stays game-systems-only. Foundry module versions are never removed, since a campaign may be pinned to an old one.
    • No current function is lost. The mockup lists every function of today's screens and where it goes.
    • Default confirmed: a package with auto-update off and no pin becomes "pinned to its current version".

    Build, in order: #755 (server), #756 (admin views), #757 (campaign Settings → Updates). Each ships as its own PR built to this mockup. The mockup's HTML is below so the contract outlives the sign-off page.

    Signed mockup (HTML: Today, Admin · package detail, Admin · package list at scale, Campaign owner)
    <div class="mk mk-685">
    <style>
    .mk-685{font-family:inherit;color:var(--c-body);background:var(--c-page);padding:1rem;border-radius:.6rem}
    .mk-685 *{box-sizing:border-box}
    .mk-685-row{display:flex;flex-wrap:wrap;gap:1rem}
    .mk-685-panel{flex:1 1 320px;max-width:440px;min-width:260px}
    .mk-685-label{font-size:.7rem;font-weight:700;letter-spacing:.06em;text-transform:uppercase;color:var(--c-muted);margin:0 0 .35rem}
    .mk-685-sub{font-size:.72rem;color:var(--c-muted);margin:0 0 .6rem;line-height:1.4}
    .mk-685-card{background:var(--c-surface);border:1px solid var(--c-border);border-radius:.6rem;padding:.8rem .9rem;margin-bottom:.6rem}
    .mk-685-card:last-child{margin-bottom:0}
    .mk-685-flat{background:transparent;border:none;padding:0 .1rem}
    .mk-685-head{display:flex;align-items:flex-start;gap:.5rem;margin-bottom:.45rem}
    .mk-685-ic{width:1.55rem;height:1.55rem;border-radius:.4rem;background:var(--c-accent-soft);display:flex;align-items:center;justify-content:center;font-size:.75rem;flex:none}
    .mk-685-nm{font-size:.8rem;font-weight:700;color:var(--c-text);display:flex;align-items:center;gap:.35rem;flex-wrap:wrap;line-height:1.3}
    .mk-685-meta{font-size:.68rem;color:var(--c-muted);margin-top:.15rem;line-height:1.4}
    .mk-685-meta b{color:var(--c-text)}
    .mk-685-good{color:var(--c-success)}
    .mk-685-chip{display:inline-flex;align-items:center;gap:.2rem;font-size:.58rem;font-weight:700;padding:.1rem .4rem;border-radius:999px;border:1px solid var(--c-border);color:var(--c-muted);white-space:nowrap}
    .mk-685-chip-type{border-color:transparent;background:var(--c-accent-soft);color:var(--c-accent)}
    .mk-685-field{display:flex;align-items:center;gap:.45rem;font-size:.7rem;margin-top:.4rem;flex-wrap:wrap}
    .mk-685-fl{color:var(--c-muted);font-size:.62rem;text-transform:uppercase;letter-spacing:.03em;flex:none}
    .mk-685-select{font:inherit;font-size:.7rem;border:1px solid var(--c-border);background:var(--c-page);color:var(--c-body);border-radius:.4rem;padding:.28rem .45rem}
    .mk-685-modes{display:flex;gap:.2rem;background:var(--c-page);border:1px solid var(--c-border);border-radius:999px;padding:.2rem;margin-top:.5rem}
    .mk-685-modes span{flex:1;text-align:center;font-size:.64rem;font-weight:700;padding:.3rem .15rem;border-radius:999px;color:var(--c-muted)}
    .mk-685-modes .on{background:var(--c-accent-soft);color:var(--c-accent)}
    .mk-685-hint{font-size:.68rem;color:var(--c-muted);line-height:1.5;margin:.5rem 0 0}
    .mk-685-hint em{font-style:normal;font-weight:700;color:var(--c-text)}
    .mk-685-queue{display:flex;align-items:center;gap:.5rem;background:var(--c-page);border:1px dashed var(--c-warn);border-radius:.5rem;padding:.4rem .55rem;margin-top:.5rem;font-size:.68rem;color:var(--c-text)}
    .mk-685-queue span:first-child{flex:1}
    .mk-685-lk{font-size:.64rem;font-weight:700;color:var(--c-accent);white-space:nowrap}
    .mk-685-lk.mut{color:var(--c-muted)}
    .mk-685-crumb{font-size:.68rem;font-weight:700;color:var(--c-muted);margin:0 0 .5rem}
    .mk-685-crumb b{color:var(--c-text)}
    
    .mk-685-go{color:var(--c-success);border-color:var(--c-success)}
    .mk-685-at{color:var(--c-warn);border-color:var(--c-warn)}
    .mk-685-ac{color:var(--c-accent);border-color:var(--c-accent);background:var(--c-accent-soft)}
    .mk-685-dash{border-style:dashed}
    .mk-685-dg{color:var(--c-danger)}
    .mk-685-crow{display:flex;align-items:center;gap:.5rem;padding:.35rem 0;border-top:1px solid var(--c-border);font-size:.72rem}
    .mk-685-crow:first-child{border-top:none}
    .mk-685-crow b{flex:1;min-width:0;color:var(--c-text);font-weight:600;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
    .mk-685-mono{font-family:ui-monospace,Consolas,monospace;color:var(--c-muted);font-size:.68rem;white-space:nowrap}
    .mk-685-vchips{display:flex;gap:.3rem;flex-wrap:wrap;margin:.4rem 0}
    .mk-685-search{font:inherit;font-size:.7rem;border:1px solid var(--c-border);background:var(--c-page);color:var(--c-muted);border-radius:.4rem;padding:.32rem .5rem;width:100%;display:block;margin-bottom:.5rem}
    .mk-685-lk:hover{color:var(--c-accent-hover)}
    </style>
    
    <div class="mk-685-row">
    
    <div class="mk-685-panel">
        <p class="mk-685-label">Today</p>
        <p class="mk-685-sub">Three unrelated controls, one of them half-built (#685), and campaign owners get no say over their game system's version at all.</p>
    
        <div class="mk-685-card">
          <div class="mk-685-head"><span class="mk-685-ic">&#128737;</span><div><div class="mk-685-nm">Draw Steel <span class="mk-685-chip mk-685-chip-type">Game System</span></div><div class="mk-685-meta">installed <b>0.13.10</b> &middot; admin-only, one setting for every campaign</div></div></div>
          <div class="mk-685-field"><span class="mk-685-fl">Auto-update</span><select class="mk-685-select" disabled><option>off</option></select></div>
          <div class="mk-685-field"><span class="mk-685-fl">Pin</span><span class="mk-685-chip">none set &middot; a separate control, inside Versions</span></div>
          <p class="mk-685-hint">Latest (<b>0.13.11</b>) already exists. Nothing on this card says so &mdash; finding out means opening Versions and comparing by eye.</p>
        </div>
    
        <div class="mk-685-card">
          <div class="mk-685-head"><span class="mk-685-ic">&#127922;</span><div><div class="mk-685-nm">Chronicle Sync <span class="mk-685-chip mk-685-chip-type">Foundry Module</span></div><div class="mk-685-meta">Campaign Settings &rsaquo; VTT Setup Guides &rsaquo; Foundry VTT</div></div></div>
          <div class="mk-685-field"><span class="mk-685-fl">Pin to Version</span><select class="mk-685-select" disabled><option>Auto-update (track latest installed)</option></select></div>
          <p class="mk-685-hint">One dropdown, two real states. A third &mdash; <em>keep serving my current version even after the admin installs a new one</em> &mdash; already exists in the database and has no control to turn it on.</p>
        </div>
    
        <div class="mk-685-card mk-685-flat">
          <p class="mk-685-hint"><em>Game system, campaign side:</em> Settings only offers <em>which</em> system &mdash; Draw Steel, D&amp;D 5e, custom&hellip; Which version it runs is entirely the admin's call. No control exists here at all.</p>
        </div>
      </div>
    
    <div class="mk-685-panel">
    <p class="mk-685-label">Proposed &middot; Admin &middot; one package in detail</p>
    <p class="mk-685-sub">Draw Steel opened up: every campaign&rsquo;s mode and version, what&rsquo;s waiting for an OK, and the actions that reach them.</p>
    
    <div class="mk-685-card">
    <div class="mk-685-head"><span class="mk-685-ic">&#128737;</span><div><div class="mk-685-nm">Draw Steel <span class="mk-685-chip mk-685-chip-type">Game System</span></div><div class="mk-685-meta">installed <b>0.13.10</b> &middot; latest <b class="mk-685-good">0.13.12 &#10003;</b> &middot; 5 campaigns</div></div></div>
    
    <div class="mk-685-crow"><b>The Sunken Crown</b><span class="mk-685-chip mk-685-go">Auto</span><span class="mk-685-mono">0.13.12</span></div>
    <div class="mk-685-crow"><b>The Ninth Bastion</b><span class="mk-685-chip mk-685-go">Auto</span><span class="mk-685-mono">0.13.12</span></div>
    <div class="mk-685-crow"><b>Vasloria by Night</b><span class="mk-685-chip mk-685-at">Pinned</span><span class="mk-685-mono">0.13.10</span></div>
    <div class="mk-685-crow"><b>Grim Harvest</b><span class="mk-685-chip mk-685-ac">Approve first</span><span class="mk-685-mono">0.13.9</span></div>
    <div class="mk-685-crow"><b>Old Campaign (archived-ish)</b><span class="mk-685-chip mk-685-at">Pinned</span><span class="mk-685-mono">0.13.9</span></div>
    
    <div class="mk-685-queue"><span><b>Grim Harvest</b> is waiting on <b>0.13.12</b></span><span class="mk-685-lk">Approve</span><span class="mk-685-lk mut">Skip</span></div>
    
    <p class="mk-685-hint"><em>Admin actions:</em> Notify owners still behind &middot; Force a version, one campaign or every older one at once &#128274; &middot; Approve on their behalf. Notify and Force-a-version are today&rsquo;s Foundry-only actions, now working for a system too; Approve calls that same Force-pin &mdash; there&rsquo;s no separate &ldquo;approve&rdquo; endpoint underneath it.</p>
    </div>
    </div>
    
    <div class="mk-685-panel">
    <p class="mk-685-label">Proposed &middot; Admin &middot; package list at scale</p>
    <p class="mk-685-sub">Many packages, many versions &mdash; unused ones marked, and pruning still only ever touches game systems.</p>
    
    <input type="text" class="mk-685-search" disabled placeholder="Filter packages&hellip;"/>
    <div class="mk-685-vchips">
    <span class="mk-685-chip mk-685-ac">All &middot; 3</span><span class="mk-685-chip">Systems &middot; 2</span><span class="mk-685-chip">Foundry Module &middot; 1</span><span class="mk-685-chip mk-685-at">Has unused &middot; 2</span>
    </div>
    
    <div class="mk-685-card">
    <div class="mk-685-head"><span class="mk-685-ic">&#128737;</span><div><div class="mk-685-nm">Draw Steel</div><div class="mk-685-meta">5 versions on disk &middot; 5 campaigns</div></div><span class="mk-685-chip mk-685-at">2 unused</span></div>
    <div class="mk-685-vchips">
    <span class="mk-685-chip mk-685-at mk-685-dash">0.13.8</span><span class="mk-685-chip mk-685-go">0.13.9 served</span><span class="mk-685-chip mk-685-go">0.13.10 served</span><span class="mk-685-chip mk-685-at mk-685-dash">0.13.11</span><span class="mk-685-chip mk-685-go">0.13.12 newest</span>
    </div>
    </div>
    
    <div class="mk-685-card">
    <div class="mk-685-head"><span class="mk-685-ic">&#128214;</span><div><div class="mk-685-nm">D&amp;D 5e</div><div class="mk-685-meta">3 versions, collapsed &middot; 2.1.0 unused &middot; 2 campaigns</div></div><span class="mk-685-chip mk-685-at">1 unused</span></div>
    </div>
    
    <div class="mk-685-card">
    <div class="mk-685-head"><span class="mk-685-ic">&#127922;</span><div><div class="mk-685-nm">Chronicle Sync <span class="mk-685-chip mk-685-chip-type">Foundry Module</span></div><div class="mk-685-meta">4 versions, collapsed &middot; 5 campaigns</div></div><span class="mk-685-chip mk-685-go">kept, never pruned</span></div>
    <p class="mk-685-hint">Module folders are never reclaimed &mdash; a campaign can pin to any past release, so every version installed here stays on disk on purpose.</p>
    </div>
    
    <div class="mk-685-queue"><span>Prune <b>3 unused versions</b>, reclaiming <b>~38 MB</b>? The newest, installed, and currently-served version of each system stays &mdash; nothing any campaign uses is touched.</span><span class="mk-685-lk mk-685-dg">Prune</span></div>
    </div>
    
    <div class="mk-685-panel">
    <p class="mk-685-label">Proposed &middot; Campaign owner</p>
    <p class="mk-685-sub">The same three-way choice, now covering the game system too &mdash; including a waiting update, and a pin that&rsquo;s starting to look neglected.</p>
    
    <p class="mk-685-crumb"><b>Grim Harvest</b> &rsaquo; Settings &rsaquo; Updates</p>
    <div class="mk-685-card">
    <div class="mk-685-head"><span class="mk-685-ic">&#128737;</span><div><div class="mk-685-nm">Game System</div><div class="mk-685-meta">Draw Steel &middot; serving <b>0.13.9</b></div></div></div>
    <div class="mk-685-modes"><span>Auto</span><span>Pinned</span><span class="on">Approve first</span></div>
    <div class="mk-685-queue"><span><b>0.13.12</b> is waiting for your OK</span><span class="mk-685-lk">Approve</span><span class="mk-685-lk mut">Skip</span></div>
    </div>
    
    <p class="mk-685-crumb"><b>Old Campaign</b> &rsaquo; Settings &rsaquo; Updates</p>
    <div class="mk-685-card">
    <div class="mk-685-head"><span class="mk-685-ic">&#128737;</span><div><div class="mk-685-nm">Game System</div><div class="mk-685-meta">Draw Steel &middot; serving <b>0.13.9</b></div></div></div>
    <div class="mk-685-modes"><span>Auto</span><span class="on">Pinned</span><span>Approve first</span></div>
    <div class="mk-685-queue"><span>Once Grim Harvest takes its update, you&rsquo;re the only campaign left on 0.13.9 &mdash; not the newest, so a future cleanup could reclaim it.</span></div>
    
    <div class="mk-685-head" style="margin-top:.55rem"><span class="mk-685-ic">&#127922;</span><div><div class="mk-685-nm">Foundry Module</div><div class="mk-685-meta">Chronicle Sync &middot; serving <b>0.9.2</b></div></div></div>
    <div class="mk-685-modes"><span>Auto</span><span class="on">Pinned</span><span>Approve first</span></div>
    <div class="mk-685-queue mk-685-go"><span>Old module versions are never cleaned up automatically &mdash; 0.9.2 stays however long you&rsquo;re pinned to it.</span></div>
    </div>
    </div>
    
    </div>
    </div>

    Generated by Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions