docs: add detailed spec for real-time web analytics dashboard#861
docs: add detailed spec for real-time web analytics dashboard#861grunch wants to merge 1 commit into
Conversation
Add a comprehensive implementation guide for a read-only web dashboard that connects to the bot's MongoDB and surfaces real-time operational and financial statistics: top fiat currencies by successful orders, daily/ monthly/custom-range metrics, filters by order type and status, node inbound/outbound sat flow, and earnings reconciliation. Covers data model, canonical metric definitions, system architecture, REST + WebSocket API, MongoDB aggregation pipelines, the exact fee/ earnings reconciliation formulas mirrored from the bot, Lightning node fund-flow tracking, real-time via change streams, frontend views/filters, security/privacy, indexing/caching, deployment, a phased plan, and tests. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01X5uNqd26cC88p5HVqErRDU
WalkthroughThis PR adds a single new documentation file, docs/ANALYTICS_DASHBOARD_SPEC.md, specifying a read-only analytics dashboard for lnp2pBot: scope, data model, metric definitions, architecture, REST API, MongoDB aggregation pseudocode, financial reconciliation, node fund flow, realtime strategy, frontend design, security, performance, deployment, testing, and appendices. ChangesAnalytics Dashboard Spec
Estimated code review effort: 2 (Simple) | ~10 minutes Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 3
🧹 Nitpick comments (1)
docs/ANALYTICS_DASHBOARD_SPEC.md (1)
1030-1037: 🚀 Performance & Scalability | 🔵 Trivial | ⚡ Quick winAdd index coverage for reconciliation and payout filters.
The proposed indexes miss
community_id, but your reconciliation and earnings/withdrawal queries filter on it. Without that field in the compound keys, those paths will stay scan-heavy as the dataset grows.📈 Suggested index adjustments
-orders: { status: 1, calculated: 1 } // conciliación -pendingpayments: { paid: 1, last_error: 1 } +orders: { community_id: 1, status: 1, calculated: 1 } // conciliación +pendingpayments: { community_id: 1, paid: 1, last_error: 1 }🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@docs/ANALYTICS_DASHBOARD_SPEC.md` around lines 1030 - 1037, The index list in the analytics dashboard spec is missing `community_id` coverage for the reconciliation and payout-related query paths, so update the index recommendations around the `orders` index definitions to include a compound key that starts with or includes `community_id` alongside the existing `status`, `created_at`, `type`, or `calculated` filters. Use the `orders` index entries in this section to locate the affected recommendations and adjust them so the reconciliation and earnings/withdrawal queries can use an index instead of scanning.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@docs/ANALYTICS_DASHBOARD_SPEC.md`:
- Around line 426-433: Clarify the semantics of the orders analytics endpoints
in ANALYTICS_DASHBOARD_SPEC so the time axis is explicitly based on created_at
and not on status-transition time; update the wording around GET
/api/v1/orders/count, GET /api/v1/orders/summary, GET /api/v1/orders/timeseries,
and GET /api/v1/orders/status-breakdown to say “orders created in the period and
currently in the selected status/type” rather than “orders canceled/successful
during the period.” If event-time analytics are intended, note that the model
must expose transition timestamps such as canceled_at and success_at, or
otherwise narrow the endpoint descriptions accordingly.
- Line 1071: The example Mongo URI in the analytics dashboard spec includes
embedded credentials, which should be removed from the sample. Update the
ANALYTICS_MONGO_URI example to use a redacted host-only URI and keep
authentication material out of the documented config; locate the example by the
ANALYTICS_MONGO_URI symbol in the docs and replace the credentialed form with a
safer placeholder.
- Around line 538-557: The ranking pipeline in the analytics spec currently
computes only unique buyers via traders/$addToSet on buyer_id, which does not
match the defined unique_traders metric. Update the aggregation in
ANALYTICS_DASHBOARD_SPEC to either compute the buyer_id ∪ seller_id union before
$size (using the existing unique_traders definition) or rename the exposed field
everywhere to unique_buyers so the metric and pipeline stay consistent.
---
Nitpick comments:
In `@docs/ANALYTICS_DASHBOARD_SPEC.md`:
- Around line 1030-1037: The index list in the analytics dashboard spec is
missing `community_id` coverage for the reconciliation and payout-related query
paths, so update the index recommendations around the `orders` index definitions
to include a compound key that starts with or includes `community_id` alongside
the existing `status`, `created_at`, `type`, or `calculated` filters. Use the
`orders` index entries in this section to locate the affected recommendations
and adjust them so the reconciliation and earnings/withdrawal queries can use an
index instead of scanning.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro
Run ID: 8dc63b0a-1768-4b2d-8001-78cf32ff3138
📒 Files selected for processing (1)
docs/ANALYTICS_DASHBOARD_SPEC.md
| - `GET /api/v1/orders/summary` — conteos por estado y por tipo en el rango. | ||
| - `GET /api/v1/orders/timeseries` — serie temporal por `granularity` de una | ||
| métrica (`metric=count|volume_sats|volume_fiat|success_rate`), opcionalmente | ||
| desglosada (`groupBy=status|type|fiat`). | ||
| - `GET /api/v1/orders/status-breakdown` — distribución por estado (para donut). | ||
| - `GET /api/v1/orders/count?status=CANCELED&from=…&to=…` — caso de uso explícito: | ||
| "número de órdenes canceladas en un periodo". (Atajo conveniente.) | ||
|
|
There was a problem hiding this comment.
🗄️ Data Integrity & Integration | 🟠 Major | 🏗️ Heavy lift
Clarify the time axis for status counts.
These queries count orders by created_at, so “canceladas en un periodo” means “created in the period and currently canceled,” not “canceled during the period.” If you need event-time analytics, the model needs explicit transition timestamps (canceled_at, success_at, etc.) or the endpoint wording should be narrowed.
Also applies to: 559-566
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@docs/ANALYTICS_DASHBOARD_SPEC.md` around lines 426 - 433, Clarify the
semantics of the orders analytics endpoints in ANALYTICS_DASHBOARD_SPEC so the
time axis is explicitly based on created_at and not on status-transition time;
update the wording around GET /api/v1/orders/count, GET /api/v1/orders/summary,
GET /api/v1/orders/timeseries, and GET /api/v1/orders/status-breakdown to say
“orders created in the period and currently in the selected status/type” rather
than “orders canceled/successful during the period.” If event-time analytics are
intended, note that the model must expose transition timestamps such as
canceled_at and success_at, or otherwise narrow the endpoint descriptions
accordingly.
| ```js | ||
| db.orders.aggregate([ | ||
| { $match: { status: "SUCCESS", created_at: { $gte: from, $lt: to } } }, | ||
| { $group: { | ||
| _id: "$fiat_code", | ||
| successful_orders: { $sum: 1 }, | ||
| volume_sats: { $sum: "$amount" }, | ||
| volume_fiat: { $sum: { $ifNull: ["$fiat_amount", 0] } }, | ||
| avg_ticket_sats: { $avg: "$amount" }, | ||
| traders: { $addToSet: "$buyer_id" } // aproximación; ver nota | ||
| }}, | ||
| { $addFields: { unique_buyers: { $size: "$traders" } } }, | ||
| { $project: { traders: 0 } }, | ||
| { $sort: { successful_orders: -1 } }, | ||
| { $limit: limit } | ||
| ]) | ||
| ``` | ||
|
|
||
| > Para `unique_traders` exacto (compradores ∪ vendedores) usar dos `$addToSet` | ||
| > (`buyer_id`, `seller_id`) y unir con `$setUnion` antes de `$size`. |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
Align the ranking pipeline with unique_traders.
The metric definition says buyer ∪ seller cardinality, but the pipeline only deduplicates buyer_id and then exposes unique_buyers. Either compute the union here or rename the metric, otherwise the ranking will systematically undercount.
♻️ Proposed fix
- traders: { $addToSet: "$buyer_id" } // aproximación; ver nota
- }},
- { $addFields: { unique_buyers: { $size: "$traders" } } },
- { $project: { traders: 0 } },
+ buyers: { $addToSet: "$buyer_id" },
+ sellers: { $addToSet: "$seller_id" }
+ }},
+ { $addFields: {
+ unique_traders: {
+ $size: { $setUnion: ["$buyers", "$sellers"] }
+ }
+ }},
+ { $project: { buyers: 0, sellers: 0 } },📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| ```js | |
| db.orders.aggregate([ | |
| { $match: { status: "SUCCESS", created_at: { $gte: from, $lt: to } } }, | |
| { $group: { | |
| _id: "$fiat_code", | |
| successful_orders: { $sum: 1 }, | |
| volume_sats: { $sum: "$amount" }, | |
| volume_fiat: { $sum: { $ifNull: ["$fiat_amount", 0] } }, | |
| avg_ticket_sats: { $avg: "$amount" }, | |
| traders: { $addToSet: "$buyer_id" } // aproximación; ver nota | |
| }}, | |
| { $addFields: { unique_buyers: { $size: "$traders" } } }, | |
| { $project: { traders: 0 } }, | |
| { $sort: { successful_orders: -1 } }, | |
| { $limit: limit } | |
| ]) | |
| ``` | |
| > Para `unique_traders` exacto (compradores ∪ vendedores) usar dos `$addToSet` | |
| > (`buyer_id`, `seller_id`) y unir con `$setUnion` antes de `$size`. |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@docs/ANALYTICS_DASHBOARD_SPEC.md` around lines 538 - 557, The ranking
pipeline in the analytics spec currently computes only unique buyers via
traders/$addToSet on buyer_id, which does not match the defined unique_traders
metric. Update the aggregation in ANALYTICS_DASHBOARD_SPEC to either compute the
buyer_id ∪ seller_id union before $size (using the existing unique_traders
definition) or rename the exposed field everywhere to unique_buyers so the
metric and pipeline stay consistent.
|
|
||
| ```bash | ||
| # Conexión DB (solo lectura) | ||
| ANALYTICS_MONGO_URI='mongodb://readonly_user:pass@host:27017/p2plnbot?authSource=admin&readPreference=secondaryPreferred' |
There was a problem hiding this comment.
🔒 Security & Privacy | 🟠 Major | ⚡ Quick win
Remove credentials from the example Mongo URI.
Even as a sample, readonly_user:pass@... encourages putting auth material directly in config. Prefer a redacted host-only URI and separate secret delivery for credentials.
🔐 Safer example
-ANALYTICS_MONGO_URI='mongodb://readonly_user:pass@host:27017/p2plnbot?authSource=admin&readPreference=secondaryPreferred'
+ANALYTICS_MONGO_URI='mongodb://host:27017/p2plnbot?authSource=admin&readPreference=secondaryPreferred'
+# Provide username/password via your secret store or separate env vars.📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| ANALYTICS_MONGO_URI='mongodb://readonly_user:pass@host:27017/p2plnbot?authSource=admin&readPreference=secondaryPreferred' | |
| ANALYTICS_MONGO_URI='mongodb://host:27017/p2plnbot?authSource=admin&readPreference=secondaryPreferred' | |
| # Provide username/password via your secret store or separate env vars. |
🧰 Tools
🪛 Betterleaks (1.6.0)
[high] 1071-1071: Detected a MongoDB connection string with embedded credentials, potentially exposing direct database access and sensitive application data.
(mongodb-connection-string)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@docs/ANALYTICS_DASHBOARD_SPEC.md` at line 1071, The example Mongo URI in the
analytics dashboard spec includes embedded credentials, which should be removed
from the sample. Update the ANALYTICS_MONGO_URI example to use a redacted
host-only URI and keep authentication material out of the documented config;
locate the example by the ANALYTICS_MONGO_URI symbol in the docs and replace the
credentialed form with a safer placeholder.
Add a comprehensive implementation guide for a read-only web dashboard
that connects to the bot's MongoDB and surfaces real-time operational and
financial statistics: top fiat currencies by successful orders, daily/
monthly/custom-range metrics, filters by order type and status, node
inbound/outbound sat flow, and earnings reconciliation.
Covers data model, canonical metric definitions, system architecture,
REST + WebSocket API, MongoDB aggregation pipelines, the exact fee/
earnings reconciliation formulas mirrored from the bot, Lightning node
fund-flow tracking, real-time via change streams, frontend views/filters,
security/privacy, indexing/caching, deployment, a phased plan, and tests.
Co-Authored-By: Claude Opus 4.8 noreply@anthropic.com
Claude-Session: https://claude.ai/code/session_01X5uNqd26cC88p5HVqErRDU
Summary by CodeRabbit