# Roadmap XIV Vault is a Windows-first backup and restore utility for the portable XIVLauncher / Dalamud configuration, with a CLI and an Avalonia desktop app on one shared engine. This file tracks what gets built, in what order, and the decisions already made. ## Decisions (2026-10-04) - **Stack:** .NET 10 (LTS), C#, Avalonia 12 with CommunityToolkit.Mvvm, Spectre.Console.Cli, System.Text.Json source generation, xUnit v3 on Microsoft.Testing.Platform. Microsoft.Extensions DI and logging abstractions are the only other dependencies. - **One engine.** All behavior lives in `XivVault.Core`. The CLI and the desktop app only present it, and both wire it up with `AddXivVaultCore()`. - **License:** Apache-2.0. - **Backup format:** a normal ZIP with `manifest.json` and a `payload/` folder. The manifest is versioned (`schemaVersion: 1`), lists every file with its SHA-256 and is the only source of metadata. The file name is not trusted. - **Allowlist:** `pluginConfigs/`, `dalamudConfig.json`, `dalamudVfs.db`, and `dalamudUI.ini` when the user opts in. Temporary files and `logs`/`cache` folders inside `pluginConfigs/` are skipped, and links are not followed. Nothing else is ever read. - **Backups are atomic.** The archive is written as `*.zip.tmp`, closed, re-read and hash-checked, then renamed. Retention runs only after that rename. - **Restore never deletes.** A plugin config that exists now but not in the backup stays. Each file is replaced through a temp file and a rename. If anything fails mid-restore, the files already replaced are put back from a local copy and the restore reports failure. - **Safety snapshots** are `pre-restore-*.zip` files in the backup destination, shown in Backups as Pre-Restore. They always include `dalamudUI.ini` when it exists, because a restore may replace it. The newest 3 are kept, separately from the regular retention count. - **Restore targets need XIVLauncher, not Dalamud config.** A fresh PC that has only run XIVLauncher is a valid restore target. Backups need at least one portable item to exist. - **Scheduling** uses Windows Task Scheduler (`schtasks /create /xml`) with one task, `XIV Vault Scheduled Backup`, running as the current user with least privilege. Turning automatic backups off removes the task and keeps the preferences. XIV Vault computes the next run itself and the scheduled run records its own result, so nothing depends on the locale of `schtasks` output. - **The task runs the app that created it.** The desktop app registers itself with `--scheduled-backup` and runs without a window. The CLI registers `xiv-vault backup --scheduled`. - **Scheduled backups wait for FFXIV to close** (checking every minute, for up to 6 hours) instead of copying a database the game has open. Manual backups run at once. - **Integrity state** is cached per archive (path, size, modified time) in `%LOCALAPPDATA%\XIV Vault\state.json`. Archives that were never verified on this PC are verified in the background when listed. - **Default destination:** `%OneDrive%\XIV Vault` when OneDrive is set up, otherwise `Documents\XIV Vault`. - **UI** implements the Claude Design "XIV Vault" mockup, built on the Quorum design system with XIV Vault's overrides: IBM Plex Sans and Mono, accent `#6C9EFF`, healthy `#3CD5DE`. Dark only, like the mockup. Fonts are bundled TTFs (OFL) and icons are Lucide paths (ISC) compiled into the app, so nothing loads from a CDN. - **The mockup's sample values are not used.** Version is 0.1.0, not the mockup's 1.4.0, and every number on screen comes from `XivVault.Core`. - **Compression** follows the mockup: Fast, Balanced (default) and Maximum map to the .NET `CompressionLevel` values. - **Name:** the product is **XIV Vault**, and every name follows it, since nothing had been released yet. `xiv-vault` for the repository, the command, archives, release zips and logs; `XivVault` for projects, namespaces and assemblies, which keeps resource URIs free of spaces; `XIV Vault` for folders: `%LOCALAPPDATA%\XIV Vault` and the default `OneDrive\XIV Vault` backup folder. The manifest field is `xivVaultVersion` and the override variable is `XIV_VAULT_DATA_DIR`. - **Brand:** the diamond from the mockup's title bar. The wordmark, "XIV Vault", is IBM Plex Sans SemiBold converted to paths by `scripts/make-lockup.mjs`. Assets are in `docs/brand/`, and `scripts/make-icons.cs` builds `xiv-vault.ico` from `app-icon.svg`. - **Screenshots** come from `tools/XivVault.Screenshots`, which renders the real views with Avalonia's headless Skia renderer against a fake XIVLauncher folder and a fake Task Scheduler. It is also how the UI was checked against the mockup. - **Fresh-PC states** that the mockup doesn't cover follow its patterns: "Setting up a new PC?" (XIVLauncher present, no Dalamud settings) leads to Restore, and "XIVLauncher not found" leads to Settings. The restore wizard also accepts a backup file picked from anywhere. - **Restore steps:** the review screen compares the backup with this PC and warns when plugins changed after the backup. The live restore runs inside step 3, as in the mockup, with stages in the order the engine runs them: verify, snapshot, plugin configs, Dalamud settings. ## Decisions (2026-10-04, after review) An independent review of the restore and validation code found failure modes; these rules close them. - **Links are refused.** Backups don't follow junctions or symlinks inside the XIVLauncher folder, so a restore refuses to write through one, and Diagnostics warns when `pluginConfigs` is a link. - **The archive being restored is untouchable.** It stays open, read-shared only, for the whole restore. Snapshot retention runs after the restore and never removes the new snapshot or that archive. - **Retention counts only verified backups.** Before deleting anything it verifies archives this PC hasn't checked, so a backup damaged after it was written never takes the place of a good one. - **One operation at a time.** A named mutex per data folder serializes backups, restores and retention between the app, the CLI and the scheduled task. - **Manifests must describe their files.** `contents` and `statistics` have to match the file list; paths that backups skip (`logs`, `cache`, temp files) are refused; archives are capped at 2 GB and 100,000 files, with sizes bounded before they are summed. ## Decisions (2026-10-05, installer and updates) - **Installer:** the desktop app also ships as `xiv-vault-setup-win-x64.exe`, built with Velopack (MIT) by `release.yml`. It installs per user into `%LOCALAPPDATA%\XivVault` with a Start menu shortcut and no administrator prompt. Settings, state and logs stay in `%LOCALAPPDATA%\XIV Vault`, so uninstalling keeps them. The desktop zip stays as a portable copy that doesn't update. The CLI stays a zip; winget remains the way to update it. - **The update check is on by default**, with a switch in Settings. It reads the public release list from GitHub and sends nothing about the user or their backups. It is the only network call XIV Vault makes, and the README's safety model says so. Portable copies never check. - **Updates install only when the user chooses**, with Update and Restart in Settings; the sidebar shows when one is available. Installing ends every copy running from the install folder, so an update waits while a backup or restore runs anywhere, or while another copy (such as a scheduled backup) is open. Downloaded updates are never applied at startup, so a scheduled run never replaces its own program. - **Uninstalling removes the scheduled task** when it starts the installed copy, and keeps the schedule preferences. - **Desktop executable:** `XIV-Vault.exe`. The assembly stays `XivVault`, because .NET compares assembly names without case and the tests load the app and the CLI (`xiv-vault`) together; publishing renames the single-file exe. The CLI stays `xiv-vault.exe`. Windows treats the two as the same file name, so they ship in separate zips and the README says to keep them in separate folders. "Another copy is running" matches processes by path, so a CLI command never holds up an update. - **Release assets:** Setup, this version's full (and, from the second release on, delta) update package and `releases.win.json` join the two zips. `SHA256SUMS` covers Setup and the zips. ## Decisions (2026-10-05, road to 1.0) - **v0.1.0 is published.** From here on, every release must update cleanly from the one before it. - **1.0 means safe to trust and stable to build on:** proven on real setups other than the author's, compatibility promises written down (0.1.0 backups always restore; the CLI, its JSON output and exit codes stay stable), and updates proven across releases. - **Restoring only some plugins is part of 1.0.** It removes the biggest limitation of a restore, which today returns every plugin in the backup to its old settings. - **Synced folders are the main case to harden.** Listing backups opens every archive, and verification reads each one in full, so on a new PC with OneDrive Files On-Demand, opening XIV Vault downloads every backup. - **Code signing waits until after 1.0**, once there is an established userbase. Until then SmartScreen asks users to confirm Setup and the zips, and the README says so. (Changed on 2026-10-10: signing comes first in M10.) ## Decisions (2026-10-06, game settings) - **Game settings are part of 1.0.** XIV Vault also backs up the game's own settings from `Documents\My Games\FINAL FANTASY XIV - A Realm Reborn`: HUD layout, hotbars, keybinds, macros and gear sets, which are what people lose on a new PC. The folder is found through Documents, so a Documents folder that OneDrive has moved is followed. They come before 1.0 because 1.0 writes the backup format down as stable. - **Game allowlist:** `MACROSYS.dat`, the `FFXIV_CHARA_*.dat` appearance saves, and the `.DAT` files directly inside each `FFXIV_CHR*` character folder, matched by extension so a file added by a game patch is not silently missed. `FFXIV.cfg` only when the user opts in, because it holds resolution, monitor and window mode that may not suit another PC (changed on 2026-10-09: always backed up, chosen at restore). Never `log/` (chat logs), `screenshots/`, `cfgcopy/`, `*.old` or `FFXIV_BOOT.cfg`. The files are copied byte for byte and never parsed. - **Character folders are named by a content ID that identifies the character.** Logs, Diagnostics and the UI never show it; they count characters. A restore writes each character's files back to the folder with the same name, never to another character, and a character folder the backup doesn't contain stays. - **Backup format:** game files go under `payload/game/`, and the manifest moves to `schemaVersion: 2` with a `contents` flag for them. Version 1 backups still restore, and older XIV Vault versions refuse version 2 with their existing "made by a newer XIV Vault" message. - **The same guards as Dalamud settings.** The safety snapshot holds every game file a restore would replace, a restore refuses while the game runs (it rewrites these files on logout), and a failed restore puts back what it replaced in both folders. ## Decisions (2026-10-07, fresh PC and synced folders) - **Cloud-only files are recognized by their Windows attributes,** which can be read without downloading the file. Listing shows their name, size and the date in their file name; manifests are read only from files already on this PC. The name is for display only: a restore still trusts nothing but the manifest, read after the download. - **Verification is on demand.** XIV Vault verifies the latest backup when it is on this PC and the backup being restored, not every archive in the folder. `xiv-vault list --verify` still checks them all. - **Retention never downloads.** It verifies archives on this PC as before. A cloud-only archive this PC hasn't verified doesn't count toward the limit, and once enough newer verified backups exist it is deleted without being opened. Archives known to be damaged are still left for the user to inspect. - **Layouts users report** are handled as they arrive, in patch releases, rather than as an M8 item. - **Google Drive for desktop doesn't mark online-only files.** Every file in `G:\My Drive` reads as a normal file whether it is on this PC or not, so XIV Vault treats backups there as local: on a new PC it reads each manifest and verifies the latest in full. That is still far less than 0.1.2, which read every backup, and it is accepted for 0.2. Found on the author's setup. ## Decisions (2026-10-08, restoring some plugins) - **A restore takes a selection:** the plugins to restore, and Dalamud settings as one separate choice (`dalamudConfig.json`, `dalamudVfs.db` and `dalamudUI.ini`). Only the chosen files are written. A plugin's settings are its `.json` file and its folder together. The whole archive is still validated, and the safety snapshot still holds everything a full restore would replace. - **Everything is chosen when the review step opens,** so a full restore stays one click. - **The checklist lives in the review step.** The plugin line in "In this backup" opens into a checklist with a filter and Select all / none. Continue is unavailable while nothing is chosen. - **On the command line,** `--plugin ` (repeatable) and `--dalamud-settings` choose what to restore. With either option only what they name is restored; with neither, everything is. A plugin the backup doesn't hold is an argument error (exit code 2). ## Decisions (2026-10-09, game settings on a new PC) - **The game keeps files restored before its first start.** Checked on the author's PC: with the game folder set aside and only a default restore's files put back, the game used the restored character folder, and the HUD, hotbars, keybinds, macros and gear sets came back without a server download. A restore creates the game folder and character folders itself; nobody has to start the game first. - **Without `FFXIV.cfg` the game starts from defaults:** controller calibration, graphics, window theme colors and sound settings such as mount music. - **`FFXIV.cfg` is always backed up and chosen at restore,** replacing the opt-in from 2026-10-06. Square Enix's own server backups are manual and easy to forget, so XIV Vault may hold the only copy. It is its own choice in the restore review step and in `xiv-vault restore`, chosen by default like everything else, so someone on a PC with a different monitor can leave it out. ## Decisions (2026-10-10, code signing) - **Signing comes first in M10,** so 0.4 is the first signed release. It no longer waits for 1.0: a Public Trust certificate from Azure Artifact Signing, publisher Hazel Granados, already exists. - **No secrets.** The release workflow signs in to Azure with GitHub's OIDC token. Only tag builds, which run in the `release` environment, can sign; the account and certificate profile names are variables of that environment, not part of the workflow. Manual runs and forks build unsigned. - **Everything Windows runs is signed.** Both exes are signed right after publishing, so the zips and the update packages carry signed copies; `vpk pack` then signs Setup and its own files and skips what is already signed. The build fails if a signature doesn't verify. - **SmartScreen still warns** about a newly signed Setup until downloads build reputation. It then names the publisher instead of "Unknown publisher". ## Decisions (2026-10-10, naming the game choices) - **Character settings and system settings,** as the game's own menus call them (Character Configuration, System Configuration). Character settings are each character's folder with the shared macros and appearance saves; system settings are `FFXIV.cfg`. "Game settings" covers both: the switch in Settings and the Diagnostics group use it. - **The same names everywhere:** `--character-settings` and `--system-settings` for `xiv-vault restore`, `characterSettings` and `systemSettings` in the manifest's `contents`, and the restore review's choices. Format version 2 was not released yet, so its fields changed with them. ## Decisions (2026-10-10, before 1.0) - **A failed scheduled backup shows a Windows notification.** Scheduled backups run without a window, so today a failing schedule is only visible when someone opens the app. A backup tool that can fail unnoticed isn't safe to trust. - **Steam Deck support comes after 1.0.** XIVLauncher.Core, native or Flatpak, keeps the same Dalamud files in `~/.xlcore` and the game's settings in `~/.xlcore/ffxivConfig`, so the backup format and commands need no change and nothing 1.0 makes stable depends on it. It needs Linux builds, a systemd timer for scheduling, and a real Deck to prove the running-game check sees FFXIV under Wine. ## Decisions (2026-10-11, website and user guide) - **1.0 launches with a website and a user guide:** a static site in `site/` on GitHub Pages at hazeliscoding.github.io/xiv-vault. Plain HTML and CSS, nothing loaded from another site, and no analytics or trackers, as on Prompuff's site. - **Shaped like XIVLauncher's own page, not copied from it.** goatcorp.github.io is one column of short sections, each answering a question someone has: download, why, install, Steam Deck, plugins, help, safety, plugin API, disclaimer. XIV Vault's site follows that pattern with its own brand, words and screenshots. - **Written for the plugin and modding community and open-source developers, not as a sales pitch.** It has Prompuff's level of craft without the product-page pitch. It says plainly what XIV Vault reads and never reads, how a restore stays safe, the backup format, the CLI with its JSON output and exit codes, and the license. A section for plugin developers explains what a backup and restore do to their plugin's files in `pluginConfigs`. - **The user guide is a page of the website,** organized by task and checked against the app's screens: the first backup, a schedule, a restore on a new PC, restoring some plugins, and the CLI. - **Screenshots come from `tools/XivVault.Screenshots`,** so no real path or content ID reaches the site. - **A disclaimer** says XIV Vault is not affiliated with Square Enix or with goatcorp's XIVLauncher and Dalamud. - **The site signs off with "Made with ♥ by hazeliscoding",** linking to the repository. ## Decisions (2026-10-11, building the website) - **The site inherits the app's world:** its tokens, dark ground, IBM Plex and the diamond mark. No `PRODUCT.md` or `DESIGN.md`; the website decisions above are the brief. - **The first screen is the demo:** the headline, Download for Windows and the guide, then the README's backup-and-restore tour as a looping video at about the app's own size. It stays still for people who ask for less motion and has a pause button. - **What it backs up is shown as the two folders,** item by item, with what is never touched, because that is what the modding community asks first. - **Screenshots, the demo and the social preview come from `docs/screenshots` at deploy time** (`scripts/stage-site.sh`), so the site never shows older pictures than the README. Only the fonts are copied into `site/`, as Latin WOFF2 subsets of the app's own. ## Decisions (2026-10-11, failure notifications) - **Core calls WinRT directly** for the notification, through about 80 lines of function-pointer interop, instead of targeting `net10.0-windows`. Microsoft's projection would add about 25 MB to each exe and make the projects Windows-only, which the Linux work would have to undo. The interfaces and their method order were read from Windows' own metadata. - **XIV Vault registers its own app ID,** `hazeliscoding.XIVVault`, under `HKCU\Software\Classes\AppUserModelId` with its name and icon, so Setup, portable copies and the CLI notify alike without a Start menu shortcut. The icon is written next to the config, since a single-file exe has no file to point at. - **Only failures notify,** with fixed words and no path or error text, because a notification can appear on a stream. A backup skipped because the game stayed open doesn't notify; Schedule shows it. - **A notification never fails the run.** The result is recorded first, and an error showing it is only logged. ## Decisions (2026-10-11, the 1.0 promise) - **Backups restore forever.** Every archive any version made restores in every later version, major versions included. A major version may change the command line, but never this. - **Scheduled tasks survive updates,** major versions included: `XIV-Vault.exe --scheduled-backup` and `xiv-vault backup --scheduled` stay, so a schedule set up once keeps running. - **The command line is stable through 1.x:** commands, options, `config set` keys, exit codes, JSON fields and the listed JSON values. New ones may be added. Wording isn't promised, including the JSON fields that hold it (`message`, `problem`, `attentionReason`, `summary`, `title`, `label`, `detail`). - **One fix before the promise:** `schedule status --json` wrote days as `"Sunday"` while every other JSON value is camelCase, so it now writes `"sunday"`. - **The promise is written in `docs/cli.md`,** with the README's Stability section in short. `CliContractTests` pins every JSON field and the exit codes, so a rename fails a test. ## Decisions (2026-10-11, accessibility) - **Text3 is lighter than the mockup,** `#838F9E` instead of `#5F6B7A`, which read at 3:1 where WCAG AA asks 4.5:1 for text. It keeps the hue and stays dimmer than Text2. Field and select borders take the old Text3 so empty fields reach 3:1, and the dash beside something not chosen uses Text3 instead of Text4. Text4 is no longer used for text. - **The check is automated where it can be.** `XivVault.Screenshots --a11y` tabs through every screen it renders, checks that focus shows, that the arrow keys reach every list item, and that everything Narrator reads has a name. Contrast was measured from the tokens. A person still listens with Narrator before the item is ticked. - **A confirmation is modal for the keyboard too:** the page behind it is disabled while it's open, it starts on the safe choice, and focus goes back where it was. - **Narrow windows adapt with container queries,** below the mockup's 1100 pixels only: Schedule stacks its side column under the settings, and a backup row leaves out the plugin count, then the size. At the mockup's size every screen looks as approved. - **Focus has somewhere to go** when the control holding it disappears: `FocusFallback.IsTarget` marks Back Up Now and each restore step's main action. ## Decisions (2026-10-11, Linux and the Steam Deck) Researched from XIVLauncher.Core's, Dalamud's and Wine's source, the XIVLauncher FAQ, and the Flatpak, Velopack and systemd documentation. - **Where XIVLauncher.Core keeps its files:** everything is in `~/.xlcore`, natively, as the Flatpak and through XLM on the Deck, with no `dalamudUserData` folder. The game's settings are in `~/.xlcore/ffxivConfig` unless `GameConfigPath` in `launcher.ini` points elsewhere; Proton and Lutris keep them in their prefix's `My Games`. `secrets.json` (passwords in plain text on the Deck), `accounts.json` and `wineprefix/` stay outside the allowlist, and `launcher.ini` is only read for that one path. - **The running-game check reads `/proc`.** Wine names the game's process after its exe (`ffxiv_dx11.exe`) and Linux truncates XIVLauncher.Core's name to `XIVLauncher.Cor`, so today's names match nothing there and the check would pass silently. It is rewritten, with tests that prove a restore refuses, before anything ships for Linux. Only process names are read, never command lines, which carry login arguments. - **Shipping:** a Velopack AppImage that updates only when the user chooses, as on Windows, and a tarball for systems where the AppImage won't start. Both run outside a sandbox, so XIV Vault can see the game. Not on Flathub: its sandbox hides other processes, so a restore couldn't check that FFXIV is closed. - **Scheduling and notifications:** a systemd user timer with `Persistent=true` takes the place of the Task Scheduler task, and failures notify through `org.freedesktop.Notifications` over D-Bus (Tmds.DBus already ships with Avalonia). Notifications may not show in Game Mode, so the app's own last-run result stays the reliable signal. - **Default backup folder:** `~/Documents/XIV Vault`, the XDG documents folder, and the app says plainly that it stays on this device. On first run it lists the Dropbox, OneDrive (abraunegg), Nextcloud and Syncthing folders it finds, and a Deck's microSD card, for the user to pick. It never picks one itself, because an installed sync app doesn't prove the folder syncs. On a Deck it says that a reset or Clear local user data erases the home folder. - **Online-only files on Linux:** Nextcloud's `.nextcloud` stubs, and anything on a network or FUSE mount (rclone, GVfs, kio-fuse, SMB, NFS) found in `/proc/self/mountinfo`, count as online-only without reading them. - **Restoring across systems:** file names are matched without case and restored onto the existing file's spelling, and an archive holding two names that differ only by case is refused. The review warns that Dalamud's dev-plugin paths, `dalamudVfs.db` and plugin settings that store paths (such as Penumbra's mod folder) may point at the other system. - **The Steam Deck leads with Wi-Fi transfer** (the owner's call: not every Deck owner runs a sync app or knows where files live). The PC sends a backup and the Deck receives it: same network only, no server or relay, a short pairing code that also encrypts the transfer, and the Deck listens only while its Receive screen is open. The PC only connects outward, so Windows Firewall doesn't ask. A received backup is validated like any other, then restored through the wizard. Folder backups, schedules and the microSD card stay. The transfer changes the "only network call is the update check" promise, so the README's safety model and the website say exactly what it does. - **Hosted download links are not planned:** they would upload backups, which can hold plugins' tokens, to a server someone has to run. - **Linux comes first (M14), then the Deck launch (M15).** Both are proven on the owner's Steam Deck, and Linux first ships through the beta channel (M13). ## Decisions (2026-10-11, a beta channel) - **Betas are opt-in GitHub prereleases** on the same update feed, tagged `vX.Y.Z-beta.N`. A **Get beta versions** switch in Settings, off by default, makes the update check offer them too. Copies with the switch off, including every version released so far, never see a beta. Turning it off never downgrades: the beta stays until a newer stable release arrives. - **Stable stays stable:** a beta is never the latest release, so the website's download button, winget and installed copies without the switch keep to stable releases. Portable copies and the CLI have no updater and don't change. - **Betas keep the same promise:** anything a beta writes, every later version restores. So a beta never ships an unfinished backup format; a format change goes out only once it is final. - **The switch ships first,** in a stable 1.2, because people can only opt in from a version that has it. Linux then ships as 1.3 betas until the check on the owner's Deck passes. ## Decisions (2026-10-12, installing plugins) - **Field result:** a tester restored a backup onto a clean PC. Her game settings came back, but no plugins were installed. Dalamud's source confirms it installs a plugin only when someone chooses Install in its plugin installer (`/xlplugins`); nothing reinstalls the plugins its settings list. The README, website and app had said Dalamud downloads them again. That was never checked, and the wording is corrected until XIV Vault installs them itself. - **XIV Vault installs the plugins after a restore** (the owner's call: a new PC should get its plugins back without a list to work through). The list comes from the restored Dalamud settings, which name every installed plugin and every collection's plugins, so backups from every version already hold it. Each plugin's current version is downloaded from its repository, as the plugin installer would, and keeps its old ID so on/off states and collections line up. - **Nothing executable comes from a backup.** Plugins are code, so they are never copied into or out of an archive; only their names and IDs are read. Collections' character entries are never read. - **The official repository installs automatically; custom repositories after a tick.** A backup can name any repository, so the review shows them and the user chooses which to install from. - **Two promises change, and the safety model says so:** the plugin downloads become a second network call, which sends nothing about the user, and XIV Vault writes into `installedPlugins\`, only for plugins it installs. Restores still refuse while the game runs, and a plugin that fails to install is listed for `/xlplugins`. - **Proven on the owner's PC** with the XIVLauncher folder renamed aside so it looks like a new PC, then renamed back, and then on the tester's laptop. - **It comes before the beta channel:** plugin installs become M12 (1.1), the beta channel M13 (1.2), Linux M14 (1.3) and the Steam Deck M15 (1.4). ## M0: Bootstrap - [x] Solution with `XivVault.Core`, `XivVault.Cli`, `XivVault.Desktop` and `XivVault.Tests`. - [x] Brand assets and app icon. - [x] CI on `windows-latest`: restore, build, test, `dotnet format --verify-no-changes`. **Done when:** CI is green on a pull request. ## M1: Core engine - [x] Configuration (`%LOCALAPPDATA%\XIV Vault\config.json`) and app state. - [x] `IXivLauncherLocator` / `WindowsXivLauncherLocator`: override, known paths, layout detection (`dalamudUserData`), validation. - [x] Backup: allowlist, ZIP + manifest, SHA-256, atomic finalize, retention. - [x] Archive validation: schema, hashes, traversal, absolute paths, unknown files. - [x] Restore: process check, safety snapshot, temp extraction, allowlisted apply, rollback on failure. **Done when:** tests back up a fake XIVLauncher folder, restore it, and the traversal, checksum, running-process and partial-failure cases fail safely. ## M2: CLI - [x] `backup`, `restore`, `list`, `status`, `doctor`, `schedule`, `config`, `version`, with `--json`, `--quiet` and `--verbose` where they apply. - [x] Stable exit codes, documented in the README. **Done when:** `xiv-vault backup`, `list`, `status`, `doctor` and `restore latest` work against a fake XIVLauncher folder. ## M3: Scheduling and diagnostics - [x] Task Scheduler integration: daily, weekly, at Windows login. - [x] Scheduled run: waits for FFXIV, records its result. - [x] Diagnostics service and a report that holds paths, versions and results only. **Done when:** `xiv-vault schedule weekly --day Sunday` creates the task, `schedule status` reads it back, and `doctor` reports all four groups. ## M4: Desktop - [x] Shell: window chrome, navigation, theme tokens, fonts, icons, shared components. - [x] Overview, Backups, Restore wizard, Schedule, Diagnostics, Settings on real Core data. - [x] Polish: keyboard and focus, screen-reader names, reduced motion, empty and error states, confirmations. **Done when:** from a clean state the app detects XIVLauncher, backs up, shows the backup in history, schedules weekly backups and restores a previous backup through the wizard. ## M5: Release v0.1.0 - [x] Self-contained win-x64 publish for both apps: `xiv-vault-cli-win-x64.zip`, `xiv-vault-desktop-win-x64.zip`. - [x] Release workflow on `v*` tags. - [x] README with screenshots, `docs/architecture.md`, `docs/backup-format.md`, `docs/troubleshooting.md`. - [x] End-to-end smoke test against a fake XIVLauncher folder. **Done when:** pushing `v0.1.0` publishes both zips to a draft GitHub release. ## M6: Installer and updates - [x] Setup and update packages built with `vpk` in the release workflow, with a delta from the previous release. - [x] Update check when the app opens, Update and Restart, and the switch in Settings; a notice in the sidebar. - [x] Updates wait for backups, restores and other running copies; uninstalling removes the scheduled task. **Done when:** Setup installs XIV Vault, an installed copy updates itself to a newer version, and uninstalling removes the scheduled task. ## M7: First users (0.1.x) - [x] Back up and restore on the author's own setup with the published release; fix what turns up. (A rehearsal on a copy, then the real restore, on 67 plugins. It turned up the three fixes in 0.1.1.) - [x] Release 0.1.1: the first update installed copies take from GitHub, and the first delta package. (A real 0.1.0 install updated itself through the 738 KB delta, and its scheduled task kept working.) - [x] Issue templates: a bug report that asks for the Diagnostics report and whether settings were lost (label those `data-loss`), and a feature request. - [x] Winget manifests for Setup and the CLI, written from a published release by `scripts/make-winget-manifests.ps1`. The app is pinned from `winget upgrade --all`, since it updates itself and Setup closes running copies. - [ ] Both packages submitted to microsoft/winget-pkgs and merged, as `hazeliscoding.XIVVault` and `hazeliscoding.XIVVault.CLI`. (Renamed from `HazelGranados.*` on 2026-10-10, before either was merged, so the identifier follows the GitHub username as Prompuff's does. Publisher stays Hazel Granados, the name in Apps & Features and on the signature. The CLI was merged at 0.4.0, and #450876 submits 1.0.0; the app's #447085 now submits 1.0.0 and waits for a moderator.) **Done when:** a 0.1.0 install updates itself to 0.1.1 from GitHub, and `winget install` works for both. ## M8: Fresh PC and synced folders (0.2) - [x] List backups without downloading them: names and sizes from the folder, manifests only for files already on this PC. - [x] Verify only the latest backup and the one being restored, not every archive in the folder. - [x] A restore whose backup is still in the cloud shows the download and its size before anything changes. (Checked on a real OneDrive folder: `status`, `list` and `doctor` left three freed-up backups in the cloud, and `restore latest` showed the size and downloaded only the backup it restored.) **Done when:** on a new PC with OneDrive Files On-Demand, opening XIV Vault downloads nothing until a restore is chosen. Released as 0.2.0 on 2026-10-08. A real 0.1.2 install updated itself to it from GitHub. ## M9: Restore only some plugins (0.3) - [x] Choose plugins in the review step of the restore wizard; Dalamud settings are their own choice. - [x] The same choice on the command line: `xiv-vault restore --plugin `. - [x] The safety backup still holds everything a full restore would replace. **Done when:** restoring one plugin's settings leaves every other plugin and Dalamud's settings as they were. ## M10: Signing and game settings (0.4) - [x] Sign releases with Artifact Signing: both exes, Setup and the update packages, verified with `signtool` before the draft is made. Manual runs of the release workflow build unsigned. (0.4.0 signed on its first tag build; every exe in Setup, the zips and the update package verifies with Hazel Granados as the signer.) - [x] README: replace the "not code-signed" notes once a signed release is out, and say what SmartScreen shows until reputation builds. - [x] Back up the game allowlist under `payload/game/` with manifest version 2, and validate it by the same rules as the Dalamud payload. (On the author's PC: 20 game files and 1 character, with no chat logs, screenshots or old copies.) - [x] Restore game settings: in the safety snapshot, by character folder, refused while the game runs, rolled back across both folders on failure, and creating the game folder on a PC where the game has never started. - [x] A PC where the game has never started: check whether the game keeps files restored before its first start. (It does; see the 2026-10-09 decisions.) - [x] Game settings in `status`, `doctor`, Overview and the backup list; a switch in Settings; their own choice in the restore review step and in `xiv-vault restore`, with `FFXIV.cfg` as a separate choice. - [x] Logs and the Diagnostics report count characters and never show a content ID. (Error messages too, including paths quoted from Windows errors.) - [x] README safety model, AGENTS.md safety contract and `docs/backup-format.md` cover game settings. **Done when:** a tag build publishes a signed Setup and signed zips, tests back up a fake game folder beside a fake XIVLauncher folder and restore it, the chat log, running-game, content-ID and partial-failure cases fail safely, and on the author's setup a restore brings back the HUD layout, hotbars and macros in game. Released as 0.4.0 on 2026-10-10. A real 0.3.0 install updated itself to it from GitHub. ## M11: 1.0 - [x] A Windows notification when a scheduled backup fails. (Checked on the author's PC: a failing scheduled run from the app and from the CLI each showed one.) - [x] Real 0.1.0 archives kept as test files, which every later version must validate and restore. (A manual backup with the UI layout and the safety snapshot from restoring it, made by the published 0.1.0 CLI from a fake XIVLauncher folder, in `tests/XivVault.Tests/Fixtures/0.1.0`.) - [x] The stable parts written down: backup format, CLI commands and options, JSON output, exit codes, and what a major version may change. (`docs/cli.md`, the README's Stability section and `docs/backup-format.md`; `CliContractTests` pins the JSON fields and exit codes.) - [x] A release checklist that installs the previous release and updates it before a draft is published. (`docs/releasing.md`: the installed previous release updates from the draft's files through `XIV_VAULT_UPDATE_SOURCE`, then backs up and runs its scheduled task.) - [x] An accessibility check of every screen: Narrator, the keyboard alone, and WCAG AA contrast. (Contrast, keyboard and the automation tree Narrator reads are checked and fixed, `--a11y` finds no problems on any screen, and the author listened through with Narrator.) - [x] An Impeccable UI audit of every screen, with fixes that keep to the approved mockup. (14/20 before fixes, held back by adaptivity: at the smallest window Schedule cut off days and hints and Backups cut off row actions. Both now adapt below the mockup's size and look as before at it.) - [x] The website in `site/`, deployed to GitHub Pages: download, what it backs up, install, a new PC, safety, plugin developers, help and the disclaimer, signed "Made with ♥ by hazeliscoding". (Live at [hazeliscoding.github.io/xiv-vault](https://hazeliscoding.github.io/xiv-vault/) since 2026-10-11, and set as the repository's homepage.) - [x] The user guide on the website, organized by task and checked against the app's screens. (`site/guide.html`: thirteen tasks from installing to uninstalling, with the screenshots the README uses.) **Done when:** every item above is checked, the last two releases updated cleanly from the one before, and no data-loss issue is open. Released as 1.0.0 on 2026-10-11. A real 0.4.0 install updated itself to the draft through `XIV_VAULT_UPDATE_SOURCE`, then backed up and ran its scheduled task successfully, before the draft was published. ## M12: Plugin installs (1.1) - [ ] Core reads the plugin list from Dalamud's settings: internal names, IDs and on/off states from the default collection and saved collections, nothing else. - [ ] Core installs each missing plugin's current version from its repository, checked as Dalamud checks it (name, version, API level, no paths outside the plugin's folder), into `installedPlugins\\\` with its old ID. A plugin that is already installed is left alone. - [ ] Custom-repository plugins install only from repositories the user ticks in the review. - [ ] Desktop: the review step says which plugins will be installed and from where, and **Restore complete** lists what was installed and what to install from `/xlplugins`. The CLI's restore does the same, with its options and JSON fields added, never changed. - [ ] Tests with a fake repository: a zip with paths outside its folder, a name or version that doesn't match the repository, an unticked custom repository, the game running, and a download that fails halfway, which leaves nothing half-installed. - [ ] Side by side: an XIV Vault install matches Dalamud's own install of the same plugin version, file for file, apart from the ID. - [ ] A weekly CI job installs one real plugin from the live official repository into a temp folder, so a change to the repository's format fails CI before users notice. - [ ] README safety model, AGENTS.md, user guide and website: what is downloaded, from where, and that nothing about the user is sent. - [ ] On the owner's PC with `%APPDATA%\XIVLauncher` renamed aside: XIVLauncher set up fresh, the restore installs the plugins, and in game they load with their settings and collections, with no manifest errors in `dalamud.log`. Then the original folder is renamed back. **Done when:** the owner's fresh-folder test passes, the tests cover the safety cases, 1.1.0 is released, and the tester's clean-PC restore brings her plugins back. ## M13: Beta channel (1.2) - [ ] **Get beta versions** under Updates in Settings, off by default. On, the update check also offers GitHub prereleases; off, it never downgrades. - [ ] Settings and the sidebar say when the installed version is a beta. - [ ] `release.yml`: a `vX.Y.Z-beta.N` tag builds a signed prerelease, with a delta from the previous release, that never becomes the latest release. - [ ] The release checklist covers betas: the previous release still updates to the draft first, and winget is skipped. - [ ] README, user guide and website say what the beta channel is and who it's for. - [ ] Tests prove the switch decides whether prereleases are offered. **Done when:** 1.2.0 is released with the switch, a beta tag builds a prerelease that isn't the latest release, and the tests cover the switch. ## M14: Linux (1.3) - [ ] Find XIVLauncher.Core: `~/.xlcore`, the Steam Flatpak's `.xlcore`, Lutris and Proton prefixes, and the game settings folder named in `launcher.ini`. - [ ] The running-game check on Linux, from `/proc/*/comm`, with tests that prove a restore refuses while the game or XIVLauncher.Core runs. - [ ] Case-safe restores, and the cross-system warnings in the restore review. - [ ] `BackupAllowlist.ForDisplay` hides character folder names in `/home/...` and `Z:\...` paths too. - [ ] Scheduled backups through a systemd user timer, and failure notifications over D-Bus. - [ ] The Documents default, the first-run choice of detected sync folders and the microSD card, and online-only detection from mounts and Nextcloud stubs. - [ ] Linux versions of the small Windows pieces: show a file in the file manager, the reduce-motion setting, `~` paths in the UI, and the same-drive warning. - [ ] `release.yml` builds the Velopack AppImage, the tarball and the CLI for linux-x64 with checksums, and CI runs the tests on Linux too. - [ ] README, user guide and website cover Linux. - [ ] Linux ships as `1.3.0-beta.N` releases. The first beta reaches an installed copy with **Get beta versions** on, and not one with it off. - [ ] On the owner's Steam Deck in Desktop Mode: the AppImage (or the tarball) runs, the game's real process names match, the timer runs after sleep and in Game Mode, and a Windows backup restores with the HUD and hotbars back in game. Whether a Windows `FFXIV.cfg` suits the Deck is checked there too. **Done when:** a Linux build backs up and restores on the owner's Steam Deck in Desktop Mode, refuses to restore while the game runs, and runs its scheduled backup; tests cover the Linux locator, the process check and case handling; and 1.3.0 is released as stable. ## M15: Steam Deck (1.4) - [ ] Wi-Fi transfer: Send on Windows and Linux, Receive on the Deck and Linux. Same network only, a pairing code that also encrypts, listening only while Receive is open, and tests that refuse a wrong code or a changed file. - [ ] On a Deck, the first screen leads with Receive from my PC; folder backups stay one step away. - [ ] Usable in Game Mode as a non-Steam game: controller focus, touch and the on-screen keyboard. - [ ] The README's safety model, the user guide and the website say exactly what the transfer sends and when XIV Vault listens. - [ ] On the owner's Steam Deck in Game Mode: receive a backup from the Windows PC over Wi-Fi and restore it. **Done when:** in Game Mode on the owner's Steam Deck, a backup sent from the Windows PC arrives over Wi-Fi and restores, and the safety model describes the transfer. ## Later - XIVLauncher layouts and folders that users report, fixed in patch releases as they come in. - Light theme. ## Not planned - Copying plugin binaries into or out of a backup. Plugins are downloaded fresh from their repositories instead (M12). - Backing up the game install, screenshots or chat logs. Only its settings are backed up (M10). - Cloud APIs (Google Drive, Dropbox, OneDrive, S3). A folder synced by their own clients is enough. - Accounts, telemetry, a web dashboard. - A Windows service or tray daemon. - Plugin-specific backup adapters, or a Dalamud plugin version of XIV Vault. - A Flathub build: its sandbox hides the game's processes, so a restore couldn't refuse while FFXIV runs. - Hosted download links, or any server that holds backups.