Skip to content

Commit bca3131

Browse files
committed
Update documentation to reflect pagination options change from 25/50/75/100 to 25/50/100, reorganize app/ directory structure with internal/ packages (config, errors, httputil, i18n, middleware, validation), add new vault status and refresh UI endpoints, document enhanced metrics with expiration buckets and optional per-certificate metrics, update build commands from make to task, and remove development notes and performance considerations sections
1 parent 83d84cf commit bca3131

File tree

3 files changed

+30
-175
lines changed

3 files changed

+30
-175
lines changed

README.fr.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ VaultCertsViewer peut surveiller simultanément plusieurs moteurs PKI via une se
9696
- **Recherche en temps réel** : Filtrage instantané pendant la saisie avec délai de 300ms
9797
- **Filtrage par statut** : Filtres rapides pour les certificats valides/expirés/révoqués
9898
- **Répartition** : Visualisation de la répartition des certificats par statut
99-
- **Pagination** : Taille de page configurable (25/50/75/100/tout) avec contrôles de navigation
99+
- **Pagination** : Taille de page configurable (25/50/100/tout) avec contrôles de navigation
100100
- **Options de tri** : Tri par vault, moteur PKI, nom commun, date de création et date d'expiration
101101

102102
### 🐳 docker-compose

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ VaultCertsViewer can monitor multiple PKI engines simultaneously through a singl
9696
- **Real-time search**: Instant filtering as you type in the search box with 300ms debouncing
9797
- **Status filtering**: Quick filters for valid/expired/revoked certificates
9898
- **Partitioning**: Visualize certificate partitioning by expiration date
99-
- **Pagination**: Configurable page size (25/50/75/100/all) with navigation controls
99+
- **Pagination**: Configurable page size (25/50/100/all) with navigation controls
100100
- **Sort options**: Sort by vault, PKI mount, common name, creation or expiration date
101101

102102
### 🐳 docker-compose

app/README.md

Lines changed: 28 additions & 173 deletions
Original file line numberDiff line numberDiff line change
@@ -14,15 +14,19 @@ This document describes the technical structure of VaultCertsViewer (vcv), a sin
1414
## Directory layout (app/)
1515

1616
- `cmd/server/main.go` — entrypoint, router, middleware, static file serving, graceful shutdown.
17-
- `web/``index.html`, `assets/app-htmx.js`, `assets/styles.css`, `templates/` (UI fragments + Admin templates).
18-
- `config/` — environment-backed configuration loading with expiration threshold support.
1917
- `internal/cache/` — simple in-memory TTL cache (used by Vault client).
18+
- `internal/config/` — environment-backed configuration loading with expiration threshold support.
19+
- `internal/errors/` — custom error types and helpers.
2020
- `internal/handlers/` — HTTP handlers (`certs`, `i18n`, `health`, `ready`, `ui`, `admin` routes).
21-
- `internal/metrics/` — Prometheus collectors.
21+
- `internal/httputil/` - HTTP utility functions for client IP extraction, used by rate limiting middleware.
22+
- `internal/i18n/` - Internationalization support.
2223
- `internal/logger/` — zerolog initialization and structured helpers (HTTP events, panic).
24+
- `internal/metrics/` — Prometheus collectors.
25+
- `internal/middleware/` — request ID, HTTP logging, panic recovery, CORS, security headers, rate limiting, CSRF protection, body limit.
26+
- `internal/validation/` - Validation helpers.
2327
- `internal/vault/` — Vault client implementations with graceful shutdown support.
2428
- `internal/version/` — build version info (injected via ldflags).
25-
- `middleware/`request ID, HTTP logging, panic recovery, CORS, security headers, rate limiting, CSRF protection, body limit.
29+
- `web/``index.html`, `assets/app-htmx.js`, `assets/styles.css`, `templates/` (UI fragments + Admin templates).
2630

2731
## API surface
2832

