Add/db and speed (#1243)

* fix(privacy): make privacy policy page dark mode friendly

Replace the hardcoded light gradient background with bg-background and
add dark:prose-invert to the prose blocks so body text is readable on
dark cards.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* feat(cloud-backup): sync archives to Dropbox alongside Google Drive

Introduce a CloudStorageProvider interface so performSync builds the
archive set once and talks to storage only through it. Google Drive
keeps its existing behaviour; Dropbox is a second implementation, so
the compliance-relevant half (fingerprints, per-year layout, size
fallback, progressive persistence) cannot drift between targets.

Dropbox uses App folder access, matching the drive.file scope's "only
what the app created" guarantee. Uploads are single-shot under 8 MB and
chunked upload sessions above, every write verified against Dropbox's
content_hash. Call arguments are ASCII-escaped per UTF-16 code unit so
Swedish file names survive the Dropbox-API-Arg header.

Each provider owns its extension_data keys, schedule, failure counter
and alert throttle, so a dead Dropbox token cannot pause a healthy
Drive backup. The google_drive_* keys and the /oauth/callback path are
untouched: both are wire format for already-connected companies.

isConfigured() gates /connect only. A deployment that loses its OAuth
credentials must not trap users with a connection they cannot remove
or a schedule they cannot switch off.

Requires DROPBOX_APP_KEY and DROPBOX_APP_SECRET; the provider row
renders disabled without them. No migration: state is extension_data
JSON throughout.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* fix: remove merge-conflict markers committed in DECISIONS.md

The merge that brought main into this branch staged DECISIONS.md while
it still carried conflict markers, so cdc3a513 shipped an unresolved
hunk (compliance swarm ISO 27001 A.8.32).

DECISIONS.md is an append-only log, so both sides are kept: main's
systemdokumentation entry followed by this branch's Dropbox entries.
No decision was dropped.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Mattsson
2026-07-27 16:49:24 +02:00
committed by GitHub
co-authored by Claude Opus 5
parent 1a7152a7af
commit fbd4b992f5
27 changed files with 2852 additions and 478 deletions
+7
View File
@@ -611,3 +611,10 @@ One line per decision: `[YYYY-MM-DD] <decision>: <why>`. Appended by agents and
[2026-07-27] Removed the granular "BFNAR 2013:2 punkt 9.x" citations from public/docs/systemdokumentation-mall.md instead of renumbering them to kap 8: the swedish-accounting-compliance skill and our own route comments both place systemdokumentation in kap 8, the template asserted kapitel 9 with a full point-by-point mapping (9.1, 9.2, 9.3-9.5, 9.6-9.8, 9.9, 9.16), and neither could be verified against BFN's actual text from here. A downloadable statutory template is the wrong place to guess a legal citation, and a wrong precise cite is worse than a correct general one, so the doc now cites BFL 5 kap. 11 § and BFNAR 2013:2 without pinning points. Restore the points once someone confirms the chapter against the standard.
[2026-07-27] Abonnemang masthead uses the halftone Stockholm skyline, not key-adding-machine and no new asset: the wide engraving crops cleanly into a banner strip (waterline pinned to the bottom edge, same physics as the onboarding backdrop) while the machine vignette read noisy and lopsided at banner crop; screenshots of both compared before choosing.
[2026-07-27] The requested Claude/OpenAI logos went into the API tab's "Anslut MCP-klient" group as a quiet works-with strip, using the marketing site's monochrome halftone marks instead of the raw colored brand tiles: full-color trademark tiles would fight the editorial monochrome chrome, and the halftone versions already exist as shared brand assets.
[2026-07-27] Dropbox added as a second cloud-backup target behind a CloudStorageProvider interface rather than by copying the Drive sync: the archive-building half of performSync (fingerprints, per-year layout, size fallback, progressive persistence) is where the compliance-relevant behaviour lives, and a fork of it would drift silently.
[2026-07-27] Dropbox uses App folder access, not full Dropbox: it matches the drive.file scope's "only what the app created" story, which is the privacy claim the backup card makes, and it is what Dropbox production approval expects for a backup app.
[2026-07-27] Each provider keeps its own extension_data keys (google_drive_* / dropbox_*) and its own schedule, failure counter and alert throttle: Emil chose independent per-provider schedules, and it means a dead Dropbox token cannot pause a healthy Drive backup.
[2026-07-27] The Google storage keys and the /oauth/callback path were left untouched: they are wire format (already-connected companies' records, plus a redirect URI registered with Google), so Dropbox got additive keys and its own /oauth/dropbox/callback.
[2026-07-27] isConfigured() gates /connect only, not /disconnect, /schedule or /sync: a deployment losing its OAuth credentials must not trap users with a connection they cannot remove or a schedule they cannot switch off.
[2026-07-27] Dropbox web links point at /home/Apps unless DROPBOX_APP_FOLDER_NAME is set: app-folder scoped calls cannot discover where the app folder sits in the user's account, and a link into the wrong folder reads as a lost backup, so the app-name deep link is opt-in rather than guessed.
[2026-07-27] performSync keeps `provider` optional, defaulting to Google Drive: it preserves the pre-Dropbox call shape (and its test suite) as the documented legacy path while all three production call sites pass a provider explicitly.