feat: LAPI metrics v2, processed traffic tracking, and Grafana dashboard v32 (#7)
## Summary
Enhanced metrics reporting with per-IP-type labels, processed traffic
tracking via passthrough firewall rules, and updated Grafana dashboard.
## Changes
### LAPI Metrics v2
- Enrich LAPI usage metrics with `ip_type` labels (`ipv4`, `ipv6`) for
dropped/processed counters
- Per-IP-type delta tracking for accurate LAPI reporting
### Passthrough Counting Rules
- Automatically create passthrough firewall rules (filter + raw) to
count processed traffic (bytes/packets)
- Rules are placed before the bouncer drop rules using `PlaceBefore` for
accurate counting
- Supports both IPv4 and IPv6 chains
### Prometheus Processed Traffic Metrics
- 4 new Prometheus gauges: `crowdsec_routeros_processed_bytes` and
`crowdsec_routeros_processed_packets` (per `ip_version` and
`chain_type`)
- Metrics are collected from the passthrough counting rules on each
reconciliation cycle
### Configurable `track_processed`
- New `metrics.track_processed` config option (default: `true`,
advanced)
- When disabled, skips creation of counting rules and omits processed
metrics from Prometheus and LAPI
- Documented in configuration reference and Grafana guide
### Grafana Dashboard v32
- Synced from live Grafana (40→50 panels) with new processed traffic
panels
- Templatized all datasource UIDs (`${DS_PROMETHEUS}`) with
`__inputs`/`__requires` for portable import
- Updated dark/light screenshots for documentation
## Testing
- Unit tests updated for new metrics and config options
- Functional tests cover passthrough rule creation and processed metric
collection
- `go vet` passes cleanly
## Summary by Sourcery
Add per-IP-type dropped and processed traffic metrics for RouterOS
firewall rules, expose them to Prometheus and LAPI, and update
configuration, tests, and monitoring docs (including Grafana dashboard
structure) to support processed traffic tracking and the new metrics.
New Features:
- Track processed firewall traffic via RouterOS passthrough counting
rules and expose per-protocol processed byte/packet metrics to
Prometheus and CrowdSec LAPI.
- Report dropped and processed traffic to LAPI with ip_type labels for
IPv4 and IPv6, including delta-based counters per protocol.
Enhancements:
- Refine firewall counter aggregation to distinguish total, dropped, and
processed traffic and to support per-IP-type delta tracking for LAPI.
- Extend Grafana dashboard layout and documentation to include processed
traffic and clearer panel organization.
- Expose a new advanced metrics.track_processed configuration option
with default enabled and surface it via metrics config info.
Documentation:
- Expand Prometheus and LAPI metrics documentation to cover processed
traffic metrics, ip_type labels, and example PromQL queries.
- Rewrite Grafana monitoring guide with prerequisites, step-by-step
setup, and updated panel descriptions reflecting the new dashboard.
Tests:
- Add and update unit and functional tests for per-IP-type delta
computation, processed/dropped counter handling, RouterOS firewall
counter aggregation, counting rule creation, concurrency safety, and the
new configuration defaults.
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **New Features**
* Added metrics.track_processed toggle to enable/disable processed
traffic monitoring
* New Prometheus metrics for processed traffic with per-protocol
(IPv4/IPv6) breakdown
* Per‑IP‑type reporting for dropped and processed traffic
* **Documentation**
* Grafana dashboard updated with Processed Traffic panels and
reorganized panel structure
* Configuration docs updated with the new metrics parameter and examples
* Prometheus docs expanded with Processed Traffic metrics and PromQL
examples
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
feat: LAPI metrics v2, processed traffic tracking, and Grafana dashboard v32 (#7)
## Summary
Enhanced metrics reporting with per-IP-type labels, processed traffic
tracking via passthrough firewall rules, and updated Grafana dashboard.
## Changes
### LAPI Metrics v2
- Enrich LAPI usage metrics with `ip_type` labels (`ipv4`, `ipv6`) for
dropped/processed counters
- Per-IP-type delta tracking for accurate LAPI reporting
### Passthrough Counting Rules
- Automatically create passthrough firewall rules (filter + raw) to
count processed traffic (bytes/packets)
- Rules are placed before the bouncer drop rules using `PlaceBefore` for
accurate counting
- Supports both IPv4 and IPv6 chains
### Prometheus Processed Traffic Metrics
- 4 new Prometheus gauges: `crowdsec_routeros_processed_bytes` and
`crowdsec_routeros_processed_packets` (per `ip_version` and
`chain_type`)
- Metrics are collected from the passthrough counting rules on each
reconciliation cycle
### Configurable `track_processed`
- New `metrics.track_processed` config option (default: `true`,
advanced)
- When disabled, skips creation of counting rules and omits processed
metrics from Prometheus and LAPI
- Documented in configuration reference and Grafana guide
### Grafana Dashboard v32
- Synced from live Grafana (40→50 panels) with new processed traffic
panels
- Templatized all datasource UIDs (`${DS_PROMETHEUS}`) with
`__inputs`/`__requires` for portable import
- Updated dark/light screenshots for documentation
## Testing
- Unit tests updated for new metrics and config options
- Functional tests cover passthrough rule creation and processed metric
collection
- `go vet` passes cleanly
## Summary by Sourcery
Add per-IP-type dropped and processed traffic metrics for RouterOS
firewall rules, expose them to Prometheus and LAPI, and update
configuration, tests, and monitoring docs (including Grafana dashboard
structure) to support processed traffic tracking and the new metrics.
New Features:
- Track processed firewall traffic via RouterOS passthrough counting
rules and expose per-protocol processed byte/packet metrics to
Prometheus and CrowdSec LAPI.
- Report dropped and processed traffic to LAPI with ip_type labels for
IPv4 and IPv6, including delta-based counters per protocol.
Enhancements:
- Refine firewall counter aggregation to distinguish total, dropped, and
processed traffic and to support per-IP-type delta tracking for LAPI.
- Extend Grafana dashboard layout and documentation to include processed
traffic and clearer panel organization.
- Expose a new advanced metrics.track_processed configuration option
with default enabled and surface it via metrics config info.
Documentation:
- Expand Prometheus and LAPI metrics documentation to cover processed
traffic metrics, ip_type labels, and example PromQL queries.
- Rewrite Grafana monitoring guide with prerequisites, step-by-step
setup, and updated panel descriptions reflecting the new dashboard.
Tests:
- Add and update unit and functional tests for per-IP-type delta
computation, processed/dropped counter handling, RouterOS firewall
counter aggregation, counting rule creation, concurrency safety, and the
new configuration defaults.
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **New Features**
* Added metrics.track_processed toggle to enable/disable processed
traffic monitoring
* New Prometheus metrics for processed traffic with per-protocol
(IPv4/IPv6) breakdown
* Per‑IP‑type reporting for dropped and processed traffic
* **Documentation**
* Grafana dashboard updated with Processed Traffic panels and
reorganized panel structure
* Configuration docs updated with the new metrics parameter and examples
* Prometheus docs expanded with Processed Traffic metrics and PromQL
examples
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
feat(docs): new brand mark, CrowdSec indigo, four diagrams, and the i18n gate on the MDX AST (#95)
## Description
Phases 5 to 7 of the documentation plan, plus the technical debt that
had accumulated in the i18n gate, plus a new brand mark chosen from
twenty-nine candidates.
## Type of change
- [x] ✨ New feature (non-breaking change that adds functionality)
- [x] 📖 Documentation update
- [x] 🧪 Tests / tooling / CI
- [x] 🧹 Refactoring / code cleanup
## Changes
### The i18n parity gate is rewritten onto the MDX AST
It had produced **three defects in one area** — an HTML-comment
terminator that missed `--!>`, a chained-replace sanitisation that left
a bare `<!--` behind, and a one-character backtick delimiter that leaked
double-backtick spans. Two were found by CodeQL, one in review. Three
findings in one file say the approach is wrong, not that the patches
were bad; parsing makes those classes unreachable.
All four parser packages were **already resolved in the lockfile**, so
declaring them added nothing to install.
Verified by a **differential harness over all 56 corpus files across six
dimensions**, which caught a regression the rewrite introduced and
surfaced a genuine improvement: three multi-path `ConfigOption`
invocations that used to collapse into one indistinguishable bucket are
now keyed individually. Demonstrated: a Spanish page pointing at a
non-existent config path **passed** the old gate and fails the new one.
It also corrected a claim the old file asserted: an HTML comment closed
with `--!>` is **not** closed for the renderer. CommonMark ends an HTML
block only at `-->`, so the earlier "fix" was wrong in the other
direction.
### A new mark
The shield is gone. Rendered side by side at the sizes that matter it
was, unmistakably, **the WiFi glyph** — a shield containing concentric
arcs radiating from a dot is the standard signal icon at 104px and at
23px. Nobody noticed until the candidates were laid out and looked at.
For a network tool that is worse than generic; it is misleading.
What replaces it: four lanes meeting a rail, three crossing and
continuing, one stopping dead at it. The proportion is deliberate — a
firewall does not block everything, it blocks the exception. **Three
primitives, 282 bytes of geometry, no ids, no defs, no mask**, against
the 3.8 KB the shield needed.
Chosen from 29 candidates across two waves. The first wave's five
directions all came from the data side — list, chain, loop, flow — and
its winner drew a generic list; the siblings anchor on a git ref and an
open book, objects that only exist in their domains. The second wave
entered through the domain and beat it on all four judging lenses.
### The accent moves to CrowdSec's indigo
`#4d4a98` light, `#807dc0` dark — the same hue and saturation raised
until it clears 4.5:1 against the **surface** rather than merely the
page. The page-only value failed twice, on the terminal prompt glyph and
the sidebar pill, and the contrast gate caught both.
This is ecosystem alignment, not a return to the co-branding retired
earlier: that palette paired CrowdSec indigo *with* MikroTik teal,
implying endorsement by two vendors including the hardware one. This is
a CrowdSec bouncer, listed on their Hub. **Worth checking their brand
guidelines before a release goes out.**
The rail takes the accent because the boundary is what the product is.
Pass and stop are carried by **length before colour**: the accent and
the muted tone measure 1.19:1 apart, so a mark relying on that pair to
tell them apart would come very close to collapsing into one tone in
greyscale.
CrowdSec's amber moves to `--rb-status-warn`, where it does semantic
work rather than decorating.
### Four architecture diagrams, under one convention
The rule-placement ladder, the decision funnel in three swimlanes, the
reconciliation diff and the shutdown order. Solid is a write, dashed is
a read, carried on three channels — line pattern, then colour, then a
legend inside each diagram — so they survive greyscale, colour vision
deficiency and a printout.
Six accuracy defects in them were corrected against the Go source. One
claim was rewritten rather than deleted: entries whose comment does not
match the prefix were described as "never listed", but `ListAddresses`
queries on the list name alone and filters client-side, so they **are**
fetched every pass and only then dropped — which costs transfer on a
list an operator may be sharing.
### Navigation
Sidebar depth hierarchy, pagination that names its destination (two
entries were both labelled "Overview"), scroll-into-view, and a **mobile
theme toggle** — there was none, the header hid the control below 50rem.
It never writes `data-theme` or `localStorage` itself: it drives
Starlight's own select and reads state back via a MutationObserver,
because anything else desynchronises from the desktop control and the
before-paint script.
## Testing
- [x] `pnpm analyze` exits 0 — config schema check, brand raster check,
i18n parity, contrast, `astro check`, ESLint, Prettier, build,
`html-validate`
- [x] `go build ./...`, `go test -race ./...`, golangci-lint, gosec,
staticcheck, govulncheck all clean; markdownlint clean
- [x] Every gate mutation-tested in both directions, including the
parity gate's twelve behaviours and the new brand-raster check
- [x] Rendered SVGs inspected in `dist/` — all 62 diagram edges parse,
dashed edges carry a real `stroke-dasharray`, and the mermaid CSS
ordering was checked so the dotted class actually wins
- [ ] Tested against a real MikroTik router (not applicable — no
behavioural change ships here)
## Notes for review
Four claims **of my own** were wrong and are corrected in the last
commit: a stale contrast figure in all three copies of the mark, the
`prefers-contrast` block still pointing at the retired teal, a comment
describing lanes "cut by the rail" that are unbroken rectangles, and a
false provenance claim about the sibling status fills' saturation.
An intermittent `analyze` failure reported by three agents did not
reproduce — 8 clean builds out of 8 in isolation. The cause was
concurrent agents building into the same `dist/`.
https://claude.ai/code/session_01ENguejGi5gZcxoMbCKWFBy
<!-- This is an auto-generated description by cubic. -->
<a
href="https://cubic.dev/pr/jmrplens/cs-routeros-bouncer/pull/95?utm_source=github"
target="_blank" rel="noopener noreferrer"
data-no-image-dialog="true"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"><source
media="(prefers-color-scheme: light)"
srcset="https://www.cubic.dev/buttons/review-in-cubic-light.svg"><img
alt="Review in cubic"
src="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"></picture></a>
<!-- End of auto-generated description by cubic. -->
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **New Features**
* Introduced refreshed CrowdSec Indigo branding across the documentation
site, including responsive wordmark, icons, and social images.
* Added light/dark theme support for diagrams and documentation images.
* Added mobile theme switching and improved sidebar, header, pagination,
and navigation behavior.
* Added clearer architecture diagrams, flow explanations, and Grafana
dashboard imagery.
* **Documentation**
* Expanded English and Spanish guidance for decision filtering,
firewall-rule placement, reconciliation, shutdown behavior, and decision
lifecycles.
* Clarified read/write diagram conventions and operational edge cases.
* **Bug Fixes**
* Improved validation for localized documentation structure and
generated brand assets.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
feat(docs): new brand mark, CrowdSec indigo, four diagrams, and the i18n gate on the MDX AST (#95)
## Description
Phases 5 to 7 of the documentation plan, plus the technical debt that
had accumulated in the i18n gate, plus a new brand mark chosen from
twenty-nine candidates.
## Type of change
- [x] ✨ New feature (non-breaking change that adds functionality)
- [x] 📖 Documentation update
- [x] 🧪 Tests / tooling / CI
- [x] 🧹 Refactoring / code cleanup
## Changes
### The i18n parity gate is rewritten onto the MDX AST
It had produced **three defects in one area** — an HTML-comment
terminator that missed `--!>`, a chained-replace sanitisation that left
a bare `<!--` behind, and a one-character backtick delimiter that leaked
double-backtick spans. Two were found by CodeQL, one in review. Three
findings in one file say the approach is wrong, not that the patches
were bad; parsing makes those classes unreachable.
All four parser packages were **already resolved in the lockfile**, so
declaring them added nothing to install.
Verified by a **differential harness over all 56 corpus files across six
dimensions**, which caught a regression the rewrite introduced and
surfaced a genuine improvement: three multi-path `ConfigOption`
invocations that used to collapse into one indistinguishable bucket are
now keyed individually. Demonstrated: a Spanish page pointing at a
non-existent config path **passed** the old gate and fails the new one.
It also corrected a claim the old file asserted: an HTML comment closed
with `--!>` is **not** closed for the renderer. CommonMark ends an HTML
block only at `-->`, so the earlier "fix" was wrong in the other
direction.
### A new mark
The shield is gone. Rendered side by side at the sizes that matter it
was, unmistakably, **the WiFi glyph** — a shield containing concentric
arcs radiating from a dot is the standard signal icon at 104px and at
23px. Nobody noticed until the candidates were laid out and looked at.
For a network tool that is worse than generic; it is misleading.
What replaces it: four lanes meeting a rail, three crossing and
continuing, one stopping dead at it. The proportion is deliberate — a
firewall does not block everything, it blocks the exception. **Three
primitives, 282 bytes of geometry, no ids, no defs, no mask**, against
the 3.8 KB the shield needed.
Chosen from 29 candidates across two waves. The first wave's five
directions all came from the data side — list, chain, loop, flow — and
its winner drew a generic list; the siblings anchor on a git ref and an
open book, objects that only exist in their domains. The second wave
entered through the domain and beat it on all four judging lenses.
### The accent moves to CrowdSec's indigo
`#4d4a98` light, `#807dc0` dark — the same hue and saturation raised
until it clears 4.5:1 against the **surface** rather than merely the
page. The page-only value failed twice, on the terminal prompt glyph and
the sidebar pill, and the contrast gate caught both.
This is ecosystem alignment, not a return to the co-branding retired
earlier: that palette paired CrowdSec indigo *with* MikroTik teal,
implying endorsement by two vendors including the hardware one. This is
a CrowdSec bouncer, listed on their Hub. **Worth checking their brand
guidelines before a release goes out.**
The rail takes the accent because the boundary is what the product is.
Pass and stop are carried by **length before colour**: the accent and
the muted tone measure 1.19:1 apart, so a mark relying on that pair to
tell them apart would come very close to collapsing into one tone in
greyscale.
CrowdSec's amber moves to `--rb-status-warn`, where it does semantic
work rather than decorating.
### Four architecture diagrams, under one convention
The rule-placement ladder, the decision funnel in three swimlanes, the
reconciliation diff and the shutdown order. Solid is a write, dashed is
a read, carried on three channels — line pattern, then colour, then a
legend inside each diagram — so they survive greyscale, colour vision
deficiency and a printout.
Six accuracy defects in them were corrected against the Go source. One
claim was rewritten rather than deleted: entries whose comment does not
match the prefix were described as "never listed", but `ListAddresses`
queries on the list name alone and filters client-side, so they **are**
fetched every pass and only then dropped — which costs transfer on a
list an operator may be sharing.
### Navigation
Sidebar depth hierarchy, pagination that names its destination (two
entries were both labelled "Overview"), scroll-into-view, and a **mobile
theme toggle** — there was none, the header hid the control below 50rem.
It never writes `data-theme` or `localStorage` itself: it drives
Starlight's own select and reads state back via a MutationObserver,
because anything else desynchronises from the desktop control and the
before-paint script.
## Testing
- [x] `pnpm analyze` exits 0 — config schema check, brand raster check,
i18n parity, contrast, `astro check`, ESLint, Prettier, build,
`html-validate`
- [x] `go build ./...`, `go test -race ./...`, golangci-lint, gosec,
staticcheck, govulncheck all clean; markdownlint clean
- [x] Every gate mutation-tested in both directions, including the
parity gate's twelve behaviours and the new brand-raster check
- [x] Rendered SVGs inspected in `dist/` — all 62 diagram edges parse,
dashed edges carry a real `stroke-dasharray`, and the mermaid CSS
ordering was checked so the dotted class actually wins
- [ ] Tested against a real MikroTik router (not applicable — no
behavioural change ships here)
## Notes for review
Four claims **of my own** were wrong and are corrected in the last
commit: a stale contrast figure in all three copies of the mark, the
`prefers-contrast` block still pointing at the retired teal, a comment
describing lanes "cut by the rail" that are unbroken rectangles, and a
false provenance claim about the sibling status fills' saturation.
An intermittent `analyze` failure reported by three agents did not
reproduce — 8 clean builds out of 8 in isolation. The cause was
concurrent agents building into the same `dist/`.
https://claude.ai/code/session_01ENguejGi5gZcxoMbCKWFBy
<!-- This is an auto-generated description by cubic. -->
<a
href="https://cubic.dev/pr/jmrplens/cs-routeros-bouncer/pull/95?utm_source=github"
target="_blank" rel="noopener noreferrer"
data-no-image-dialog="true"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"><source
media="(prefers-color-scheme: light)"
srcset="https://www.cubic.dev/buttons/review-in-cubic-light.svg"><img
alt="Review in cubic"
src="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"></picture></a>
<!-- End of auto-generated description by cubic. -->
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **New Features**
* Introduced refreshed CrowdSec Indigo branding across the documentation
site, including responsive wordmark, icons, and social images.
* Added light/dark theme support for diagrams and documentation images.
* Added mobile theme switching and improved sidebar, header, pagination,
and navigation behavior.
* Added clearer architecture diagrams, flow explanations, and Grafana
dashboard imagery.
* **Documentation**
* Expanded English and Spanish guidance for decision filtering,
firewall-rule placement, reconciliation, shutdown behavior, and decision
lifecycles.
* Clarified read/write diagram conventions and operational edge cases.
* **Bug Fixes**
* Improved validation for localized documentation structure and
generated brand assets.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->