Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 19 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
</p>

<p align="center">
<a href="https://github.com/nimiq/validators-api/actions/workflows/sync.yml" target="_blank"><img src="https://github.com/nimiq/validators-api/actions/workflows/sync.yml/badge.svg" /></a>
<a href="https://github.com/nimiq/validators-api/actions/workflows/ci.yml" target="_blank"><img src="https://github.com/nimiq/validators-api/actions/workflows/ci.yml/badge.svg" /></a>
</p>

<h2 align="center">Dashboards</h2>
Expand Down Expand Up @@ -203,7 +203,18 @@ The system automatically detects the environment and only sends notifications in

## Deployment

The deployment is handled by the [`NuxtHub Action`](./.github/workflows/nuxt-hub.yml).
The deployment is handled via Wrangler CLI using the `wrangler.json` configuration file.

**Deploy command:**
```bash
pnpm build && npx wrangler --cwd .output deploy [-e env]
```

Where `env` can be: `preview`, `testnet`, or `testnet-preview` (omit for mainnet production).

**Required secrets:**
- `ALBATROSS_RPC_NODE_URL`
- `NUXT_SLACK_WEBHOOK_URL`

There are 4 different environments:

Expand All @@ -214,6 +225,11 @@ There are 4 different environments:
| `preview` | `preview-mainnet` | [Validators API Mainnet Preview](https://dev.validators-api-mainnet.pages.dev) | Push any commit to any branch |
| `preview` | `preview-testnet` | [Validators API Testnet Preview](https://dev.validators-api-testnet.pages.dev) | Push any commit to any branch |

Each Nuxt Hub environment has its own database, so effectively we have 4 different databases and there are 4 tasks in the [`sync.yml`](./.github/workflows/sync.yml) workflow that are responsible for syncing the data from the Nimiq network to the database.
**Data Synchronization:**

Each environment has its own D1 database, KV cache, and R2 blob storage. Data synchronization is handled automatically by Nitro scheduled tasks that run hourly via Cloudflare Workers cron triggers configured in `wrangler.json`:

- `sync:epochs` - Fetches missing blockchain epochs and stores them in the database
- `sync:snapshot` - Updates validator snapshots and calculates trust scores

**Write operations to `main` are restricted**, only via PR.
51 changes: 5 additions & 46 deletions app/app.vue
Original file line number Diff line number Diff line change
Expand Up @@ -6,27 +6,6 @@ const debouncedRefresh = useDebounceFn(() => {
refreshNuxtData(['/api/v1/validators', '/api/v1/supply', '/api/v1/status'])
}, 300)

const { status: statusSync, data: dataSync, error: syncError, close: closeSync, open: syncData } = useEventSource('/api/v1/sync/sse', [], { immediate: false })

// Check for sync success message and refresh document
watch(() => dataSync.value, (newData) => {
if (newData) {
try {
const parsedData = JSON.parse(newData)
if (parsedData.kind === 'success' && parsedData.message === 'Sync process completed') {
debouncedRefresh()
closeSync()
}
}
catch (e) {
console.error('Failed to parse sync data:', e)
}
}
}, { immediate: true })

// Also maintain the original watch for general updates
watch(() => [dataSync, syncError], debouncedRefresh)

const colorMode = useColorMode()
const toggleDark = () => colorMode.value = colorMode.value === 'light' ? 'dark' : 'light'

Expand Down Expand Up @@ -110,7 +89,7 @@ const currentEnvItem = { branch: gitBranch, network: nimiqNetwork, link: environ
<button i-nimiq:moon @click="() => toggleDark()" />
</header>
<main flex-1>
<div v-if="(!isSynced || error || syncError) && $route.path === '/'" bg="red/8" outline="1.5 ~ red-600" rounded-12 f-p-md text="14 red-1100" nq-prose-compact children:max-w-none f-mb-lg>
<div v-if="(!isSynced || error) && $route.path === '/'" bg="red/8" outline="1.5 ~ red-600" rounded-12 f-p-md text="14 red-1100" nq-prose-compact children:max-w-none f-mb-lg>
<h1 flex="~ items-center gap-12" text-red-1100 f-text-lg>
<div i-nimiq:alert op-70 text-0.9em m-0 />
<template v-if="!isActivitySync">
Expand All @@ -124,7 +103,7 @@ const currentEnvItem = { branch: gitBranch, network: nimiqNetwork, link: environ
The database is not fully synchronized with the blockchain. The API may not return the most recent data.
</p>

<pre v-if="syncError || error" bg="red/6" text="f-2xs red-1100" outline="red/30" w-inherit>{{ JSON.stringify(syncError || error, null, 2) }}</pre>
<pre v-if="error" bg="red/6" text="f-2xs red-1100" outline="red/30" w-inherit>{{ JSON.stringify(error, null, 2) }}</pre>

<template v-if="status">
<h2 f-mt-md text-red-1100 f-text-md flex="~ items-center gap-12">
Expand All @@ -149,29 +128,9 @@ const currentEnvItem = { branch: gitBranch, network: nimiqNetwork, link: environ

<hr f-my-sm border-red-600>

<div flex="~ items-baseline gap-8" mx-0 f-mt-md>
<button
mx-0 nq-pill nq-pill-red outline="~ 1.5 offset--1.5 red-1100/40"
:disabled="statusSync === 'OPEN'"
@click="() => syncData()"
>
<div :class="statusSync === 'OPEN' ? 'i-nimiq:spinner' : 'i-nimiq:restore'" mr-6 />
<span>
{{ statusSync === 'OPEN' ? 'Syncing...' : 'Sync now' }}
</span>
</button>

<button v-if="statusSync === 'OPEN'" mx-0 nq-pill-tertiary @click="() => closeSync()">
<div i-nimiq:cross mr-6 scale-70 />
Cancel
</button>

<div flex-1 flex="~ items-center justify-end">
<code w-max mr-0>SSE: {{ statusSync }}</code>
</div>
</div>

<pre v-if="dataSync" bg="red/6" lh-none text="f-2xs red-1100" outline="red/30" w-inherit max-h-80vh of-auto>{{ dataSync }}</pre>
<p f-mt-md text="f-sm red-1100/80">
<strong>Note:</strong> Data synchronization is handled automatically by scheduled tasks that run hourly. Please wait for the next sync cycle or contact an administrator if the issue persists.
</p>
</div>

<NuxtPage />
Expand Down