Hacktoberfest 2026: los issues que los mantenedores marcaron para octubre, abiertos y aptos para principiantes. Explorar issues de Hacktoberfest

docs(adr): ADR-0009: Audience Scopes for Filtered Documentation Views

Abierto
#17 0 comentarios 0 reacciones 1 asignado Ver en GitHub

@aRustyDev ya está trabajando en esto.

Desde el 5/1/2026.

Evaluación

Este issue todavía no se ha evaluado.

Descripción

documentation

ADR-0009: Audience Scopes for Filtered Documentation Views

Status

Accepted

Context

Documentation often serves multiple audiences with different needs:

  • Developers need API references, code examples
  • Managers need architecture overviews, decision rationale
  • SREs need operational runbooks, monitoring guides
  • Beginners need tutorials, getting started guides

Users authorized to see multiple audiences' content want to focus on one audience at a time, filtering navigation and search to that subset.

Decision Drivers

  1. Focus - Users shouldn't wade through irrelevant content
  2. Security - Users shouldn't see content they're not authorized for
  3. Simplicity - Minimal configuration burden on content authors
  4. Performance - Fast filtering without server-side computation

Key Decisions

1. URL Structure: Query Parameter

Decision: Use query parameter ?scope=developers instead of path prefix.

/docs/chapter-1?scope=developers   ✅ Chosen
/docs/developers/chapter-1         ❌ Rejected

Rationale:

  • Content URL is stable regardless of scope
  • Better caching (same page, different lens)
  • No path rewriting needed for internal links
  • Scope is a "view preference" not a location
2. No Scope Inheritance

Decision: Each page explicitly declares its scopes. No inheritance from parent chapters.

# Every page must declare its scopes
---
scopes: [developers, sre]
---

Rationale:

  • Explicit is better than implicit
  • Easy to audit (grep for scopes)
  • No surprises when restructuring chapters
  • Avoids complex inheritance resolution
3. Separate Search Indexes Per Scope

Decision: Generate scope-specific search indexes at build time.

book/htmx/
├── search-index.json              # Full index
├── search-index.developers.json   # Developer scope only
├── search-index.managers.json     # Manager scope only

Rationale:

  • Prevents information leakage (titles, snippets)
  • No runtime filtering overhead
  • Unauthorized content never sent to client
4. Runtime AuthZ as Defense in Depth

Decision: Apply authorization filtering at runtime even with scope-specific indexes.

Rationale:

  • Build-time scope filtering may drift from auth rules
  • Defense in depth catches edge cases
  • Minimal performance impact

Implementation

Frontmatter Schema
---
title: API Reference
scopes:
  - developers
  - sre
auth:
  access: roles
  roles: [developer, sre]
---

Note: scopes and auth are independent:

  • scopes controls navigation filtering (user's choice)
  • auth controls access permissions (admin's policy)
Configuration
[output.htmx.scopes]
enabled = true
available = ["all", "developers", "managers", "sre"]
default = "all"

[output.htmx.search]
scope-indexes = true           # Generate per-scope indexes
authz-filter = true            # Runtime auth check
global-scopes = ["all"]        # Always in main index
Build Output
book/htmx/
├── manifest.json              # Full manifest
├── manifest.developers.json   # Navigation for developer scope
├── manifest.managers.json     # Navigation for manager scope
├── search-index.json          # Full search index
├── search-index.developers.json
└── search-index.managers.json
Server Implementation
app.get('/docs/*', async (c) => {
  const scope = c.req.query('scope') || 'all';
  const user = c.get('user');

  // Anonymous users forced to 'all' scope
  const effectiveScope = user ? scope : 'all';

  // Load scope-specific manifest for navigation
  const manifest = manifests[effectiveScope] || manifests.all;

  // Load scope-specific search index
  const searchIndex = searchIndexes[effectiveScope] || searchIndexes.all;

  return c.html(await render('layout.html', {
    page,
    navigation: manifest.navigation,
    currentScope: effectiveScope,
    availableScopes: user ? manifest.scopes.available : ['all']
  }));
});
Scope Switcher Partial
<!-- partials/scope-switcher.html -->
<div class="scope-switcher" id="scope-switcher">
  <label>View:</label>
  <select hx-get="{{ current_path }}"
          hx-target="body"
          hx-push-url="true"
          name="scope">
    {% for scope in available_scopes %}
    <option value="{{ scope }}"
            {% if scope == current_scope %}selected{% endif %}>
      {{ scope | title }}
    </option>
    {% endfor %}
  </select>
</div>

Scope vs Authorization

Aspect Scope Authorization
Question What view do I want? Can I access this page?
Who decides User (their preference) Admin (policy)
Enforcement Navigation + search filtering Access denied / redirect
Failure mode Page hidden from nav/search 403 or redirect to login

A page can be:

  • In scope developers but require role senior-developer
  • Visible in navigation but return 403 on access
  • In multiple scopes with the same authorization

Consequences

Positive
  • Users can focus on relevant content
  • Search results are scoped appropriately
  • No information leakage via search
  • Clean URL structure
  • Simple explicit configuration
Negative
  • More build output (one manifest/index per scope)
  • Authors must tag every page with scopes
  • No automatic scope inference
Mitigation
  • Default scope all catches untagged pages
  • Linting can warn about missing scope declarations
  • Build-time validation ensures consistency

Alternatives Considered

Path-Based Scopes (/docs/developers/page)

Rejected because:

  • Breaks internal links (need rewriting)
  • Complicates caching
  • Scope is a lens, not a location
Scope Inheritance from Parent Chapters

Rejected because:

  • Implicit behavior causes surprises
  • Hard to audit
  • Restructuring chapters changes scope unexpectedly
Single Index with Runtime Filtering

Rejected because:

  • Leaks page titles and snippets
  • Runtime overhead on every search
  • Defense-only approach (no build-time separation)

References

Lenguaje dominante
Rust
Estrellas
0
Forks
1
Métricas de merge de PR
Sin PR fusionados en 30 d

Preparar el entorno

Primeros pasos

  1. Lee el issue completo y luego la guía de contribución del proyecto.
  2. Comenta en el issue que vas a ocuparte — evita que dos personas hagan lo mismo.
  3. Haz un fork del repositorio y trabaja en una rama.
  4. Abre un pull request que haga referencia al número del issue.

Más de aRustyDev/mdbook-htmx

Todos los issues de aRustyDev/mdbook-htmx

Issues similares

Más issues de Rust

Recibe los nuevos issues en tu correo

Un resumen breve de issues de GitHub para principiantes.