@@ -45,7 +49,8 @@ This document describes the technical structure of VaultCertsViewer (vcv), a sin
4549
| `/ui/certs/refresh` | POST | HTMX fragment: refresh certificates |
4650
| `/ui/certs/{id}/details` | GET | HTMX fragment: certificate details |
4751
| `/ui/theme/toggle` | POST | Toggle dark/light theme |
48-
| `/ui/status` | GET | Real-time Vault connection status |
52+
| `/ui/vaults/status` | GET | HTMX fragment: vault status |
53+
| `/ui/vaults/refresh` | POST | HTMX fragment: refresh vaults |
4954
| `/admin` | GET | Admin page (enabled only if admin password is configured in settings.json) |
5055
| `/admin/panel` | GET | Admin panel fragment (HTMX) |
5156
| `/admin/login` | POST | Admin login (HTMX) |
@@ -148,7 +153,7 @@ Precedence rules:
148153
- Responsive design with sticky header
149154
- Dark/light theme persistence
150155
- Modal mount selector for multi-PKI support
151-
- Configurable pagination (25/50/75/100/all)
156+
- Configurable pagination (25/50/100/all)
152157
- Sortable columns with visual indicators
153158

154159
## Metrics
@@ -181,158 +186,26 @@ Metrics are exposed at `/metrics`.
181186
- Uses the configured expiration thresholds.
182187
- `vcv_vaults_configured`
183188
- `vcv_pki_mounts_configured{vault_id}`
189+
- `vcv_expiration_threshold_critical_days` — Configured critical threshold.
190+
- `vcv_expiration_threshold_warning_days` — Configured warning threshold.
184191

185-
### Optional metric (disabled by default)
192+
### Enhanced metrics
186193

187-
- `vcv_certificate_expiry_timestamp_seconds{certificate_id, common_name, status, vault_id, pki}`
194+
- `vcv_certificates_expiry_bucket{vault_id, pki, bucket}` — Certificate distribution by time bucket.
195+
- Buckets: `0-7d`, `7-30d`, `30-90d`, `90d+`, `expired`, `revoked`.
188196

189-
Enable it with:
197+
### Optional metrics (disabled by default)
190198

191-
```bash
192-
VCV_METRICS_PER_CERTIFICATE=true
193-
```
199+
- `vcv_certificate_expiry_timestamp_seconds{certificate_id, common_name, status, vault_id, pki}`
200+
- `vcv_certificate_days_until_expiry{certificate_id, common_name, status, vault_id, pki}` — Days until expiration (negative if expired).
194201

195-
Example:
202+
Enable with:
196203

