docs: define v2.0.1 account and startup work
This commit is contained in:
parent
c58d9203bc
commit
b11b28e417
208
docs/superpowers/plans/2026-08-07-v2-account-manager-startup.md
Normal file
208
docs/superpowers/plans/2026-08-07-v2-account-manager-startup.md
Normal file
@ -0,0 +1,208 @@
|
|||||||
|
# V2.0.1 Account Manager und Startup Implementation Plan
|
||||||
|
|
||||||
|
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
|
||||||
|
|
||||||
|
**Goal:** Einen atomaren Ein-Klick-Account-Flow, einen deterministischen White-Screen-sicheren Start und eine funktionierende Update-Brücke von 3.3.108 auf die sichtbare Version 2.0.1 liefern.
|
||||||
|
|
||||||
|
**Architecture:** Browserunabhängige Kernlogik kapselt Validate-then-Commit und Release-Versionsauflösung und wird vom bestehenden Renderer beziehungsweise Updater verwendet. Der Electron-Main-Prozess erzwingt Software-Rendering vor Ready und zeigt das Hauptfenster erst nach `ready-to-show`.
|
||||||
|
|
||||||
|
**Tech Stack:** Electron 41, Node.js 24, `node:test`, electron-builder 26, Gitea Releases, GitHub Releases.
|
||||||
|
|
||||||
|
## Global Constraints
|
||||||
|
|
||||||
|
- Keine Code-Kommentare, XML-Dokumentation, TODOs oder Platzhalter hinzufügen.
|
||||||
|
- Sichtbare Produktversion, UI, Build und öffentlicher GitHub-Tag sind exakt `2.0.1` beziehungsweise `v2.0.1`.
|
||||||
|
- Der private Gitea-Transport-Tag für diese Version ist exakt `v3.3.109`; der Release-Titel ist exakt `Multi-Hoster-Upload v2.0.1`.
|
||||||
|
- Fehlgeschlagene, abgebrochene, veraltete oder OTP-erfordernde Prüfungen persistieren keinen Account.
|
||||||
|
- Release nur aus frischer Positivliste, ohne interne KI-/Task-/Log-/Backup-/Testdaten und nach Quell-, Build-, Archiv- und Secret-Prüfung.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Task 1: Startup-Renderer absichern
|
||||||
|
|
||||||
|
**Files:**
|
||||||
|
- Create: `lib/startup-renderer.js`
|
||||||
|
- Modify: `main.js`
|
||||||
|
- Create: `tests/startup-renderer.test.js`
|
||||||
|
|
||||||
|
**Interfaces:**
|
||||||
|
- Produces: `configureStartupRenderer(app)` deaktiviert Hardwarebeschleunigung genau einmal vor Ready.
|
||||||
|
- Produces: `createWindow()` erstellt das Hauptfenster unsichtbar und zeigt es auf `ready-to-show`.
|
||||||
|
|
||||||
|
- [ ] **Step 1: Failing Tests schreiben**
|
||||||
|
|
||||||
|
```js
|
||||||
|
test('configureStartupRenderer disables hardware acceleration', () => {
|
||||||
|
let calls = 0;
|
||||||
|
configureStartupRenderer({ disableHardwareAcceleration() { calls++; } });
|
||||||
|
assert.equal(calls, 1);
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
- [ ] **Step 2: RED verifizieren**
|
||||||
|
|
||||||
|
Run: `node --test tests/startup-renderer.test.js`
|
||||||
|
|
||||||
|
Expected: FAIL, weil `lib/startup-renderer.js` noch fehlt.
|
||||||
|
|
||||||
|
- [ ] **Step 3: Minimale Implementierung schreiben**
|
||||||
|
|
||||||
|
```js
|
||||||
|
function configureStartupRenderer(app) {
|
||||||
|
app.disableHardwareAcceleration();
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = { configureStartupRenderer };
|
||||||
|
```
|
||||||
|
|
||||||
|
`main.js` ruft die Funktion unmittelbar nach dem Electron-Import auf, entfernt das heuristische RDP-/Flag-Gate, setzt `show: false`, registriert `ready-to-show` vor `loadFile` und behandelt einen abgelehnten Load.
|
||||||
|
|
||||||
|
- [ ] **Step 4: GREEN und Startup-Smoke verifizieren**
|
||||||
|
|
||||||
|
Run: `node --test tests/startup-renderer.test.js`
|
||||||
|
|
||||||
|
Run: `$env:RUN_UI_SMOKE='1'; node tests/ui-smoke.js`
|
||||||
|
|
||||||
|
- [ ] **Step 5: Commit erstellen**
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
git add lib/startup-renderer.js main.js tests/startup-renderer.test.js
|
||||||
|
git commit -m "fix(startup): make renderer initialization deterministic"
|
||||||
|
```
|
||||||
|
|
||||||
|
### Task 2: Account in einem Lauf prüfen und anlegen
|
||||||
|
|
||||||
|
**Files:**
|
||||||
|
- Create: `renderer/account-submit.js`
|
||||||
|
- Modify: `renderer/index.html`
|
||||||
|
- Modify: `renderer/app.js`
|
||||||
|
- Replace: `tests/validate-credentials.test.js`
|
||||||
|
|
||||||
|
**Interfaces:**
|
||||||
|
- Produces: `submitValidatedAccount({ validate, commit, isCurrent })` mit den Resultaten `committed`, `rejected`, `otp_required`, `stale` und `error`.
|
||||||
|
- Consumes: bestehendes `window.api.validateCredentials` und `window.api.saveConfig`.
|
||||||
|
|
||||||
|
- [ ] **Step 1: Failing Tests für Ein-Klick- und Fehlerpfade schreiben**
|
||||||
|
|
||||||
|
```js
|
||||||
|
test('ok validates and commits exactly once in one submission', async () => {
|
||||||
|
let commits = 0;
|
||||||
|
const result = await submitValidatedAccount({
|
||||||
|
validate: async () => ({ status: 'ok' }),
|
||||||
|
commit: async () => { commits++; },
|
||||||
|
isCurrent: () => true
|
||||||
|
});
|
||||||
|
assert.equal(result.status, 'committed');
|
||||||
|
assert.equal(commits, 1);
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
Zusätzliche Tests decken `warn`, `error`, `skipped`, Throw, OTP, stale vor Commit und Save-Fehler ab.
|
||||||
|
|
||||||
|
- [ ] **Step 2: RED verifizieren**
|
||||||
|
|
||||||
|
Run: `node --test tests/validate-credentials.test.js`
|
||||||
|
|
||||||
|
Expected: FAIL, weil `submitValidatedAccount` noch fehlt.
|
||||||
|
|
||||||
|
- [ ] **Step 3: Submit-Core und Renderer-Integration implementieren**
|
||||||
|
|
||||||
|
Der Submit-Core validiert, prüft `isCurrent`, committet ausschließlich `ok|warn` und gibt strukturierte Ergebnisse zurück. `saveAccount()` hält Busy bis zum Ende, vergleicht Session und Credential-Snapshot, speichert einen kopierten Kandidaten und übernimmt ihn erst nach erfolgreichem IPC. Der Button bleibt bis zum Schließen deaktiviert.
|
||||||
|
|
||||||
|
- [ ] **Step 4: GREEN und UI-Vertrag verifizieren**
|
||||||
|
|
||||||
|
Run: `node --test tests/validate-credentials.test.js`
|
||||||
|
|
||||||
|
Run: `node --test tests/*.test.js`
|
||||||
|
|
||||||
|
Run: `$env:RUN_UI_SMOKE='1'; node tests/ui-smoke.js`
|
||||||
|
|
||||||
|
- [ ] **Step 5: Commit erstellen**
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
git add renderer/account-submit.js renderer/index.html renderer/app.js tests/validate-credentials.test.js
|
||||||
|
git commit -m "feat(accounts): validate and save in one action"
|
||||||
|
```
|
||||||
|
|
||||||
|
### Task 3: Produktversion und Updater-Brücke implementieren
|
||||||
|
|
||||||
|
**Files:**
|
||||||
|
- Modify: `lib/updater.js`
|
||||||
|
- Modify: `scripts/release_gitea.mjs`
|
||||||
|
- Modify: `package.json`
|
||||||
|
- Modify: `package-lock.json`
|
||||||
|
- Create: `tests/updater-version.test.js`
|
||||||
|
|
||||||
|
**Interfaces:**
|
||||||
|
- Produces: `resolveReleaseVersion(release)` liest zuerst eine semantische Version aus `release.name`, dann aus `tag_name`.
|
||||||
|
- Produces: Release-CLI `node scripts/release_gitea.mjs 2.0.1 --transport-tag v3.3.109 <notes>`.
|
||||||
|
|
||||||
|
- [ ] **Step 1: Failing Tests für Release-Auflösung und Bridge schreiben**
|
||||||
|
|
||||||
|
```js
|
||||||
|
test('bridge title resolves product version instead of transport tag', () => {
|
||||||
|
assert.equal(resolveReleaseVersion({ name: 'Multi-Hoster-Upload v2.0.1', tag_name: 'v3.3.109' }), '2.0.1');
|
||||||
|
assert.equal(isNewer('2.0.1', '2.0.1'), false);
|
||||||
|
assert.equal(isNewer('2.0.2', '2.0.1'), true);
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
- [ ] **Step 2: RED verifizieren**
|
||||||
|
|
||||||
|
Run: `node --test tests/updater-version.test.js`
|
||||||
|
|
||||||
|
Expected: FAIL, weil `resolveReleaseVersion` noch fehlt.
|
||||||
|
|
||||||
|
- [ ] **Step 3: Produkt-/Transport-Trennung implementieren**
|
||||||
|
|
||||||
|
`checkForUpdate()` verwendet die aufgelöste Produktversion für UI und Vergleich. Der Transport-Tag bleibt im Ergebnis diagnostizierbar. Das Release-Skript validiert `--transport-tag`, baut `2.0.1`, taggt `v3.3.109`, benennt den privaten Release `Multi-Hoster-Upload v2.0.1` und erzeugt `latest.yml` mit `2.0.1`.
|
||||||
|
|
||||||
|
- [ ] **Step 4: Version auf 2.0.1 setzen und GREEN verifizieren**
|
||||||
|
|
||||||
|
Run: `npm version 2.0.1 --no-git-tag-version`
|
||||||
|
|
||||||
|
Run: `node --test tests/updater-version.test.js`
|
||||||
|
|
||||||
|
Run: `npm test`
|
||||||
|
|
||||||
|
- [ ] **Step 5: Commit erstellen**
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
git add lib/updater.js scripts/release_gitea.mjs package.json package-lock.json tests/updater-version.test.js
|
||||||
|
git commit -m "feat(updater): bridge 3.3.108 clients to v2.0.1"
|
||||||
|
```
|
||||||
|
|
||||||
|
### Task 4: Build, Laufzeit und Veröffentlichung verifizieren
|
||||||
|
|
||||||
|
**Files:**
|
||||||
|
- Modify: `tasks/todo.md`
|
||||||
|
|
||||||
|
**Interfaces:**
|
||||||
|
- Consumes: Tasks 1 bis 3.
|
||||||
|
- Produces: geprüfte private Bridge und kuratierten öffentlichen Release v2.0.1.
|
||||||
|
|
||||||
|
- [ ] **Step 1: Vollständige lokale Gates ausführen**
|
||||||
|
|
||||||
|
Run: `npm test`
|
||||||
|
|
||||||
|
Run: `npx eslint .`
|
||||||
|
|
||||||
|
Run: `npm audit --omit=dev --json`
|
||||||
|
|
||||||
|
Run: `npm run release:win`
|
||||||
|
|
||||||
|
- [ ] **Step 2: Build und Archive prüfen**
|
||||||
|
|
||||||
|
Portable, Setup, Blockmap und `latest.yml` werden vollständig entpackt, auf Version, Struktur, Hashes, private Endpunkte, Credentials und interne Dateien geprüft. Gitleaks und TruffleHog laufen über Quell-Positivliste und entpackte Artefakte.
|
||||||
|
|
||||||
|
- [ ] **Step 3: Update-Brücke isoliert testen**
|
||||||
|
|
||||||
|
Ein unveränderter 3.3.108-Updater muss den privaten Transport-Tag `v3.3.109` als neuer erkennen. Der gebaute 2.0.1-Updater muss denselben Release-Titel als installiert erkennen. Setup und Portable werden separat gestartet; UI, Account-Modal und sauberer Teardown werden geprüft.
|
||||||
|
|
||||||
|
- [ ] **Step 4: Private und öffentliche Releases veröffentlichen**
|
||||||
|
|
||||||
|
Der private Gitea-Release nutzt Transport-Tag `v3.3.109` und Titel `Multi-Hoster-Upload v2.0.1`. Der öffentliche GitHub-Release wird aus einem neuen Positivlisten-Ordner als `v2.0.1` mit ausschließlich benötigtem Source und vier Release-Artefakten erstellt.
|
||||||
|
|
||||||
|
- [ ] **Step 5: Veröffentlichte Downloads erneut verifizieren**
|
||||||
|
|
||||||
|
Alle öffentlichen und privaten Assets werden neu heruntergeladen, byte- und hashverglichen, `latest.yml` wird gegen das Setup geprüft und der veröffentlichte Build wird erneut gestartet. Erst danach wird `tasks/todo.md` mit den exakten Belegen aktualisiert.
|
||||||
@ -0,0 +1,25 @@
|
|||||||
|
# V2.0.1 Account Manager und Startup
|
||||||
|
|
||||||
|
## Ziel
|
||||||
|
|
||||||
|
Multi-Hoster-Upload wird als sichtbare Produktversion `2.0.1` ausgeliefert. Das Hinzufügen und Bearbeiten eines Accounts validiert und speichert in einem Klick. Ein fehlgeschlagener, abgebrochener oder veralteter Check verändert weder die persistierte noch die im Renderer gehaltene Account-Konfiguration. Der intermittierende weiße Startzustand wird durch einen deterministischen Software-Renderer und ein erst nach erfolgreichem Laden sichtbares Hauptfenster verhindert.
|
||||||
|
|
||||||
|
## Account-Flow
|
||||||
|
|
||||||
|
Der Button lautet im Anlegefall `Prüfen und anlegen`, im Bearbeitungsfall `Prüfen und speichern`. Der bestehende Credential-Check bleibt die einzige fachliche Validierung. `ok` und `warn` führen unmittelbar zum Save, `error`, `skipped`, IPC-Fehler und `otp_required` nicht. OTP zeigt das Eingabefeld; der nächste Klick validiert und speichert in einem Lauf.
|
||||||
|
|
||||||
|
Ein einziger Busy-Zustand umfasst Check und Save. Vor dem Save werden Modal-Session, Hoster, Account-ID und Credential-Snapshot erneut abgeglichen. Hoster- oder Credential-Änderung, Schließen oder erneutes Öffnen invalidieren die laufende Operation. Der Kandidat wird auf einer Kopie der Hoster-Konfiguration aufgebaut. Erst nach erfolgreichem `saveConfig` ersetzt er den Renderer-State. Bei Save-Fehler bleibt das Modal offen und der bisherige State unverändert.
|
||||||
|
|
||||||
|
## Startup
|
||||||
|
|
||||||
|
Die App benötigt keine GPU-beschleunigten Canvas-, WebGL- oder Video-Oberflächen. Hardwarebeschleunigung wird deshalb bei jedem Start vor `app.whenReady()` deaktiviert, unabhängig von `SESSIONNAME` und einem späteren GPU-Crash. Das Hauptfenster startet mit `show: false`, wird auf `ready-to-show` eingeblendet und wertet das Promise von `loadFile` aus. Load- und Renderer-Fehler bleiben sichtbar diagnostizierbar.
|
||||||
|
|
||||||
|
## Versions- und Update-Brücke
|
||||||
|
|
||||||
|
`package.json`, UI, Installer-Metadaten und öffentliche GitHub-Version lauten `2.0.1` beziehungsweise `v2.0.1`. Der ausgelieferte 3.3.108-Client vergleicht den privaten Gitea-Tag numerisch und würde einen Tag `v2.0.1` ablehnen. Außerdem existiert dort bereits ein historischer Tag `v2.0.1`.
|
||||||
|
|
||||||
|
Der private Updater-Transport verwendet deshalb für diese Veröffentlichung den neuen internen Tag `v3.3.109`, während Release-Titel und Build `v2.0.1` anzeigen. Der neue Updater liest die Produktversion aus dem Release-Titel und fällt nur bei fehlender Produktversion auf den Tag zurück. Dadurch sieht 3.3.108 den höheren Transport-Tag, während 2.0.1 denselben Release anhand des Titels als bereits installiert erkennt. Künftige 2.x-Releases verwenden fortlaufende interne Transport-Tags oberhalb 3.3.108 und sichtbare 2.x-Titel.
|
||||||
|
|
||||||
|
## Verifikation
|
||||||
|
|
||||||
|
Regressionsfälle prüfen den real verwendeten Account-Submit-Core, die Startup-Konfiguration und die Produkt-/Transport-Versionsauflösung. Danach folgen vollständige Unit-Tests, UI-Smoke, wiederholte reale Starts, Windows-Build, entpackte Artefaktprüfung, Secret-Scans, isolierter Installer-/Updater-Test und erst anschließend die kuratierten privaten und öffentlichen Releases mit erneutem Download und Hashvergleich.
|
||||||
Loading…
Reference in New Issue
Block a user