Hacktoberfest 2026: le issue che i maintainer hanno segnato per ottobre, aperte e adatte ai principianti. Sfoglia le issue Hacktoberfest

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

Aperta
#17 0 commenti 0 reazioni 1 assegnatario Vedi su GitHub

@aRustyDev ci sta già lavorando.

Dal 5/1/2026.

Valutazione

Questa issue non è ancora stata valutata.

Descrizione

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

Lingua principale
Rust
Stelle
0
Fork
1
Metriche di merge delle PR
Nessuna PR unita negli ultimi 30g

Preparare l'ambiente

Come iniziare

  1. Leggi tutta la issue e poi la guida ai contributi del progetto.
  2. Commenta sulla issue per dire che te ne occupi tu — evita che due persone facciano lo stesso lavoro.
  3. Fai un fork del repository e lavora su un branch.
  4. Apri una pull request che faccia riferimento al numero della issue.

Altre issue di aRustyDev/mdbook-htmx

Tutte le issue di aRustyDev/mdbook-htmx

Issue simili

Altre issue su Rust

Ricevi le nuove issue nella tua casella

Un breve riepilogo di issue GitHub adatte ai principianti.