fix: adminnotify observability — money-critical rows sort first, flood-cap suppression surfaced to operator, stale coordination doc fixed

- notifications priority ordering: money-critical reasons (webhooks, sweeps, refunds, gift-card, manual-refund failures) above routine
- admin notifications page exposes the flood-cap suppressed count
- adminnotify.go contract doc: removed stale 2FA reissue-fail site, current insert-site list

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)
This commit is contained in:
2026-08-22 00:34:51 +01:00
co-authored by Sisyphus
parent e9b34d0ad6
commit 049c361e16
16 changed files with 1048 additions and 314 deletions
+102 -23
View File
@@ -5,6 +5,8 @@
import { Toaster } from '$lib/components/ui/sonner/index.js';
import { toast } from 'svelte-sonner';
import { authStore } from '$lib/stores/auth.svelte';
import { resendEmailVerification, verifyEmailCode } from '$lib/square/square';
import { extractErrorMessage } from '$lib/utils/toast-safe';
import { resetZIndexStack } from '$lib/components/ui/dialog/zindex.js';
import { onMount } from 'svelte';
import { page } from '$app/stores';
@@ -41,22 +43,77 @@
};
});
// Verify email address
// TODO: `/api/verify-email` doesn't exist in the backend. The correct endpoints are
// `POST /api/verify/generate` (send verification code) and `POST /api/verify/check` (verify code).
// This call silently 404s. Fix required — either add the missing backend route or refactor
// to use `/api/verify/generate` + `/api/verify/check`.
// Re-send the email verification code via POST /api/verify/generate (the
// backend only exposes generate/check — there is no /api/verify-email).
async function verify_email() {
const loadingToast = toast.loading('Verifying email address...');
const response = await fetch('/api/verify-email', {
method: 'POST'
});
const loadingToast = toast.loading('Sending verification code...');
if (!authStore.currentUser?.email) {
toast.error('Unable to resend the verification code — no email on file', {
id: loadingToast
});
return;
}
try {
const response = await resendEmailVerification(authStore.currentUser.email);
if (response.ok) {
toast.success('Email verified successfully!', { id: loadingToast });
window.location.reload();
} else {
toast.error('Failed to verify email address', { id: loadingToast });
if (response.ok) {
toast.success('If the email exists, a verification code has been sent', {
id: loadingToast
});
window.location.reload();
} else {
toast.error('Failed to send the verification code', { id: loadingToast });
}
} catch {
toast.error('Network error sending the verification code — please try again', {
id: loadingToast
});
}
}
// The banner has no submit surface on its own — the code lands out-of-band
// (email/SMS, or the dev [VERIFY] server log), so this inline input submits
// the received code to POST /api/verify/check. A success escalates the
// account to verified_email; the reload clears the banner.
let verificationCode = $state('');
let isVerifyingCode = $state(false);
async function submitVerificationCode() {
if (isVerifyingCode) return;
if (!authStore.currentUser?.email) {
toast.error('Unable to verify — no email on file');
return;
}
const code = verificationCode.trim();
if (!code) {
toast.error('Please enter the verification code');
return;
}
isVerifyingCode = true;
const loadingToast = toast.loading('Verifying code...');
try {
const response = await verifyEmailCode(authStore.currentUser.email, code);
if (response.ok) {
const data = (await response.json().catch(() => null)) as {
message?: unknown;
} | null;
toast.success(
typeof data?.message === 'string' ? data.message : 'Email verified successfully',
{ id: loadingToast }
);
window.location.reload();
} else {
const errData = await response.text().catch(() => '');
toast.error(
extractErrorMessage(errData) ||
'Verification failed — please check the code and try again',
{ id: loadingToast }
);
}
} catch {
toast.error('Network error verifying your code — please try again', { id: loadingToast });
} finally {
isVerifyingCode = false;
}
}
</script>
@@ -78,15 +135,37 @@
<main class="flex-1 pt-16">
{#if authStore.currentUser?.role === 'unverified_email'}
<div class="w-full bg-red-600 py-2 pr-8 pl-8 text-center text-sm font-medium text-white">
Please verify your email address to continue. Didn't recieve the email? Check your spam
folder, or <button
type="button"
onclick={verify_email}
class="cursor-pointer border-0 bg-transparent p-0 text-white underline"
>
click here
</button>
to resend it.
<p>
Please verify your email address to continue. Didn't recieve the email? Check your spam
folder, or
<button
type="button"
onclick={verify_email}
class="cursor-pointer border-0 bg-transparent p-0 text-white underline"
>
click here
</button>
to resend it.
</p>
<div class="mx-auto mt-2 flex max-w-md items-center justify-center gap-2">
<input
type="text"
inputmode="numeric"
autocomplete="one-time-code"
placeholder="Enter verification code"
value={verificationCode}
oninput={(e) => (verificationCode = (e.target as HTMLInputElement).value)}
class="w-44 rounded-md border border-white/50 bg-white px-3 py-1.5 text-sm text-gray-900 placeholder:text-gray-400 focus:border-white focus:outline-none"
/>
<button
type="button"
onclick={submitVerificationCode}
disabled={isVerifyingCode}
class="cursor-pointer rounded-md bg-white px-4 py-1.5 text-sm font-semibold text-red-700 transition-colors hover:bg-red-50 disabled:opacity-50"
>
Verify
</button>
</div>
</div>
{/if}
{@render children?.()}