ADR-072: Qute Web Documentation Server

Status

Accepted (Implemented)

Date

2025-12-27

Context

The iDempiere Hub needs to serve documentation to users via HTTP. Requirements:

  1. Dynamic content - Render docs from AD metadata in real-time
  2. Search - Allow filtering tables, windows, processes
  3. Navigation - Browse ADRs, guides, reference docs
  4. Multiple formats - HTML for web, JSON for API, Markdown for export

We evaluated options:

This ADR documents the Qute Web approach which is now working.

Related ADRs:

Decision

1. Quarkus Qute Web Extension

Use quarkus-qute-web for template-based HTTP responses:

<dependency>
    <groupId>io.quarkiverse.qute.web</groupId>
    <artifactId>quarkus-qute-web</artifactId>
    <version>3.3.1</version>
</dependency>

2. Documentation Endpoints

Endpoint Template Data Source
GET /docs/ pub/docs/index.html Static navigation
GET /docs/tables/ tablesList.html AD_Table list
GET /docs/tables/{name} tableView.html TableDocGenerator
GET /docs/windows/ windowsList.html WindowRegistryLogic
GET /docs/processes/ processesList.html ProcessRegistryLogic
GET /docs/adr/ adrList.html AdrService
GET /docs/adr/{id} adrView.html AdrService
GET /docs/guides/ guidesList.html Static (future)

3. DocsResource Implementation

@Path("/docs")
public class DocsResource {

    @Inject TableDocGenerator tableDocGenerator;
    @Inject WindowRegistryLogic windowRegistry;
    @Inject ProcessRegistryLogic processRegistry;
    @Inject AdrService adrService;

    @Inject Template tableView;
    @Inject Template windowsList;
    @Inject Template processesList;

    @GET
    @Path("/tables/{tableName}")
    @Produces(MediaType.TEXT_HTML)
    public TemplateInstance getTableDoc(
            @PathParam("tableName") String tableName,
            @QueryParam("lang") String lang) {

        Optional<TableDoc> doc = tableDocGenerator.generate(tableName, lang);

        if (doc.isEmpty()) {
            return tableView.data("error", "Table not found: " + tableName);
        }

        return tableView
            .data("doc", doc.get())
            .data("tableName", tableName);
    }

    @GET
    @Path("/windows/")
    @Produces(MediaType.TEXT_HTML)
    public TemplateInstance listWindows(@QueryParam("pattern") String pattern) {
        String effectivePattern = (pattern != null) ? pattern : "%";
        ToolResult result = windowRegistry.listWindows(effectivePattern, 100);

        List<Map<String, Object>> windows =
            (List<Map<String, Object>>) result.getData().get("windows");

        return windowsList
            .data("windows", windows)
            .data("pattern", effectivePattern)
            .data("count", windows.size());
    }
}

4. Template Structure

src/main/resources/templates/
├── base.html              # Base layout with header, footer
├── tableView.html         # Single table documentation
├── tablesList.html        # Table search/list
├── windowsList.html       # Windows list with search
├── processesList.html     # Processes list with badges
├── adrList.html           # ADR list from docs/adr/
├── adrView.html           # Single ADR with markdown
├── guidesList.html        # Guides navigation
└── pub/
    └── docs/
        └── index.html     # Static entry point

5. Profile Configuration

The docs server runs on a separate profile:

# application-docs.properties
quarkus.http.port=8080
quarkus.qute.content-types.md=text/html

Run command:

java -Dquarkus.profile=docs -jar idempiere-hub-runner.jar server docs

6. Qute Features Used

Feature Usage
{#include base} Template inheritance
{#for item in list} Iteration
{#if cond}...{/if} Conditionals
{value ?: 'default'} Elvis operator
{#md}...{/md} Markdown rendering
Type-safe templates @Inject Template name

Implementation Status

Component File Status
DocsResource DocsResource.java Working
TableDocGenerator TableDocGenerator.java Working
Table View tableView.html Working
Windows List windowsList.html Working
Processes List processesList.html Working
ADR List adrList.html Working
ADR View adrView.html Working
Guides List guidesList.html Placeholder

Test Results

$ curl http://localhost:8080/docs/windows/?pattern=%Order%
Found 15 window(s) matching "%Order%"
- Sales Order
- Purchase Order
- Manufacturing Order
...

$ curl http://localhost:8080/docs/processes/?pattern=%Invoice%
Found 12 process(es) matching "%Invoice%"
- Generate Invoice
- Invoice Print
...

$ curl http://localhost:8080/docs/tables/C_Order
[Full table documentation with columns, references, etc.]

Consequences

Benefits

Drawbacks

Next Steps

  1. Add caching for table metadata
  2. Implement guides content from Git
  3. Add authentication via OIDC
  4. Add JSON export for API consumers

References

Path: /docs/developers/architecture/idempiere-hub/072-qute-web-docs-server