197-
```bash
198-
# HELP vcv_cache_size Number of items currently cached
199-
# TYPE vcv_cache_size gauge
200-
vcv_cache_size 0
201-
# HELP vcv_certificate_exporter_last_scrape_duration_seconds Duration of the last certificate scrape in seconds
202-
# TYPE vcv_certificate_exporter_last_scrape_duration_seconds gauge
203-
vcv_certificate_exporter_last_scrape_duration_seconds 0.000118208
204-
# HELP vcv_certificate_exporter_last_scrape_success Whether the last scrape succeeded (1) or failed (0)
205-
# TYPE vcv_certificate_exporter_last_scrape_success gauge
206-
vcv_certificate_exporter_last_scrape_success 1
207-
# HELP vcv_certificates_expired_count Number of expired certificates
208-
# TYPE vcv_certificates_expired_count gauge
209-
vcv_certificates_expired_count 30
210-
# HELP vcv_certificates_expiring_soon_count Number of certificates expiring soon within threshold window
211-
# TYPE vcv_certificates_expiring_soon_count gauge
212-
vcv_certificates_expiring_soon_count{level="critical",pki="__all__",vault_id="__all__"} 17
213-
vcv_certificates_expiring_soon_count{level="critical",pki="pki",vault_id="vault-main"} 3
214-
vcv_certificates_expiring_soon_count{level="critical",pki="pki_blockchain",vault_id="vault-dev-3"} 0
215-
vcv_certificates_expiring_soon_count{level="critical",pki="pki_cloud",vault_id="vault-dev-3"} 0
216-
vcv_certificates_expiring_soon_count{level="critical",pki="pki_corporate",vault_id="vault-dev-2"} 0
217-
vcv_certificates_expiring_soon_count{level="critical",pki="pki_dev",vault_id="vault-main"} 1
218-
vcv_certificates_expiring_soon_count{level="critical",pki="pki_dmz",vault_id="vault-dev-5"} 0
219-
vcv_certificates_expiring_soon_count{level="critical",pki="pki_edge",vault_id="vault-dev-3"} 0
220-
vcv_certificates_expiring_soon_count{level="critical",pki="pki_external",vault_id="vault-dev-2"} 0
221-
vcv_certificates_expiring_soon_count{level="critical",pki="pki_internal",vault_id="vault-dev-5"} 0
222-
vcv_certificates_expiring_soon_count{level="critical",pki="pki_iot",vault_id="vault-dev-3"} 0
223-
vcv_certificates_expiring_soon_count{level="critical",pki="pki_lab",vault_id="vault-dev-4"} 0
224-
vcv_certificates_expiring_soon_count{level="critical",pki="pki_partners",vault_id="vault-dev-2"} 0
225-
vcv_certificates_expiring_soon_count{level="critical",pki="pki_perf",vault_id="vault-dev-4"} 0
226-
vcv_certificates_expiring_soon_count{level="critical",pki="pki_production",vault_id="vault-main"} 0
227-
vcv_certificates_expiring_soon_count{level="critical",pki="pki_qa",vault_id="vault-dev-4"} 0
228-
vcv_certificates_expiring_soon_count{level="critical",pki="pki_shared",vault_id="vault-dev-5"} 0
229-
vcv_certificates_expiring_soon_count{level="critical",pki="pki_stage",vault_id="vault-main"} 1
230-
vcv_certificates_expiring_soon_count{level="critical",pki="pki_vault2",vault_id="vault-dev-2"} 2
231-
vcv_certificates_expiring_soon_count{level="critical",pki="pki_vault3",vault_id="vault-dev-3"} 2
232-
vcv_certificates_expiring_soon_count{level="critical",pki="pki_vault4",vault_id="vault-dev-4"} 4
233-
vcv_certificates_expiring_soon_count{level="critical",pki="pki_vault5",vault_id="vault-dev-5"} 4
234-
vcv_certificates_expiring_soon_count{level="warning",pki="__all__",vault_id="__all__"} 45
235-
vcv_certificates_expiring_soon_count{level="warning",pki="pki",vault_id="vault-main"} 7
236-
vcv_certificates_expiring_soon_count{level="warning",pki="pki_blockchain",vault_id="vault-dev-3"} 0
237-
vcv_certificates_expiring_soon_count{level="warning",pki="pki_cloud",vault_id="vault-dev-3"} 0
238-
vcv_certificates_expiring_soon_count{level="warning",pki="pki_corporate",vault_id="vault-dev-2"} 0
239-
vcv_certificates_expiring_soon_count{level="warning",pki="pki_dev",vault_id="vault-main"} 2
240-
vcv_certificates_expiring_soon_count{level="warning",pki="pki_dmz",vault_id="vault-dev-5"} 5
241-
vcv_certificates_expiring_soon_count{level="warning",pki="pki_edge",vault_id="vault-dev-3"} 0
242-
vcv_certificates_expiring_soon_count{level="warning",pki="pki_external",vault_id="vault-dev-2"} 0
243-
vcv_certificates_expiring_soon_count{level="warning",pki="pki_internal",vault_id="vault-dev-5"} 5
244-
vcv_certificates_expiring_soon_count{level="warning",pki="pki_iot",vault_id="vault-dev-3"} 0
245-
vcv_certificates_expiring_soon_count{level="warning",pki="pki_lab",vault_id="vault-dev-4"} 0
246-
vcv_certificates_expiring_soon_count{level="warning",pki="pki_partners",vault_id="vault-dev-2"} 0
247-
vcv_certificates_expiring_soon_count{level="warning",pki="pki_perf",vault_id="vault-dev-4"} 0
248-
vcv_certificates_expiring_soon_count{level="warning",pki="pki_production",vault_id="vault-main"} 0
249-
vcv_certificates_expiring_soon_count{level="warning",pki="pki_qa",vault_id="vault-dev-4"} 6
250-
vcv_certificates_expiring_soon_count{level="warning",pki="pki_shared",vault_id="vault-dev-5"} 0
251-
vcv_certificates_expiring_soon_count{level="warning",pki="pki_stage",vault_id="vault-main"} 2
252-
vcv_certificates_expiring_soon_count{level="warning",pki="pki_vault2",vault_id="vault-dev-2"} 5
253-
vcv_certificates_expiring_soon_count{level="warning",pki="pki_vault3",vault_id="vault-dev-3"} 5
254-
vcv_certificates_expiring_soon_count{level="warning",pki="pki_vault4",vault_id="vault-dev-4"} 4
255-
vcv_certificates_expiring_soon_count{level="warning",pki="pki_vault5",vault_id="vault-dev-5"} 4
256-
# HELP vcv_certificates_last_fetch_timestamp_seconds Timestamp of last successful certificates fetch
257-
# TYPE vcv_certificates_last_fetch_timestamp_seconds gauge
258-
vcv_certificates_last_fetch_timestamp_seconds 1.765985686e+09
259-
# HELP vcv_certificates_total Total certificates grouped by status
260-
# TYPE vcv_certificates_total gauge
261-
vcv_certificates_total{pki="__all__",status="expired",vault_id="__all__"} 30
262-
vcv_certificates_total{pki="__all__",status="revoked",vault_id="__all__"} 14
263-
vcv_certificates_total{pki="__all__",status="valid",vault_id="__all__"} 85
264-
vcv_certificates_total{pki="pki",status="expired",vault_id="vault-main"} 3
265-
vcv_certificates_total{pki="pki",status="revoked",vault_id="vault-main"} 0
266-
vcv_certificates_total{pki="pki",status="valid",vault_id="vault-main"} 12
267-
vcv_certificates_total{pki="pki_blockchain",status="expired",vault_id="vault-dev-3"} 0
268-
vcv_certificates_total{pki="pki_blockchain",status="revoked",vault_id="vault-dev-3"} 1
269-
vcv_certificates_total{pki="pki_blockchain",status="valid",vault_id="vault-dev-3"} 1
270-
vcv_certificates_total{pki="pki_cloud",status="expired",vault_id="vault-dev-3"} 0
271-
vcv_certificates_total{pki="pki_cloud",status="revoked",vault_id="vault-dev-3"} 1
272-
vcv_certificates_total{pki="pki_cloud",status="valid",vault_id="vault-dev-3"} 1
273-
vcv_certificates_total{pki="pki_corporate",status="expired",vault_id="vault-dev-2"} 0
274-
vcv_certificates_total{pki="pki_corporate",status="revoked",vault_id="vault-dev-2"} 1
275-
vcv_certificates_total{pki="pki_corporate",status="valid",vault_id="vault-dev-2"} 1
276-
vcv_certificates_total{pki="pki_dev",status="expired",vault_id="vault-main"} 1
277-
vcv_certificates_total{pki="pki_dev",status="revoked",vault_id="vault-main"} 2
278-
vcv_certificates_total{pki="pki_dev",status="valid",vault_id="vault-main"} 5
279-
vcv_certificates_total{pki="pki_dmz",status="expired",vault_id="vault-dev-5"} 0
280-
vcv_certificates_total{pki="pki_dmz",status="revoked",vault_id="vault-dev-5"} 0
281-
vcv_certificates_total{pki="pki_dmz",status="valid",vault_id="vault-dev-5"} 6
282-
vcv_certificates_total{pki="pki_edge",status="expired",vault_id="vault-dev-3"} 0
283-
vcv_certificates_total{pki="pki_edge",status="revoked",vault_id="vault-dev-3"} 1
284-
vcv_certificates_total{pki="pki_edge",status="valid",vault_id="vault-dev-3"} 1
285-
vcv_certificates_total{pki="pki_external",status="expired",vault_id="vault-dev-2"} 0
286-
vcv_certificates_total{pki="pki_external",status="revoked",vault_id="vault-dev-2"} 1
287-
vcv_certificates_total{pki="pki_external",status="valid",vault_id="vault-dev-2"} 1
288-
vcv_certificates_total{pki="pki_internal",status="expired",vault_id="vault-dev-5"} 0
289-
vcv_certificates_total{pki="pki_internal",status="revoked",vault_id="vault-dev-5"} 1
290-
vcv_certificates_total{pki="pki_internal",status="valid",vault_id="vault-dev-5"} 6
291-
vcv_certificates_total{pki="pki_iot",status="expired",vault_id="vault-dev-3"} 0
292-
vcv_certificates_total{pki="pki_iot",status="revoked",vault_id="vault-dev-3"} 1
293-
vcv_certificates_total{pki="pki_iot",status="valid",vault_id="vault-dev-3"} 1
294-
vcv_certificates_total{pki="pki_lab",status="expired",vault_id="vault-dev-4"} 0
295-
vcv_certificates_total{pki="pki_lab",status="revoked",vault_id="vault-dev-4"} 0
296-
vcv_certificates_total{pki="pki_lab",status="valid",vault_id="vault-dev-4"} 7
297-
vcv_certificates_total{pki="pki_partners",status="expired",vault_id="vault-dev-2"} 0
298-
vcv_certificates_total{pki="pki_partners",status="revoked",vault_id="vault-dev-2"} 1
299-
vcv_certificates_total{pki="pki_partners",status="valid",vault_id="vault-dev-2"} 1
300-
vcv_certificates_total{pki="pki_perf",status="expired",vault_id="vault-dev-4"} 0
301-
vcv_certificates_total{pki="pki_perf",status="revoked",vault_id="vault-dev-4"} 0
302-
vcv_certificates_total{pki="pki_perf",status="valid",vault_id="vault-dev-4"} 1
303-
vcv_certificates_total{pki="pki_production",status="expired",vault_id="vault-main"} 0
304-
vcv_certificates_total{pki="pki_production",status="revoked",vault_id="vault-main"} 0
305-
vcv_certificates_total{pki="pki_production",status="valid",vault_id="vault-main"} 1
306-
vcv_certificates_total{pki="pki_qa",status="expired",vault_id="vault-dev-4"} 0
307-
vcv_certificates_total{pki="pki_qa",status="revoked",vault_id="vault-dev-4"} 0
308-
vcv_certificates_total{pki="pki_qa",status="valid",vault_id="vault-dev-4"} 7
309-
vcv_certificates_total{pki="pki_shared",status="expired",vault_id="vault-dev-5"} 0
310-
vcv_certificates_total{pki="pki_shared",status="revoked",vault_id="vault-dev-5"} 0
311-
vcv_certificates_total{pki="pki_shared",status="valid",vault_id="vault-dev-5"} 6
312-
vcv_certificates_total{pki="pki_stage",status="expired",vault_id="vault-main"} 1
313-
vcv_certificates_total{pki="pki_stage",status="revoked",vault_id="vault-main"} 0
314-
vcv_certificates_total{pki="pki_stage",status="valid",vault_id="vault-main"} 5
315-
vcv_certificates_total{pki="pki_vault2",status="expired",vault_id="vault-dev-2"} 5
316-
vcv_certificates_total{pki="pki_vault2",status="revoked",vault_id="vault-dev-2"} 1
317-
vcv_certificates_total{pki="pki_vault2",status="valid",vault_id="vault-dev-2"} 6
318-
vcv_certificates_total{pki="pki_vault3",status="expired",vault_id="vault-dev-3"} 5
319-
vcv_certificates_total{pki="pki_vault3",status="revoked",vault_id="vault-dev-3"} 1
320-
vcv_certificates_total{pki="pki_vault3",status="valid",vault_id="vault-dev-3"} 6
321-
vcv_certificates_total{pki="pki_vault4",status="expired",vault_id="vault-dev-4"} 7
322-
vcv_certificates_total{pki="pki_vault4",status="revoked",vault_id="vault-dev-4"} 1
323-
vcv_certificates_total{pki="pki_vault4",status="valid",vault_id="vault-dev-4"} 5
324-
vcv_certificates_total{pki="pki_vault5",status="expired",vault_id="vault-dev-5"} 8
325-
vcv_certificates_total{pki="pki_vault5",status="revoked",vault_id="vault-dev-5"} 1
326-
vcv_certificates_total{pki="pki_vault5",status="valid",vault_id="vault-dev-5"} 5
327-
# HELP vcv_vault_connected Vault connection status (1=connected,0=disconnected)
328-
# TYPE vcv_vault_connected gauge
329-
vcv_vault_connected{vault_id="__all__"} 0
330-
vcv_vault_connected{vault_id="vault-dev-2"} 1
331-
vcv_vault_connected{vault_id="vault-dev-3"} 1
332-
vcv_vault_connected{vault_id="vault-dev-4"} 1
333-
vcv_vault_connected{vault_id="vault-dev-5"} 1
334-
vcv_vault_connected{vault_id="vault-dev-6"} 0
335-
vcv_vault_connected{vault_id="vault-main"} 1
204+
```json
205+
"metrics": {
206+
"per_certificate": true,
207+
"enhanced_metrics": false
208+
}
336209
```
337210

338211
## Build & run
@@ -346,7 +219,7 @@ See README.md on the root path for production deployment instructions.
346219
A Hashicorp Vault or OpenBao server is required to run the application in development mode. Thus, a container with an init script is provided in `docker-compose.dev.yml`. It will initialize a Vault server with a PKI mount and some certs.
347220

348221
```bash
349-
make dev
222+
task dev
350223
```
351224

352225
Binary serves UI and API at `http://localhost:52000`.
@@ -367,23 +240,5 @@ cd app && go test ./...
367240

368241
Test targets:
369242

370-
- `make test-offline`: Run tests without Vault dependency
371-
- `make test-dev`: Run tests against dev Vault instance
372-
373-
## Development notes
374-
375-
- No external frontend toolchain; edit `app-htmx.js`/`styles.css` directly.
376-
- Request IDs are added to all responses; include them when correlating logs.
377-
- Use `VAULT_TLS_INSECURE=true` only in development environments.
378-
- HTMX partial templates are in `web/templates/`.
379-
- JavaScript uses modern ES6+ features with browser-native APIs.
380-
- CSS uses custom properties for theming and responsive design.
381-
382-
## Performance Considerations
383-
384-
- In-memory caching with configurable TTL (default 5 minutes)
385-
- Request deduplication for concurrent identical requests
386-
- Efficient DOM updates via HTMX partial swapping
387-
- Lazy loading of certificate details
388-
- Optimized search with client-side filtering
389-
- Rate limiting to prevent abuse (production only)
243+
- `task test-offline`: Run tests without Vault dependency
244+
- `task test-dev`: Run tests against dev Vault instance

0 commit comments

Comments
 (0)