---
URL: "https://docs.revosurge.com/"
LLMS_URL: "https://docs.revosurge.com/index.md"
layout: "page"
title: "RevoSurge Platform Docs"
head:
- 0: "meta"
1:
http-equiv: "refresh"
content: "0;url=/en/"
---
Redirecting to [English](/en/)...
---
URL: "https://docs.revosurge.com/docs/superpowers/plans/2026-03-18-exchange-rate-reference"
LLMS_URL: "https://docs.revosurge.com/docs/superpowers/plans/2026-03-18-exchange-rate-reference.md"
---
# Exchange Rate Reference Implementation Plan
> **For agentic workers:** REQUIRED: Use superpowers:subagent-driven-development (if subagents available) or superpowers:executing-plans to implement this plan. Steps use checkbox (`- [ ]`) syntax for tracking.
**Goal:** Add a new English `Reference Data` docs page that loads monthly exchange-rate JSON from a CDN at runtime, defaults to the latest month, and lets readers switch months in a full table view.
**Architecture:** Implement one page-specific Vue component at `.vitepress/theme/components/ExchangeRatesTable.vue`. The Markdown page passes a single `indexUrl` prop; the component fetches `index.json`, derives monthly file URLs from the same directory, validates both payload shapes, caches month payloads in memory, and renders loading, error, empty, and table states. Update the English sidebar to expose a new top-level `Reference Data` group containing `Exchange Rate Reference`.
**Tech Stack:** VitePress 2, Vue 3 with `
Loading exchange rates...
```
- [ ] **Step 2: Create the new English page and import the component locally**
Create `en/reference-data/exchange-rates.md` and make the confirmed production CDN URL explicit in one local constant:
```md
---
title: Exchange Rate Reference
description: Browse monthly exchange-rate reference data by month.
---
# Exchange Rate Reference
Monthly exchange-rate reference data published from the internal finance pipeline.
```
Set `exchangeRatesIndexUrl` to the exact production `index.json` URL confirmed in Preconditions. Keep it as a single local constant in this page so the data source remains obvious and page-scoped.
- [ ] **Step 3: Add the page to the English sidebar**
Modify `.vitepress/config/en.ts` to insert a new top-level group:
```ts
{
text: 'Reference Data',
link: '/en/reference-data/exchange-rates',
collapsed: false,
items: [
{ text: 'Exchange Rate Reference', link: '/en/reference-data/exchange-rates' }
]
}
```
Place it near the end of the existing sidebar groups, before `LLM Resources`, so it reads like reference material instead of product onboarding.
- [ ] **Step 4: Run the build to verify the new route and import path compile**
Run: `npm run build`
Expected:
- Exit code `0`
- VitePress builds successfully
- No Markdown import errors
- No Vue SFC compile errors
- [ ] **Step 5: Commit the route wiring**
```bash
git add .vitepress/theme/components/ExchangeRatesTable.vue en/reference-data/exchange-rates.md .vitepress/config/en.ts
git commit -m "feat: add exchange rate reference page shell"
```
### Task 2: Implement runtime loading, validation, and the table UI
**Files:**
- Modify: `.vitepress/theme/components/ExchangeRatesTable.vue`
- Test: `npm run build`
- [ ] **Step 1: Add strict payload types and validation helpers**
Expand the component script with explicit runtime guards instead of trusting raw JSON:
```ts
import { computed, onMounted, ref } from 'vue'
type IndexPayload = {
latestMonth: string
months: string[]
}
type RateRow = {
currency: string
rate: number
}
type MonthPayload = {
month: string
baseCurrency: string
generatedAt: string
rates: RateRow[]
}
function assertIndexPayload(value: unknown): IndexPayload {
if (!value || typeof value !== 'object') {
throw new Error('Invalid exchange-rate index payload.')
}
const payload = value as Record
if (typeof payload.latestMonth !== 'string') {
throw new Error('Exchange-rate index is missing latestMonth.')
}
if (
!Array.isArray(payload.months) ||
payload.months.some(
(month) => typeof month !== 'string' || !/^\d{4}-\d{2}$/.test(month)
)
) {
throw new Error('Exchange-rate index has invalid months.')
}
if (!payload.months.includes(payload.latestMonth)) {
throw new Error('Exchange-rate index latestMonth is not present in months.')
}
return {
latestMonth: payload.latestMonth,
months: payload.months as string[]
}
}
function assertMonthPayload(value: unknown, requestedMonth: string): MonthPayload {
if (!value || typeof value !== 'object') {
throw new Error('Invalid monthly exchange-rate payload.')
}
const payload = value as Record
if (payload.month !== requestedMonth) {
throw new Error(`Exchange-rate month mismatch for ${requestedMonth}.`)
}
if (typeof payload.baseCurrency !== 'string') {
throw new Error('Monthly exchange-rate payload is missing baseCurrency.')
}
if (typeof payload.generatedAt !== 'string') {
throw new Error('Monthly exchange-rate payload is missing generatedAt.')
}
if (
!Array.isArray(payload.rates) ||
payload.rates.some((row) => {
if (!row || typeof row !== 'object') return true
const rateRow = row as Record
return typeof rateRow.currency !== 'string' || typeof rateRow.rate !== 'number'
})
) {
throw new Error('Monthly exchange-rate payload has invalid rates.')
}
return {
month: payload.month as string,
baseCurrency: payload.baseCurrency as string,
generatedAt: payload.generatedAt as string,
rates: payload.rates as RateRow[]
}
}
```
Use thrown `Error` instances for invalid payloads so the component can render one consistent error state.
- [ ] **Step 2: Add reactive state, URL derivation, and month cache**
Introduce only the state needed for this page:
```ts
const months = ref([])
const selectedMonth = ref('')
const monthData = ref(null)
const loadingIndex = ref(true)
const loadingMonth = ref(false)
const errorMessage = ref('')
const monthCache = new Map()
const baseUrl = computed(() => new URL('.', props.indexUrl).toString())
function monthUrl(month: string): string {
return new URL(`${month}.json`, baseUrl.value).toString()
}
```
Sort `months` in descending lexicographic order as soon as the index payload is accepted.
- [ ] **Step 3: Implement `loadIndex`, `loadMonth`, `initialize`, and `retry`**
Add one code path for first load and one for month switching:
```ts
async function loadIndex(): Promise {
const response = await fetch(props.indexUrl)
if (!response.ok) throw new Error('Failed to load exchange-rate index.')
return assertIndexPayload(await response.json())
}
async function loadMonth(month: string): Promise {
if (monthCache.has(month)) {
monthData.value = monthCache.get(month) ?? null
selectedMonth.value = month
errorMessage.value = ''
return
}
loadingMonth.value = true
errorMessage.value = ''
try {
const response = await fetch(monthUrl(month))
if (!response.ok) throw new Error(`Failed to load exchange rates for ${month}.`)
const payload = assertMonthPayload(await response.json(), month)
monthCache.set(month, payload)
monthData.value = payload
selectedMonth.value = month
} catch (error) {
errorMessage.value = error instanceof Error ? error.message : 'Failed to load exchange rates.'
} finally {
loadingMonth.value = false
}
}
async function initialize(): Promise {
loadingIndex.value = true
errorMessage.value = ''
try {
const indexPayload = await loadIndex()
months.value = [...indexPayload.months].sort().reverse()
await loadMonth(indexPayload.latestMonth)
} catch (error) {
errorMessage.value = error instanceof Error ? error.message : 'Failed to load exchange-rate index.'
} finally {
loadingIndex.value = false
}
}
```
Call `initialize()` in `onMounted()`. Expose one retry action that calls `initialize()` if no month has loaded yet, otherwise retries `loadMonth(selectedMonth.value)`.
- [ ] **Step 4: Replace the shell template with the real stateful UI**
Render exactly these sections inside the component template:
```vue
Loading exchange rates...
{{ errorMessage || 'No exchange-rate months are available.' }}
No exchange-rate rows are available for this month.
Currency
Rate
{{ row.currency }}
{{ row.rate }}
```
Keep the template narrow. Do not add charts, filters, or search.
- [ ] **Step 5: Add scoped styles for readability and mobile overflow**
Add scoped CSS inside `.vitepress/theme/components/ExchangeRatesTable.vue` for:
- A padded state container with subtle border/background
- A compact toolbar row
- Readable metadata chips or inline blocks
- A horizontally scrollable table wrapper
- Table header and row borders using VitePress color tokens
- A simple retry button that matches the theme
Minimum structure:
```css
.exchange-rates__table-wrap {
overflow-x: auto;
}
.exchange-rates__table {
width: 100%;
min-width: 420px;
border-collapse: collapse;
}
.exchange-rates__table th,
.exchange-rates__table td {
padding: 12px 14px;
border-bottom: 1px solid var(--vp-c-divider);
text-align: left;
}
```
Keep all new styling inside the component unless a real global style need appears.
- [ ] **Step 6: Run the build after the component implementation**
Run: `npm run build`
Expected:
- Exit code `0`
- No TypeScript-in-SFC errors
- No VitePress SSR build errors
- [ ] **Step 7: Commit the runtime implementation**
```bash
git add .vitepress/theme/components/ExchangeRatesTable.vue
git commit -m "feat: implement exchange rate table runtime"
```
### Task 3: Manually verify states and finish the page
**Files:**
- Modify if needed: `.vitepress/theme/components/ExchangeRatesTable.vue`
- Modify if needed: `en/reference-data/exchange-rates.md`
- Modify if needed: `.vitepress/config/en.ts`
- Test: `npm run dev`, `npm run build`
- [ ] **Step 1: Start the local docs server**
Run: `npm run dev`
Expected:
- VitePress prints a local URL such as `http://localhost:5173/`
- The new page is reachable at `/en/reference-data/exchange-rates`
- [ ] **Step 2: Verify the happy path in the browser**
Open the page and confirm:
- The latest month loads automatically
- The month selector is populated
- Metadata shows month, base currency, and generation timestamp
- The full table renders with all rows from the selected month JSON
- [ ] **Step 3: Verify month switching and cache reuse**
Switch to an older month, then switch back to the original month.
Expected:
- Metadata changes with the selected month
- Table rows update with the selected month payload
- The second visit to a previously loaded month reuses the in-memory cache instead of issuing a new request
Use the browser Network panel to confirm that switching back to an already loaded month does not issue another `YYYY-MM.json` request.
- [ ] **Step 4: Verify the blocking index error state**
Temporarily change `exchangeRatesIndexUrl` in `en/reference-data/exchange-rates.md` so it points at a missing JSON file in the same CDN directory. For example, keep the same base path but replace `index.json` with `does-not-exist.json`.
Refresh the page and confirm:
- The feature shows the blocking error state
- The retry button is visible
Restore the real `indexUrl` immediately after verification.
- [ ] **Step 5: Verify the month-file error state**
Temporarily change the component `monthUrl()` helper to return a missing file name:
```ts
function monthUrl(month: string): string {
return new URL(`${month}-missing.json`, baseUrl.value).toString()
}
```
Load the page and confirm:
- The month selector still renders
- The table area shows the month-level error state
- The retry button is visible
Restore the real `monthUrl()` implementation immediately after verification.
- [ ] **Step 6: Verify the empty state**
If the CDN can provide a temporary empty month fixture, use it. Otherwise, temporarily stub an empty month payload inside `loadMonth()` after validation:
```ts
monthData.value = {
...payload,
rates: []
}
```
Confirm the empty-state message appears instead of the table, then restore the real assignment:
```ts
monthData.value = payload
```
- [ ] **Step 7: Run the final build**
Run: `npm run build`
Expected:
- Exit code `0`
- Final implementation builds cleanly after all temporary verification edits are restored
- [ ] **Step 8: Commit the final verified version**
```bash
git add .vitepress/theme/components/ExchangeRatesTable.vue en/reference-data/exchange-rates.md .vitepress/config/en.ts
git commit -m "feat: add exchange rate reference"
```
---
URL: "https://docs.revosurge.com/docs/superpowers/specs/2026-03-18-exchange-rates-design"
LLMS_URL: "https://docs.revosurge.com/docs/superpowers/specs/2026-03-18-exchange-rates-design.md"
---
# Monthly Exchange Rates Page Design
## Summary
Add one English documentation page that displays a monthly exchange-rate table. The data will not be fetched during the VitePress build. Instead, an internal DAG will periodically fetch the private source data, transform it into static JSON files, and publish those files to a CDN. The docs page will load the latest month at runtime in the browser, allow the reader to switch months, and render the full rate table for the selected month.
This design is intentionally narrow. It does not introduce a shared data layer or a reusable cross-page component system. It implements one page-specific feature with one page-specific Vue component.
## Context
This repository is a static VitePress site deployed to GitHub Pages. The current deployment workflow runs on GitHub-hosted runners and builds static output only. That environment should not be responsible for reaching private Kubernetes services.
The chosen integration model is:
1. Internal DAG fetches private API data on a schedule.
2. DAG writes frontend-ready JSON to a CDN.
3. The docs page reads the CDN JSON at runtime in the browser.
This keeps private network access, authentication, and API shaping outside the docs repository.
## Goals
- Show a monthly exchange-rate table on one docs page.
- Default to the latest available month.
- Allow users to switch months and see the full dataset for that month.
- Keep the docs site purely static and browser-driven for this feature.
- Keep the implementation simple and local to this page.
## Non-Goals
- No build-time fetch from the exchange-rate data source.
- No GitHub Actions access to private Kubernetes services.
- No generic shared data-fetching framework.
- No global component registration for this feature.
- No charting, CSV export, filtering, or search in the first version.
- No Simplified Chinese or Traditional Chinese versions in the first version.
- No compatibility layer for multiple JSON schema versions.
## File Layout
The implementation will use these files:
- `en/reference-data/exchange-rates.md`
- `.vitepress/theme/components/ExchangeRatesTable.vue`
- `.vitepress/config/en.ts`
`en/reference-data/exchange-rates.md` will contain the page copy, import the page-specific component locally, and pass one required prop: `indexUrl`. `.vitepress/config/en.ts` will add a top-level English sidebar group named `Reference Data`, with a page entry named `Exchange Rate Reference`. The component will not be registered globally in `.vitepress/theme/index.ts`.
## Runtime Architecture
The page will import `ExchangeRatesTable.vue` and render it once. The component will accept one required prop, `indexUrl`, which points to the CDN index file. The component will derive monthly file URLs from the same directory as `indexUrl`. The component will own the runtime behavior for this page:
1. On client mount, request the CDN `index.json`.
2. Read the latest month and the available month list from that file.
3. Select the latest month by default.
4. Request the selected month JSON file.
5. Render the month metadata and the full rate table.
6. When the user changes the month, request the corresponding month JSON file and re-render the table.
The component will perform all network requests in the browser only. It will not fetch during SSR or the static build.
## CDN Data Contract
The docs page will consume two JSON shapes.
### Index file
Location pattern:
`https:///exchange-rates/index.json`
Required shape:
```json
{
"latestMonth": "2026-03",
"months": ["2026-03", "2026-02", "2026-01"]
}
```
Rules:
- `latestMonth` is required and must match one entry in `months`.
- `months` is required and contains month identifiers in `YYYY-MM` format.
- The page will sort the months in descending lexicographic order before rendering. `YYYY-MM` is chosen specifically so simple string sorting is valid.
### Monthly file
Location pattern:
`https:///exchange-rates/YYYY-MM.json`
Required shape:
```json
{
"month": "2026-03",
"baseCurrency": "USD",
"generatedAt": "2026-03-01T00:00:00Z",
"rates": [
{ "currency": "EUR", "rate": 0.92 },
{ "currency": "JPY", "rate": 149.31 }
]
}
```
Rules:
- `month` is required and must equal the requested `YYYY-MM`.
- `baseCurrency` is required.
- `generatedAt` is required and must be an ISO-8601 UTC timestamp string.
- `rates` is required.
- Each `rates` item must contain:
- `currency`: currency code string
- `rate`: numeric exchange rate
The page will treat this schema as strict. If required fields are missing or malformed, the component will show an error state instead of attempting to infer or repair the data.
## Publish and Caching Requirements
The feature depends on the CDN behaving predictably.
Required external conditions:
- Files are publicly reachable over HTTPS.
- The CDN serves the JSON with `Content-Type: application/json`.
- The CDN allows browser access from `https://docs.revosurge.com` via CORS, or allows all origins.
Publishing rules for the DAG:
- Upload the new monthly file first.
- Update `index.json` last.
This prevents the docs page from seeing a new `latestMonth` before the corresponding monthly file exists on the CDN.
Caching guidance:
- `index.json` should have a short cache lifetime because it changes when a new month becomes available.
- Monthly files should have a longer cache lifetime because a month file is expected to be immutable after publication.
## Page UX
The page will display:
- A month selector.
- The selected month.
- The base currency.
- The data generation timestamp in UTC.
- A full table with one row per currency.
The initial page state is:
- Show a loading state while `index.json` and the first monthly file are being requested.
- After both requests succeed, show the month selector and the table.
Month switching behavior:
- When a user selects another month, the component requests only that month file.
- The component does not re-request `index.json` during month switching.
The table will use a horizontally scrollable wrapper on smaller screens so the page remains usable on mobile without collapsing the dataset into cards.
## Error and Empty States
The page will support three explicit UI states:
- `loading`
- `error`
- `empty`
Behavior rules:
- If `index.json` fails to load or is invalid, show a blocking error state for the whole feature area.
- If the selected month file fails to load or is invalid, keep the month selector visible and show an error state for the table area with a retry action.
- If the selected month file loads successfully but `rates` is empty, show an empty state message instead of the table.
The first version does not need nuanced partial recovery beyond these rules.
## Client Behavior
The component will keep a simple in-memory cache keyed by month. If a user switches from one month to another and then back, the component should reuse the already loaded JSON from memory during that page session. The cache does not need persistence across reloads, tabs, or browser sessions.
The component will not use local storage, indexed DB, or service workers.
## Implementation Boundaries
This feature should remain page-specific.
Explicit boundaries:
- Use a single page-specific Vue component.
- Import the component directly into the exchange-rates page.
- Do not create a shared hook, shared store, or multi-endpoint abstraction.
- Do not add this feature to `.vitepress/theme/index.ts` unless a future requirement creates a real need for broader registration.
## Verification Requirements
Implementation is complete when all of the following are true:
- The English page exists at `en/reference-data/exchange-rates.md`.
- The English sidebar contains a top-level `Reference Data` group with an `Exchange Rate Reference` entry.
- Opening the page loads the latest available month by default.
- Switching months updates the displayed metadata and table correctly.
- The `loading`, `error`, and `empty` states are each supported.
- The table remains usable on mobile through horizontal scrolling.
- `npm run build` succeeds without SSR or VitePress errors.
Manual verification is sufficient for the first version. No dedicated test framework is required for this feature.
## Recommendation For Planning
When writing the implementation plan, keep the work split into three focused parts:
1. Create the page-specific Vue component and runtime fetch logic.
2. Add the new English docs page and sidebar entry.
3. Verify runtime behavior, responsive layout, and build success.
---
URL: "https://docs.revosurge.com/en"
LLMS_URL: "https://docs.revosurge.com/en.md"
title: "RevoSurge Platform Docs"
layout: "home"
description: "RevoSurge docs. Performance campaigns, first-party tracking, account, API."
hero:
name: "RevoSurge"
text: "Platform Docs"
tagline: "A unified platform for running performance campaigns and measuring outcomes with first-party data."
actions:
- theme: "brand"
text: "Get started"
link: "/en/growth/getting-started"
- theme: "alt"
text: "Overview"
link: "/en/revosurge/welcome"
features:
- title: "Performance Campaigns"
details: "Launch and optimize campaigns in AdWave with guided setup workflows and real-time validation."
- title: "First-Party Tracking"
details: "Install trackers, validate events, and measure outcomes using DataPulse analytics."
- title: "Account Management"
details: "Manage your account, wallet, team members, and permissions all in one place."
- title: "API Integration"
details: "Automate campaign management, reporting, and audience segmentation with comprehensive APIs."
---
---
URL: "https://docs.revosurge.com/en/adflow/adflowjs-debugger"
LLMS_URL: "https://docs.revosurge.com/en/adflow/adflowjs-debugger.md"
title: "adflow.js Debugger"
description: "Test adflow.js in-browser. Configure URL, account ID, placement to validate S2S bidding."
---
# adflow.js Test
Test the adflow.js one-script integration: just include the script and place iframe tags to enable Prebid S2S bidding.
## Configuration
## Code Preview
Auto-generated integration code based on the parameters above. Publishers can copy and paste to integrate:
Generated HTML Code
## Test Status
Execution Status
Script LoadWaiting
Config ReadWaiting
Slot DiscoveryWaiting
Prebid.js LoadWaiting
S2S AuctionWaiting
Ad RenderingWaiting
Runtime Config
Status:Not Started
## Ad Preview
Test Ad Slot (300x250)
data-placement-id="test-placement-1"
Waiting for auction...
## Logs
---
URL: "https://docs.revosurge.com/en/adflow/integration-guide"
LLMS_URL: "https://docs.revosurge.com/en/adflow/integration-guide.md"
title: "Publisher Integration Guide"
description: "Integrate adflow.js or Prebid S2S to place ads. adflow.js or S2S step-by-step guide."
---
# Publisher Integration Guide
This guide covers how to integrate ads into your website. We offer two integration approaches: [adflow.js Quick Integration](#adflow-sdk) (recommended, simplest) and [S2S Configuration](#s2s-integration) (manual setup, more flexible).
## Integration Modes Comparison
| Dimension | adflow.js Quick Integration | S2S Configuration |
| --- | --- | --- |
| **Complexity** | Minimal — just 2 lines of HTML | Moderate — requires JS coding |
| **Prebid.js Knowledge** | Not required | Required |
| **Ad Formats** | Banner | Banner / Video / Native / Multi-Format |
| **Rendering** | Automatic iframe rendering | Full control, custom rendering supported |
| **Configuration** | HTML data attributes | Full Prebid.js config API |
| **Preferred Deal** | Supported | Supported |
| **Advanced Features** | Basic configuration | Price Granularity, User Sync, First Party Data, etc. |
| **Recommended For** | Quick launch, simple pages, no frontend dev resources | Production environments, complex requirements, fine-grained control |
## adflow.js Quick Integration {#adflow-sdk}
adflow.js is a self-contained JavaScript SDK that encapsulates all Prebid.js S2S bidding logic into a single script. Publishers only need to include one `
```
**2. Place Ad Slots**
Add `