Skip to content

[Task] Add declarative plugin documentation metadata and XML doc extraction #40

Description

@rian-be

Summary

Add structured plugin documentation as declarative metadata, and keep XML doc extraction strictly as build/tooling separate from the runtime plugin contract.

H5 introduces PluginDocumentation, plain, JSON serializable metadata DTO plugin owns as static data (host/catalog reads it, no runtime generation). H6 is reframed as generate/populate step: an extractor tool (outside AuthKit.Plugins.Abstractions) reads the compiled plugin's C# XML doc and fills PluginDocumentation, which the catalog serializes to JSON for catalog/docs/UI. H6 is not part of the runtime contract.

Goal

Give every plugin single, serializable documentation shape the host and catalog can render without parsing prose READMEs, while keeping IAuthKitPlugin lean documentation is metadata plugin possesses, not runtime behavior it performs.

Problem

  • Plugin documentation lives only in prose the host/catalog cannot render it.
  • XML doc describes code: namespace, type, method, property, parameter, exception, returns. Product documentation such as Overview, Setup, Configuration, Endpoints, Health, Security is different model. Mapping between them is not obvious and must not be guessed.
  • GetDocumentation() as an executed method blurs two things: static plugin metadata vs runtime behavior. If the documentation is static, the API should read metadata, not generate a document.

Status architecture decision

Two candidate models were considered:

XML comments -> XML documentation -> extraction -> PluginDocumentation -> IAuthKitPlugin.Documentation (runtime)

and

XML documentation -> extractor (tool) -> PluginDocumentation -> JSON -> catalog / docs / UI (static)

Decision: documentation is static metadata you read, not behavior you execute. It is exposed as an accessor like property PluginDocumentation Documentation { get; } — never method that generates anything. H6 is tooling the runtime contract exposes only the shape plus its default. Nothing in the DTO or the property performs generation.

The binding condition: Documentation belongs on IAuthKitPlugin only if the host consumes it as runtime metadata a Plugin Catalog, Admin UI, or runtime discovery consuming /plugins/{id} -> JSON. If documentation is consumed only to generate a website, H5 does not exist in the runtime contract at all: the marker-driven H6 extractor alone is sufficient, producing static JSON/Markdown for the docs site.

flowchart LR
    A["Plugin Assembly"] --> M["PluginManifest (what the plugin is)"]
    A --> D["Documentation source<br/>XML-doc + markers"]
    M --> C["Plugin Catalog"]
    D --> E["H6 Extractor"]
    E --> P["PluginDocumentation"]
    P --> C
    C --> J["JSON"]
    C --> U["UI"]
    C --> S["Docs"]
Loading

Clean boundaries:

  • manifest = what the plugin is and what it needs,
  • documentation = how the plugin works / how to use it,
  • runtime contract = what the host can do with the plugin,
  • extractor = tooling,
  • catalog = presentation/read.

Scope

ID Element Shape Boundary
H5 PluginDocumentation declarative, JSON-serializable metadata DTO + accessor property on IAuthKitPlugin part of AuthKit.Plugins.Abstractions (shape only) only if runtime catalog/admin consumes it
H6 XML doc extraction build/tooling generator that populates PluginDocumentation outside the runtime plugin contract

Proposed Contract (H5)

public sealed record PluginDocumentation
{
    public IReadOnlyCollection<PluginDocumentationSection> Sections { get; init; } = [];
    public IReadOnlyDictionary<string, string> Parameters { get; init; } = new Dictionary<string, string>();
}

public interface IAuthKitPlugin
{
    // accessor like metadata never generates anything at runtime
    PluginDocumentation Documentation => new();
}
  • Documentation is property, not method, so the semantics are unambiguous: Documentation is metadata; an operation would be GetDocumentation(). If GetDocumentation() is kept for API reasons, the ADR must state it is accessor like and performs no generation the property form is preferred.
  • Default new() keeps every existing plugin compatible and valid.
  • Parameters (MVP) is descriptive only: name -> short description of what the configuration entry means, never an actual value. If the catalog later needs structured rendering (Name, Description, Type, Required, Default), the model becomes PluginDocumentationParameter(Name, Description) as an IReadOnlyCollection only when real requirement demands it no abstraction now.

XML doc -> Sections (H6) explicit, marker-driven mapping

XML doc describes code (types, members, parameters) product sections such as Setup, Security, Configuration are different model. The extractor MUST NOT infer sections from class names, member lists, or parameter names.

Rules:

  • The marker is [PluginDocumentationSection("...")] distinct from the PluginDocumentation DTO, so there is no name collision:
[PluginDocumentationSection("configuration")]
public sealed class MyPluginOptions { }
  • Marker is opt-in. Only elements explicitly marked are extracted:
    • marked element + missing/hollow XML documentation -> build warning (author declared the element for docs but provided none),
    • XML documentation present but no marker → ignored (normal internal code /// <summary>Internal helper…</summary> must never enter plugin docs).
  • Each marked element's XML doc (<summary>, <remarks>, member docs) feeds the named PluginDocumentationSection(Section, Content).
  • An alternative explicit XML doc convention is acceptable provided it is deterministic and documented once. No name -> Overview, no param -> Configuration inference.

Decisions

  • H6 is tool, not the contract. The extractor lives in the repository's tools/build layer, never in AuthKit.Plugins.Abstractions.
  • PluginDocumentation is documentation DTO, not platform API: it holds plain records, strings, collections, and round trips to JSON with no runtime logic.
  • Documentation stays on IAuthKitPlugin only for runtime consumption (catalog/admin//plugins/{id}). Pure static site generation needs no runtime API alone suffices.
  • Boundary: Section H remains Observability, DX and tests. Documentation is metadata DTO plus generator IAuthKitPlugin is not home for every platform feature.

Validation

  • PluginDocumentation serializes to and from JSON without loss.
  • Default (new()) is empty but valid; existing plugins compile unchanged.
  • Documentation is a property (or documented accessor like method) that never generates at runtime.
  • Parameters contains descriptions only no runtime configuration values leak in.
  • Extractor (H6) produces PluginDocumentation from explicitly marked XML doc unmarked code is ignored.
  • Marked element with no XML documentation -> build warning.
  • No section is inferred from class/member/parameter naming.
  • Catalog renders plugin documentation from the serialized object without parsing README.

Acceptance Criteria

  • Plugins possess structured, serializable documentation metadata through the contract shape (and only if runtime consumer exists otherwise H6 tooling alone).
  • XML doc extraction is provided as tooling that populates that shape, outside the runtime contract.
  • Section mapping is deterministic, marker driven, and opt-in.
  • Existing plugins are unaffected (new() default) DevTokens/DevTools compile and load.

Non Goals

  • No runtime documentation generation by the plugin Documentation is metadata access only.
  • No documentation rendering engine in the contract (host concern).
  • No heuristic/magical XML doc -> section mapping.
  • No warnings for well documented but unmarked code the marker is opt-in.
  • No configuration values inside PluginDocumentation (descriptive Parameters only).
  • No .Parameters abstraction beyond the MVP dictionary until real catalog requirement appears.
  • No XML doc extractor inside AuthKit.Plugins.Abstractions tooling only.
  • No expansion of Section H beyond observability/DX/tests docs remain metadata DTO + generator

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    P1Core operationadditiveAdditive, non-breaking changearea/abstractionsAuthKit.Plugins.Abstractions contractcontractChanges the plugin contractsub-taskChild task of an epic

    Type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions