feat(docs): version-based docs, correct Gitea tag links, form guide help

- each release now carries a full docs snapshot (reference + handbook)
  under docs/releases/<v>/; the docs frontend loads a version's snapshot
  for /docs/vX.Y.Z/* and shows the handbook/reference of that version
- version dropdown navigates to /docs/<version> (docs home) instead of
  the release notes page; old /docs/vX.Y.Z redirect removed
- generator: --snapshot writes handbook + reference; build copies
  versioned snapshots (last 7 versions) into /docs/versions/<v>/
- fix Gitea tag links: /admin/tool-evaluator/tags/<v> was 404, correct
  URL is /releases/tag/<v>
- add GuideHelp button to forms/pages linking to the matching handbook
  guide (rating, tool add/edit, costs, compare, watchlist, analytics)
This commit is contained in:
opencode
2026-08-04 07:31:47 +02:00
parent d23990e322
commit 3bb4598d04
53 changed files with 7545 additions and 117 deletions
@@ -0,0 +1,29 @@
import { BookOpen } from "lucide-react";
import { Link } from "wouter";
import { Tooltip, TooltipContent, TooltipTrigger } from "@/components/ui/tooltip";
export function GuideHelp({
guide,
label,
}: {
guide: string;
label: string;
}) {
return (
<Tooltip>
<TooltipTrigger asChild>
<Link
href={`/docs/handbook/${guide}`}
target="_blank"
rel="noreferrer"
aria-label={`Help: ${label}`}
data-testid={`guide-${guide}`}
className="inline-flex shrink-0 text-muted-foreground hover:text-foreground transition-colors"
>
<BookOpen className="h-3.5 w-3.5" />
</Link>
</TooltipTrigger>
<TooltipContent>{label} Anleitung in der Dokumentation</TooltipContent>
</Tooltip>
);
}
+5 -1
View File
@@ -6,6 +6,7 @@ import {
GetTopToolsMetric
} from "@workspace/api-client-react";
import { Layout } from "@/components/layout";
import { GuideHelp } from "@/components/guide-help";
import { Card, CardContent, CardHeader, CardTitle, CardDescription } from "@/components/ui/card";
import { Skeleton } from "@/components/ui/skeleton";
import {
@@ -48,7 +49,10 @@ export default function Analytics() {
<Layout>
<div className="space-y-6 pb-10">
<div>
<h1 className="text-3xl font-bold tracking-tight mb-2">Platform Analytics</h1>
<h1 className="text-3xl font-bold tracking-tight mb-2 flex items-center gap-2">
Platform Analytics
<GuideHelp guide="analytics" label="Platform Analytics" />
</h1>
<p className="text-muted-foreground">Macro-level insights into tool performance and community engagement.</p>
</div>
+5 -1
View File
@@ -8,6 +8,7 @@ import { Link, useSearch } from "wouter";
import { Layout } from "@/components/layout";
import { useAuth } from "@/hooks/use-auth";
import { RatingStars } from "@/components/rating-stars";
import { GuideHelp } from "@/components/guide-help";
import { Badge } from "@/components/ui/badge";
import { Button } from "@/components/ui/button";
import { Skeleton } from "@/components/ui/skeleton";
@@ -101,7 +102,10 @@ export default function Compare() {
<Layout>
<div className="space-y-6 pb-10">
<div>
<h1 className="text-3xl font-bold tracking-tight mb-2">{t("compare.title")}</h1>
<h1 className="text-3xl font-bold tracking-tight mb-2 flex items-center gap-2">
{t("compare.title")}
<GuideHelp guide="vergleichen" label={t("compare.title")} />
</h1>
<p className="text-muted-foreground">{t("compare.subtitle", { count: list.length })}</p>
</div>
+111 -91
View File
@@ -1,4 +1,4 @@
import { useEffect, useMemo, useState } from "react";
import { useEffect, useMemo, useState, createContext, useContext } from "react";
import { Link, useLocation } from "wouter";
import { Marked } from "marked";
import DOMPurify from "dompurify";
@@ -42,6 +42,21 @@ import {
const DOCS_BASE = `${import.meta.env.BASE_URL.replace(/\/$/, "")}/docs`;
const REPO_URL = "https://git.kubebase.de/admin/tool-evaluator";
// Active docs version (null = current docs). Shared via context so every
// sub-view builds versioned links and file paths.
const DocsVersionContext = createContext<string | null>(null);
const useDocsVersion = () => useContext(DocsVersionContext);
// Full in-app URL for a docs path, prefixed with the active version.
function docsHref(version: string | null, path: string) {
return version === null ? `/docs/${path}` : `/docs/${version}/${path}`;
}
// Static file path under /docs, prefixed with the versioned snapshot dir.
function docsFile(version: string | null, relPath: string) {
return version === null ? relPath : `versions/${version}/${relPath}`;
}
// ---------------------------------------------------------------------------
// Types
// ---------------------------------------------------------------------------
@@ -88,6 +103,7 @@ type ReleaseDoc = {
title: string;
date: string | null;
hasReference: boolean;
hasHandbook: boolean;
};
type HandbookPage = { slug: string; file: string; title: string; order: number };
@@ -230,8 +246,11 @@ function isLinkableType(t: FieldType): boolean {
}
function resolveTypeHref(t: FieldType): string | null {
if (t.kind === "ref") return `/docs/reference/schemas/${t.value}`;
if (t.kind === "array" && /^[A-Z]/.test(t.value)) return `/docs/reference/schemas/${t.value}`;
const version = useDocsVersion();
const href = (v: string | null) =>
v === null ? `/docs/reference/schemas/${t.value}` : `/docs/${v}/reference/schemas/${t.value}`;
if (t.kind === "ref") return href(version);
if (t.kind === "array" && /^[A-Z]/.test(t.value)) return href(version);
return null;
}
@@ -328,14 +347,14 @@ function DocsNav({
const groups: { label: string; icon: LucideIcon; items: { href: string; label: string; active: boolean }[] }[] = [];
if (handbook && handbook.length > 0 && version === null) {
if (handbook && handbook.length > 0) {
groups.push({
label: t("docs.guides"),
icon: BookOpen,
items: handbook.map((p) => ({
href: `/docs/handbook/${p.slug}`,
href: docsHref(version, `handbook/${p.slug}`),
label: p.title,
active: navLink(`/docs/handbook/${p.slug}`),
active: navLink(docsHref(version, `handbook/${p.slug}`)),
})),
});
}
@@ -345,18 +364,18 @@ function DocsNav({
label: t("docs.endpoints"),
icon: Server,
items: reference.tags.map((tag) => ({
href: `/docs/reference/endpoints/${tag.name}`,
href: docsHref(version, `reference/endpoints/${tag.name}`),
label: tag.name,
active: navLink(`/docs/reference/endpoints/${tag.name}`),
active: navLink(docsHref(version, `reference/endpoints/${tag.name}`)),
})),
});
groups.push({
label: t("docs.schemas"),
icon: Library,
items: reference.schemas.map((s) => ({
href: `/docs/reference/schemas/${s.name}`,
href: docsHref(version, `reference/schemas/${s.name}`),
label: s.name,
active: navLink(`/docs/reference/schemas/${s.name}`),
active: navLink(docsHref(version, `reference/schemas/${s.name}`)),
})),
});
}
@@ -365,9 +384,7 @@ function DocsNav({
label: t("docs.releases"),
icon: Tag,
items: versions.map((v) => ({
href: v.version === (version ?? versions[0]?.version) && version !== null
? `/docs/releases/${v.version}`
: `/docs/releases/${v.version}`,
href: `/docs/releases/${v.version}`,
label: v.version,
active: navLink(`/docs/releases/${v.version}`),
})),
@@ -708,7 +725,7 @@ function ReleaseNoteView({ version }: { version: string }) {
<Tag className="h-4 w-4" />
<span className="font-mono">{version}</span>
<a
href={`${REPO_URL}/tags/${version}`}
href={`${REPO_URL}/releases/tag/${version}`}
target="_blank"
rel="noreferrer"
className="inline-flex items-center gap-1 hover:text-foreground"
@@ -723,8 +740,9 @@ function ReleaseNoteView({ version }: { version: string }) {
}
function HandbookView({ slug }: { slug: string }) {
const version = useDocsVersion();
const handbookFile = `${slug}.md`;
return <MarkdownView file={`handbook/${handbookFile}`} />;
return <MarkdownView file={docsFile(version, `handbook/${handbookFile}`)} />;
}
// ---------------------------------------------------------------------------
@@ -803,9 +821,11 @@ export default function Docs() {
});
const { data: releases, error: releasesError } = useJson<ReleaseDoc[]>(`${DOCS_BASE}/index.json`);
const { data: handbook, error: handbookError } = useJson<HandbookPage[]>(
version === null ? `${DOCS_BASE}/handbook/index.json` : null,
);
const activeRelease = releases?.find((r) => r.version === version) ?? null;
const handbookAvailable = version === null || activeRelease?.hasHandbook;
const handbookUrl = handbookAvailable ? `${DOCS_BASE}/${docsFile(version, "handbook/index.json")}` : null;
const { data: handbook, error: handbookError } = useJson<HandbookPage[]>(handbookUrl);
const isCurrentVersion =
version === null ||
@@ -814,7 +834,7 @@ export default function Docs() {
const refUrl = version === null
? `${DOCS_BASE}/reference.json`
: releases?.find((r) => r.version === version)?.hasReference
: activeRelease?.hasReference
? `${DOCS_BASE}/versions/${version}.json`
: null;
@@ -832,20 +852,13 @@ export default function Docs() {
return null;
}, [releases, versionInfo]);
// Redirect old-style /docs/vX.Y.Z to /docs/releases/vX.Y.Z
useEffect(() => {
if (version !== null && path.length === 0) {
setLocation(`/docs/releases/${version}`, { replace: true });
}
}, [version, path, setLocation]);
const handleVersionChange = (v: string | null) => {
setSearchQuery("");
if (v === null || v === currentVersion) {
setLocation("/docs");
return;
}
setLocation(`/docs/releases/${v}`);
setLocation(`/docs/${v}`);
};
// ---- route resolution ----
@@ -864,7 +877,12 @@ export default function Docs() {
let content: React.ReactNode = null;
if (version !== null && path.length === 0) {
content = <ReleaseNoteView version={version} />;
content =
handbook && handbook.length > 0 ? (
<HandbookView slug={handbook[0].slug} />
) : (
<ReleaseNoteView version={version} />
);
} else if (section === "home") {
content =
handbook && handbook.length > 0 ? (
@@ -913,7 +931,7 @@ export default function Docs() {
{reference.tags.map((tg) => (
<Link
key={tg.name}
href={`/docs/reference/endpoints/${tg.name}`}
href={docsHref(version, `reference/endpoints/${tg.name}`)}
className="rounded-lg border p-3 text-sm hover:bg-accent/50"
>
<span className="font-medium">{tg.name}</span>
@@ -930,7 +948,7 @@ export default function Docs() {
{reference.schemas.map((s) => (
<Link
key={s.name}
href={`/docs/reference/schemas/${s.name}`}
href={docsHref(version, `reference/schemas/${s.name}`)}
className="rounded-lg border p-3 text-sm font-mono hover:bg-accent/50"
>
{s.name}
@@ -955,75 +973,77 @@ export default function Docs() {
const showSearch = version === null && section !== "releases";
return (
<div className="min-h-screen bg-background flex flex-col">
<header className="border-b bg-card shrink-0">
<div className="mx-auto max-w-6xl px-4 md:px-6 h-14 flex items-center justify-between gap-3">
<div className="flex items-center gap-1 min-w-0">
<Sheet open={navOpen} onOpenChange={setNavOpen}>
<SheetTrigger asChild>
<Button
variant="ghost"
size="icon"
className="lg:hidden -ml-1 shrink-0"
title={t("docs.nav")}
data-testid="button-docs-nav-mobile"
>
<Menu className="h-5 w-5" />
</Button>
</SheetTrigger>
<SheetContent side="left" className="w-80 overflow-y-auto p-4">
<SheetTitle className="sr-only">{t("docs.nav")}</SheetTitle>
<DocsVersionContext.Provider value={version}>
<div className="min-h-screen bg-background flex flex-col">
<header className="border-b bg-card shrink-0">
<div className="mx-auto max-w-6xl px-4 md:px-6 h-14 flex items-center justify-between gap-3">
<div className="flex items-center gap-1 min-w-0">
<Sheet open={navOpen} onOpenChange={setNavOpen}>
<SheetTrigger asChild>
<Button
variant="ghost"
size="icon"
className="lg:hidden -ml-1 shrink-0"
title={t("docs.nav")}
data-testid="button-docs-nav-mobile"
>
<Menu className="h-5 w-5" />
</Button>
</SheetTrigger>
<SheetContent side="left" className="w-80 overflow-y-auto p-4">
<SheetTitle className="sr-only">{t("docs.nav")}</SheetTitle>
<DocsNav
version={version}
handbook={handbook}
reference={reference}
versions={releases ?? []}
/>
</SheetContent>
</Sheet>
<Link
href="/"
className="inline-flex items-center gap-2 text-primary font-bold text-lg min-w-0"
data-testid="link-docs-back"
>
<Wrench className="w-5 h-5 shrink-0" />
<span className="truncate">toolr</span>
<span className="hidden md:inline-flex items-center gap-1 text-xs font-normal text-muted-foreground border-l pl-2 ml-1">
<ArrowLeft className="w-3.5 h-3.5" />
{t("docs.backToApp")}
</span>
</Link>
</div>
<div className="flex items-center gap-1.5 shrink-0">
<ThemeToggle />
</div>
</div>
</header>
<div className="mx-auto max-w-6xl w-full flex-1 space-y-6 px-4 md:px-6 py-6 pb-12">
<DocsHeader
versions={releases ?? []}
activeVersion={headerVersion}
onVersionChange={handleVersionChange}
onSearchChange={showSearch ? setSearchQuery : undefined}
/>
{showSearch && <SearchOverlay query={searchQuery} onClose={() => setSearchQuery("")} />}
<div className="grid grid-cols-1 lg:grid-cols-[240px_minmax(0,1fr)] gap-8">
<aside className="hidden lg:block">
<div className="sticky top-20 max-h-[calc(100vh-6rem)] overflow-auto">
<DocsNav
version={version}
handbook={handbook}
reference={reference}
versions={releases ?? []}
/>
</SheetContent>
</Sheet>
<Link
href="/"
className="inline-flex items-center gap-2 text-primary font-bold text-lg min-w-0"
data-testid="link-docs-back"
>
<Wrench className="w-5 h-5 shrink-0" />
<span className="truncate">toolr</span>
<span className="hidden md:inline-flex items-center gap-1 text-xs font-normal text-muted-foreground border-l pl-2 ml-1">
<ArrowLeft className="w-3.5 h-3.5" />
{t("docs.backToApp")}
</span>
</Link>
</div>
</aside>
<div className="min-w-0">{content}</div>
</div>
<div className="flex items-center gap-1.5 shrink-0">
<ThemeToggle />
</div>
</div>
</header>
<div className="mx-auto max-w-6xl w-full flex-1 space-y-6 px-4 md:px-6 py-6 pb-12">
<DocsHeader
versions={releases ?? []}
activeVersion={headerVersion}
onVersionChange={handleVersionChange}
onSearchChange={showSearch ? setSearchQuery : undefined}
/>
{showSearch && <SearchOverlay query={searchQuery} onClose={() => setSearchQuery("")} />}
<div className="grid grid-cols-1 lg:grid-cols-[240px_minmax(0,1fr)] gap-8">
<aside className="hidden lg:block">
<div className="sticky top-20 max-h-[calc(100vh-6rem)] overflow-auto">
<DocsNav
version={version}
handbook={handbook}
reference={reference}
versions={releases ?? []}
/>
</div>
</aside>
<div className="min-w-0">{content}</div>
</div>
</div>
</div>
</DocsVersionContext.Provider>
);
}
+9 -2
View File
@@ -61,6 +61,7 @@ import {
import { customFetch } from "@workspace/api-client-react";
import { recordRecentTool } from "@/lib/recent-tools";
import { FieldHelp } from "@/components/field-help";
import { GuideHelp } from "@/components/guide-help";
const ratingSchema = z.object({
usefulness: z.number().min(1).max(5),
@@ -615,7 +616,10 @@ export default function ToolDetail() {
<Dialog open={costDialogOpen} onOpenChange={(o) => { if (!o) setCostDialogOpen(false); }}>
<DialogContent>
<DialogHeader>
<DialogTitle>{editCost ? t("detail.edit") + " " + t("detail.costs") : t("detail.addCost")}</DialogTitle>
<DialogTitle className="flex items-center gap-2">
{editCost ? t("detail.edit") + " " + t("detail.costs") : t("detail.addCost")}
<GuideHelp guide="kosten" label={t("detail.costs")} />
</DialogTitle>
<DialogDescription>Manage license cost information for this tool.</DialogDescription>
</DialogHeader>
<div className="space-y-4 py-2">
@@ -765,7 +769,10 @@ export default function ToolDetail() {
{isReviewFormOpen && (
<Card className="border-primary shadow-sm">
<CardHeader>
<CardTitle>{t("detail.addReview")}</CardTitle>
<CardTitle className="flex items-center gap-2">
{t("detail.addReview")}
<GuideHelp guide="bewerten" label={t("detail.addReview")} />
</CardTitle>
<CardDescription>Share your experience with {tool.name}</CardDescription>
</CardHeader>
<CardContent>
@@ -31,6 +31,7 @@ import { FeatureInput } from "@/components/feature-input";
import { TagInput } from "@/components/tag-input";
import { useAuth } from "@/hooks/use-auth";
import { FieldHelp } from "@/components/field-help";
import { GuideHelp } from "@/components/guide-help";
const toolSchema = z.object({
name: z.string().min(2, "Name must be at least 2 characters"),
@@ -160,6 +161,7 @@ export default function ToolEdit() {
<CardTitle className="flex items-center gap-2">
<Pencil className="w-5 h-5 text-primary" />
Tool Details
<GuideHelp guide="tool-bearbeiten" label="Tool Details" />
</CardTitle>
<CardDescription>Modify the tool information below.</CardDescription>
</CardHeader>
@@ -19,6 +19,7 @@ import { FeatureInput } from "@/components/feature-input";
import { TagInput } from "@/components/tag-input";
import { useAuth } from "@/hooks/use-auth";
import { FieldHelp } from "@/components/field-help";
import { GuideHelp } from "@/components/guide-help";
const toolSchema = z.object({
name: z.string().min(2, "Name must be at least 2 characters"),
@@ -123,6 +124,7 @@ export default function ToolNew() {
<CardTitle className="flex items-center gap-2">
<Wrench className="w-5 h-5 text-primary" />
Tool Details
<GuideHelp guide="tool-anlegen" label="Tool Details" />
</CardTitle>
<CardDescription>Provide the basic information about the tool.</CardDescription>
</CardHeader>
+5 -1
View File
@@ -6,6 +6,7 @@ import { useAuth } from "@/hooks/use-auth";
import { useWatchlist } from "@/hooks/use-watchlist";
import { Layout } from "@/components/layout";
import { ToolCard } from "@/components/tool-card";
import { GuideHelp } from "@/components/guide-help";
import { Button } from "@/components/ui/button";
import { Skeleton } from "@/components/ui/skeleton";
import { ShieldAlert, Bookmark } from "lucide-react";
@@ -42,7 +43,10 @@ export default function Watchlist() {
<Layout>
<div className="space-y-6 pb-10">
<div>
<h1 className="text-3xl font-bold tracking-tight mb-2">{t("watchlist.title")}</h1>
<h1 className="text-3xl font-bold tracking-tight mb-2 flex items-center gap-2">
{t("watchlist.title")}
<GuideHelp guide="watchlist" label={t("watchlist.title")} />
</h1>
<p className="text-muted-foreground">{t("watchlist.subtitle")}</p>
</div>
+2 -2
View File
@@ -5,7 +5,7 @@
> nicht zutreffen entfernen. Die Seite wird unter `/docs/vX.Y.Z` in der App
> angezeigt.
**Datum:** YYYY-MM-DD · **Tag:** [`vX.Y.Z`](https://git.kubebase.de/admin/tool-evaluator/tags/vX.Y.Z)
**Datum:** YYYY-MM-DD · **Tag:** [`vX.Y.Z`](https://git.kubebase.de/admin/tool-evaluator/releases/tag/vX.Y.Z)
## Neue Features
@@ -32,4 +32,4 @@
## Links
- Commit: [`<short-sha>`](https://git.kubebase.de/admin/tool-evaluator/commit/<short-sha>)
- Tag: [`vX.Y.Z`](https://git.kubebase.de/admin/tool-evaluator/tags/vX.Y.Z)
- Tag: [`vX.Y.Z`](https://git.kubebase.de/admin/tool-evaluator/releases/tag/vX.Y.Z)
+2 -2
View File
@@ -1,6 +1,6 @@
# v0.6.0 — Release Notes
**Datum:** 2026-08-03 · **Tag:** [`v0.6.0`](https://git.kubebase.de/admin/tool-evaluator/tags/v0.6.0)
**Datum:** 2026-08-03 · **Tag:** [`v0.6.0`](https://git.kubebase.de/admin/tool-evaluator/releases/tag/v0.6.0)
## Neue Features
@@ -34,4 +34,4 @@
## Links
- Commit: [`2f66fff`](https://git.kubebase.de/admin/tool-evaluator/commit/2f66fff)
- Tag: [`v0.6.0`](https://git.kubebase.de/admin/tool-evaluator/tags/v0.6.0)
- Tag: [`v0.6.0`](https://git.kubebase.de/admin/tool-evaluator/releases/tag/v0.6.0)
+2 -2
View File
@@ -1,6 +1,6 @@
# v0.7.0 — Release Notes
**Datum:** 2026-08-03 · **Tag:** [`v0.7.0`](https://git.kubebase.de/admin/tool-evaluator/tags/v0.7.0)
**Datum:** 2026-08-03 · **Tag:** [`v0.7.0`](https://git.kubebase.de/admin/tool-evaluator/releases/tag/v0.7.0)
## Neue Features
@@ -32,4 +32,4 @@
## Links
- Commit: [`520f917`](https://git.kubebase.de/admin/tool-evaluator/commit/520f917)
- Tag: [`v0.7.0`](https://git.kubebase.de/admin/tool-evaluator/tags/v0.7.0)
- Tag: [`v0.7.0`](https://git.kubebase.de/admin/tool-evaluator/releases/tag/v0.7.0)
+2 -2
View File
@@ -1,6 +1,6 @@
# v0.8.0 — Release Notes
**Datum:** 2026-08-03 · **Tag:** [`v0.8.0`](https://git.kubebase.de/admin/tool-evaluator/tags/v0.8.0)
**Datum:** 2026-08-03 · **Tag:** [`v0.8.0`](https://git.kubebase.de/admin/tool-evaluator/releases/tag/v0.8.0)
## Neue Features
@@ -43,4 +43,4 @@
## Links
- Commit: [`6c92b63`](https://git.kubebase.de/admin/tool-evaluator/commit/6c92b63)
- Tag: [`v0.8.0`](https://git.kubebase.de/admin/tool-evaluator/tags/v0.8.0)
- Tag: [`v0.8.0`](https://git.kubebase.de/admin/tool-evaluator/releases/tag/v0.8.0)
+2 -2
View File
@@ -1,6 +1,6 @@
# v0.8.1 — Release Notes
**Datum:** 2026-08-03 · **Tag:** [`v0.8.1`](https://git.kubebase.de/admin/tool-evaluator/tags/v0.8.1)
**Datum:** 2026-08-03 · **Tag:** [`v0.8.1`](https://git.kubebase.de/admin/tool-evaluator/releases/tag/v0.8.1)
## Neue Features
@@ -44,4 +44,4 @@
## Links
- Commit: [`fdf2d74`](https://git.kubebase.de/admin/tool-evaluator/commit/fdf2d74)
- Tag: [`v0.8.1`](https://git.kubebase.de/admin/tool-evaluator/tags/v0.8.1)
- Tag: [`v0.8.1`](https://git.kubebase.de/admin/tool-evaluator/releases/tag/v0.8.1)
@@ -0,0 +1,61 @@
# Administration
Der Bereich **Admin** (`/admin`) ist ausschließlich für Admins zugänglich.
Ohne Admin-Rolle erscheint eine Zugriffsverweigerung.
> Oben rechts führt die Schaltfläche **Redundanz-Dashboard** zur automatischen
> Doppelungs-Erkennung (siehe [Redundanz](/docs/handbook/redundanz)).
## Tab „Nutzer"
Verwaltung der lokalen Konten.
- **Nutzer hinzufügen:** Benutzername (Pflicht), Passwort (mind. 6 Zeichen),
E-Mail (optional), **Rolle** (User/Admin), **Tarif** (Free/Premium/Enterprise).
- **Nutzer bearbeiten:** Rolle, Tarif und (für lokale Konten) ein neues Passwort
setzen. Für OIDC-Konten wird die Passwortverwaltung im Identitätsanbieter
(z. B. Keycloak) angeboten.
- **Nutzer löschen:** Entfernt das Konto endgültig (nicht für das eigene Konto).
API-Referenz:
[`POST /users`](/docs/reference/endpoints/users#createUser),
[`PATCH /users/{id}`](/docs/reference/endpoints/users#updateUser),
[`DELETE /users/{id}`](/docs/reference/endpoints/users#deleteUser).
## Tab „Tools"
Zentraler Zugriff auf den Tool-Katalog.
- **Suchen** nach Tools.
- Tools einzeln ansehen, bearbeiten oder in den Papierkorb verschieben.
- **Massenaktion:** mehrere Tools auswählen und in den Papierkorb verschieben
(Bestätigungsdialog; soft gelöschte Tools sind aus allen öffentlichen Ansichten
entfernt und können wiederhergestellt oder endgültig gelöscht werden).
## Tab „Audit-Log"
Chronologisches Protokoll aller Anlage-, Änderungs- und Löschvorgänge
(max. 100 Einträge): Aktion, Entität + ID, Zeitstempel, ausführende Person und
geänderte Felder.
API-Referenz: [`GET /audit-logs`](/docs/reference/endpoints/audit#listAuditLogs).
## Tab „System"
Versionsinformationen der laufenden Instanz:
- **Version** (z. B. `v0.8.1`),
- **Commit** (7-stelliger SHA, verlinkt zum Repository),
- **Build-Datum**,
- **Papierkorb-Aufbewahrung** („N Tage" oder „Für immer").
## Tool-Verknüpfungen (Admin)
Auf der Detailseite eines Tools kannst du als Admin **Verknüpfungen**
(eigene/„manual" sowie automatisch erkannte) verwalten:
- **Tool verknüpfen:** Dialog mit Tool-ID, **Beziehungstyp**
(Ähnlich / Ersetzt / Abgelöst durch) und optionalen Notizen.
- Beziehungstypen werden als Badges auf der Detailseite angezeigt.
- Manuelle Verknüpfungen lassen sich per Papierkorb-Icon wieder entfernen.
@@ -0,0 +1,29 @@
# Analytics
Der Bereich **Analytics** (`/analytics`) ist ein öffentliches Dashboard mit
Kennzahlen und Diagrammen auf Basis aller Tools und Bewertungen.
## Kennzahlen (KPI-Karten)
- **Anzahl Tools** — wie viele Tools sind im Katalog erfasst.
- **Anzahl Bewertungen** — wie viele Bewertungen wurden insgesamt abgegeben.
- **Aktive Kategorien** — wie viele Kategorien existieren.
- **Durchschnittliche Bewertung** — globaler kombinierter Wert.
## Diagramme
| Diagramm | Inhalt |
| --- | --- |
| **Top 8 Tools** | Balkendiagramm der Tools mit der höchsten kombinierten Punktzahl (05) |
| **Tools je Kategorie** | Radar-Diagramm der Tool-Anzahl pro Kategorie |
| **Punkteverteilung** | Zwei horizontale Balken-Diagramme (Nützlichkeit & Bedienbarkeit) pro Stern |
Die Diagramme sind interaktiv (Tooltips beim Überfahren).
## API
- [`GET /analytics/summary`](/docs/reference/endpoints/analytics#getAnalyticsSummary)
- [`GET /analytics/top-tools`](/docs/reference/endpoints/analytics#getTopTools)
- [`GET /analytics/by-category`](/docs/reference/endpoints/analytics#getAnalyticsByCategory)
- [`GET /analytics/rating-distribution`](/docs/reference/endpoints/analytics#getRatingDistribution)
+39
View File
@@ -0,0 +1,39 @@
# Bewerten
Auf der Detailseite eines Tools kannst du deine Erfahrung teilen. Klicke auf
**Bewertung abgeben** (erfordert ein Konto).
## Formularfelder
| Feld | Pflicht | Hinweise |
| --- | --- | --- |
| **Nützlichkeit** | Ja | 15 Sterne |
| **Bedienbarkeit** | Ja | 15 Sterne |
| **Kommentar** | Nein | Freitext |
| **Name** | Nein | Standard „Anonym" |
Neben den Feldern führt das **?Icon** direkt zur zugehörigen Feldbeschreibung
in der [Datenmodell-Referenz](/docs/reference/schemas/ratinginput).
## Was passiert nach dem Abgeben?
- Deine Bewertung wird sofort gespeichert und erscheint in der
**Bewertungsliste** der Detailseite.
- Die **Durchschnittswerte** (Nützlichkeit, Bedienbarkeit, Kombiniert) und die
**Punkteverteilung** werden aktualisiert.
- Die **Statistiken** im Bereich [Analytics](/docs/handbook/analytics) werden
neu berechnet.
## Statistik-Bereiche auf der Detailseite
- **Bewertungsübersicht:** Nützlichkeit & Bedienbarkeit als Durchschnitt mit
Fortschrittsbalken.
- **Punkteverteilung:** Anzahl der Bewertungen pro Stern (1★–5★).
- **Verlauf:** Linienchart der kombinierten/Teilwerte über die Zeit
(erst ab mehreren Bewertungen sichtbar).
## API
- [`POST /tools/{id}/ratings`](/docs/reference/endpoints/ratings#createRating) — Bewertung abgeben
- [`GET /tools/{id}/ratings`](/docs/reference/endpoints/ratings#listToolRatings) — Bewertungen eines Tools
@@ -0,0 +1,70 @@
# Datenmodell
Dieses Kapitel erklärt die zentralen Datenobjekte von toolr auf Ebene der
Anwendung. Die vollständige, automatisch generierte Referenz aller Felder,
Typen und Constraints findest du in der
[API-Referenz](/docs/reference/schemas/tool).
## Tool
Das Herzstück: ein im Katalog erfasstes Werkzeug.
| Eigenschaft | Beschreibung |
| --- | --- |
| `id` | Eindeutige Kennung |
| `name` | Anzeigename |
| `description` | Beschreibung (Was macht das Tool?) |
| `category` | Kategorie-Zuordnung |
| `websiteUrl` | Offizielle Website (optional) |
| `iconUrl` | Logo-/Icon-URL (optional) |
| `features` | Liste von Fähigkeiten |
| `tags` | Liste von Schlagwörtern |
| `createdAt` / `updatedAt` | Zeitstempel |
| `createdBy` | Erstellende Person |
| `deletedAt` / `deletedBy` | Soft-Löschung (Papierkorb) |
Eingabe-Formulare verwenden die abgeleiteten Schemas
[`ToolInput`](/docs/reference/schemas/toolinput) und
[`ToolUpdate`](/docs/reference/schemas/toolupdate).
Aggregierte Ansichten liefert [`ToolWithStats`](/docs/reference/schemas/toolwithstats)
(z. B. mit Durchschnittsbewertung).
## Rating (Bewertung)
Eine einzelne Bewertung zu einem Tool:
- `usefulness` (Nützlichkeit, 15) und `usability` (Bedienbarkeit, 15)
- optional `comment` und ein Anzeigename (`reviewerName`)
- Zeitstempel
Eingabe-Schema: [`RatingInput`](/docs/reference/schemas/ratinginput).
## User & Auth
- [`User`](/docs/reference/schemas/user) — Benutzerkonto mit Rolle (User/Admin)
und Tarif (Free/Premium/Enterprise).
- [`AuthUser`](/docs/reference/schemas/authuser) — das angemeldete Profil
inklusive `entitlements` (verfügbare Features).
- [`UserPreferences`](/docs/reference/schemas/userpreferences) — Ansichts- und
Dichte-Präferenzen sowie die `watchlist` (Liste von Tool-IDs).
## Analytics
Die Statistik-Endpunkte liefern aggregierte Daten:
- [`AnalyticsSummary`](/docs/reference/schemas/analyticssummary) — globale
Kennzahlen (Anzahl Tools/Bewertungen, Kategorien, Durchschnitt).
- [`TopToolEntry`](/docs/reference/schemas/TopToolEntry) — ein Eintrag der
Top-Tools.- [`CategoryStats`](/docs/reference/schemas/categorystats) — Tool-Anzahl je
Kategorie.
- [`RatingDistribution`](/docs/reference/schemas/ratingdistribution) —
Punkteverteilung (Nützlichkeit & Bedienbarkeit).
- [`ScoreBucket`](/docs/reference/schemas/scorebucket) — ein Werte-Bucket.
## Weitere
- [`VersionInfo`](/docs/reference/schemas/versioninfo) — Version, Commit-SHA,
Build-Datum und Papierkorb-Aufbewahrung der laufenden Instanz.
- [`AuditLog`](/docs/reference/schemas/auditlog) — ein Protokolleintrag
(Aktion, Entität, Zeitstempel, Akteur, Änderungen).
@@ -0,0 +1,53 @@
# Erste Schritte
Diese Seite führt dich durch die wichtigsten Abläufe in toolr — vom ersten
Besuch bis zum Anlegen und Bewerten eines Tools.
## 1. Anmelden
Die meisten Aktionen (Tool anlegen, bewerten, Watchlist, Vergleichen) erfordern
ein Konto. Klicke unten links auf **Anmelden**. Je nach Konfiguration der
Instanz hast du zwei Möglichkeiten:
- **Lokale Konten:** Benutzername + Passwort. Der Zugang wird von einem Admin
angelegt (siehe [Administration](/docs/handbook/administration)).
- **OIDC (SSO):** Anmelden mit dem konfigurierten Identitätsanbieter (z. B.
Keycloak).
Welcher Modus aktiv ist, steht im Endpunkt
[`GET /auth/mode`](/docs/reference/endpoints/auth#getAuthMode). Details findest
du im Abschnitt [Anmelden & Konto](/docs/handbook/konto).
## 2. Tools finden
Öffne den Bereich **Tools durchsuchen**:
- **Suchen** — Volltextsuche über Name & Beschreibung (Tastenkürzel `/`).
- **Filtern** — nach Kategorie, Tags, Features und Mindestbewertung
(`minRating`).
- **Sortieren** — nach Aktualität, Top-Bewertung, meistbewertet, Name
(auf-/absteigend) oder letztem Update.
Alle Optionen im Detail: [Tools finden & durchsuchen](/docs/handbook/tools-finden).
## 3. Tool anlegen
Gehe auf **Tool hinzufügen** und fülle das Formular aus. Details zu jedem Feld
findest du im Abschnitt [Tool anlegen](/docs/handbook/tool-anlegen) und in der
[Feld-Referenz](/docs/reference/schemas/toolinput).
## 4. Bewerten
Auf der Detailseite eines Tools kannst du **Nützlichkeit** und **Bedienbarkeit**
(jeweils 15) vergeben und optional einen Kommentar hinterlassen. Deine
Bewertung fließt sofort in die Statistiken ein.
Siehe [Bewerten](/docs/handbook/bewerten).
## 5. Weiterführend
- [Tools vergleichen](/docs/handbook/vergleichen)
- [Watchlist](/docs/handbook/watchlist)
- [Analytics](/docs/handbook/analytics)
- [Pläne & Berechtigungen](/docs/handbook/plaene)
- [Administration](/docs/handbook/administration)
+104
View File
@@ -0,0 +1,104 @@
[
{
"slug": "index",
"file": "index.md",
"title": "Überblick",
"order": 1
},
{
"slug": "getting-started",
"file": "getting-started.md",
"title": "Erste Schritte",
"order": 2
},
{
"slug": "konto",
"file": "konto.md",
"title": "Anmelden & Konto",
"order": 3
},
{
"slug": "tools-finden",
"file": "tools-finden.md",
"title": "Tools finden & durchsuchen",
"order": 4
},
{
"slug": "tool-anlegen",
"file": "tool-anlegen.md",
"title": "Tool anlegen",
"order": 5
},
{
"slug": "tool-bearbeiten",
"file": "tool-bearbeiten.md",
"title": "Tool bearbeiten & löschen",
"order": 6
},
{
"slug": "bewerten",
"file": "bewerten.md",
"title": "Bewerten",
"order": 7
},
{
"slug": "watchlist",
"file": "watchlist.md",
"title": "Watchlist",
"order": 8
},
{
"slug": "vergleichen",
"file": "vergleichen.md",
"title": "Vergleichen",
"order": 9
},
{
"slug": "analytics",
"file": "analytics.md",
"title": "Analytics",
"order": 10
},
{
"slug": "plaene",
"file": "plaene.md",
"title": "Pläne & Berechtigungen",
"order": 11
},
{
"slug": "kosten",
"file": "kosten.md",
"title": "Kosten erfassen",
"order": 12
},
{
"slug": "administration",
"file": "administration.md",
"title": "Administration",
"order": 13
},
{
"slug": "redundanz",
"file": "redundanz.md",
"title": "Redundanz-Dashboard",
"order": 14
},
{
"slug": "papierkorb",
"file": "papierkorb.md",
"title": "Papierkorb",
"order": 15
},
{
"slug": "tastatur",
"file": "tastatur.md",
"title": "Tastenkürzel & Kommandopalette",
"order": 16
},
{
"slug": "datenmodell",
"file": "datenmodell.md",
"title": "Datenmodell",
"order": 17
}
]
+52
View File
@@ -0,0 +1,52 @@
# Willkommen bei toolr
toolr ist eine Plattform zum **Entdecken, Bewerten und Vergleichen von
Entwicklungstools**. Nutzer:innen pflegen einen gemeinsamen Katalog von Tools,
vergeben Bewertungen (Nützlichkeit & Bedienbarkeit) und nutzen Statistiken, um
die richtige Wahl zu treffen.
## Was kannst du mit toolr tun?
| Funktion | Beschreibung | Sichtbarkeit |
| --- | --- | --- |
| **Tools durchsuchen** | Katalog filtern, sortieren und durchsuchen | Alle |
| **Tool anlegen** | Neues Tool mit Beschreibung, Kategorie, Features & Tags eintragen | Angemeldet |
| **Tool bearbeiten/löschen** | Eigene Tools pflegen (Ersteller:in oder Admin) | Angemeldet |
| **Bewerten** | Nützlichkeit & Bedienbarkeit (15) plus Kommentar vergeben | Angemeldet |
| **Watchlist** | Tools als Favoriten speichern | Premium |
| **Vergleichen** | Tools nebeneinander gegenüberstellen | Premium |
| **Kosten erfassen** | Lizenz- und Kostenmodelle je Tool eintragen | Premium |
| **Analytics** | Statistiken, Top-Tools, Verteilungen | Alle |
| **Papierkorb** | Soft-gelöschte Tools wiederherstellen oder endgültig löschen | Premium |
| **Admin** | Nutzerverwaltung, Audit-Log, Systeminformationen | Admin |
| **Redundanz** | Automatische Doppelungs-Erkennung | Admin |
## Wie diese Doku aufgebaut ist
- **User Guide** (diese Seiten): Schritt-für-Schritt-Anleitungen für alle
Funktionen — von den [Ersten Schritten](/docs/handbook/getting-started) bis
zur [Administration](/docs/handbook/administration).
- **API-Referenz**: automatisch aus der OpenAPI-Spezifikation generiert — alle
[Endpunkte](/docs/reference/endpoints/tools) und
[Datenfelder](/docs/reference/schemas/toolinput) der aktuellen Version.
- **Release-Notes**: Was ist in welcher [Version](/docs/releases/v0.8.1) neu.
## Der Einstieg
Der schnellste Weg:
1. **Anmelden** — ohne Konto kannst du nur stöbern
(siehe [Erste Schritte](/docs/handbook/getting-started#1-anmelden)).
2. **Tools finden** — Suche, Filter und Sortierung im Bereich
[Tools durchsuchen](/docs/handbook/tools-finden).
3. **Tool anlegen** — über „Tool hinzufügen"
([Anleitung](/docs/handbook/tool-anlegen)).
4. **Bewerten** — auf der Detailseite eines Tools
([Anleitung](/docs/handbook/bewerten)).
## Kontakt & Quellcode
Der Quellcode liegt unter
[git.kubebase.de/admin/tool-evaluator](https://git.kubebase.de/admin/tool-evaluator) —
über das Repository-Icon oben rechts erreichst du ihn jederzeit.
+53
View File
@@ -0,0 +1,53 @@
# Anmelden & Konto
## Anmelden
Klicke unten links in der Seitenleiste auf **Anmelden**. Je nach Konfiguration
der Instanz:
- **Lokale Konten:** Benutzername und Passwort eingeben. Die Konten werden von
einem Admin angelegt (siehe [Administration](/docs/handbook/administration)).
- **OIDC (SSO):** Du wirst an den konfigurierten Identitätsanbieter
weitergeleitet und meldest dich dort an.
Der aktive Modus steht im Endpunkt
[`GET /auth/mode`](/docs/reference/endpoints/auth#getAuthMode).
> Die Login-Seite erreichst du direkt unter `/login`. Nach erfolgreicher
> Anmeldung wirst du zur ursprünglich aufgerufenen Seite zurückgeleitet.
## Benutzerprofil
Dein Profil (Avatar, Name, E-Mail, Tarif) siehst du unten links im
Benutzermenü. Dort stehen dir folgende Aktionen zur Verfügung:
- **Watchlist** — deine gespeicherten Tools (nur mit dem entsprechenden Tarif).
- **Papierkorb** — wiederherstellbare, gelöschte Tools (Premium/Enterprise).
- **Passwort ändern** — für lokale Konten direkt in toolr; für OIDC-Konten wird
die Passwortverwaltung im Identitätsanbieter angeboten.
- **Abmelden** — beendet deine Sitzung.
## Passwort ändern (lokales Konto)
1. Öffne das Benutzermenü unten links.
2. Wähle **Passwort ändern**.
3. Gib das **aktuelle** sowie ein **neues** Passwort ein (mind. 6 Zeichen) und
bestätige es.
4. Speichern — das Passwort wird sofort übernommen.
API-Referenz: [`POST /auth/me/password`](/docs/reference/endpoints/auth#changeMyPassword).
## Anzeigeeinstellungen
Über die Schaltflächen oben rechts kannst du:
- **Sprache** wechseln (Deutsch / Englisch),
- **Theme** umschalten (Hell / Dunkel / System),
- die **Listenansicht** und **Dichte** im Bereich Tools durchsuchen anpassen
(siehe [Tools finden & durchsuchen](/docs/handbook/tools-finden)).
Deine Präferenzen (inkl. Watchlist) werden im Endpunkt
[`GET /auth/me/preferences`](/docs/reference/endpoints/auth#getMePreferences)
gespeichert und über [`PUT /auth/me/preferences`](/docs/reference/endpoints/auth#updateMePreferences)
aktualisiert.
+35
View File
@@ -0,0 +1,35 @@
# Kosten erfassen
Auf der Detailseite eines Tools kannst du Kosten- und Lizenzmodelle eintragen,
damit die Gesamtkosten je Tool transparent werden.
> Kosten ist ein **Premium-Feature** (`costs`, Premium/Enterprise). Admins
> haben immer Zugriff.
## Kosten hinzufügen
Klicke auf **Kosten hinzufügen** im Kosten-Bereich der Detailseite und fülle
das Formular aus:
| Feld | Hinweise |
| --- | --- |
| **Lizenztyp** | Free / Subscription / One-Time / Usage-Based |
| **Abrechnungszeitraum** | Nur für „Subscription": Monatlich / Quartalsweise / Jährlich |
| **Kosten** | Betrag als Zahl |
| **Währung** | EUR / USD / GBP / CHF |
| **Notizen** | Optionaler Freitext |
Speichern legt den Eintrag an. Jeder Kosten-Eintrag wird als Karte mit
Lizenz-Badge, Abrechnungszeitraum, Betrag (`Betrag Währung` bzw. „Free") und
Notizen angezeigt.
## Kosten bearbeiten & löschen
Beim Überfahren einer Kosten-Karte erscheinen die Aktionen **Bearbeiten**
(Bleistift) und **Löschen** (Papierkorb).
## API
Die Kosten-Daten werden über die Tool-Endpunkte verwaltet
(siehe [API-Referenz](/docs/reference/endpoints/tools)).
@@ -0,0 +1,41 @@
# Papierkorb
Der **Papierkorb** (`/trash`) enthält soft gelöschte Tools. Mit Papierkorb-Zugang
können sie wiederhergestellt werden; endgültiges Löschen ist Admins vorbehalten.
> Der Papierkorb ist ein **Premium-Feature** (`trash`, Premium/Enterprise).
> Admins haben immer Zugriff.
## Zugang
Der Papierkorb ist über das Benutzermenü oder die Seitenleiste erreichbar.
Ohne `trash`-Berechtigung erscheint ein Hinweis auf den Tarifwechsel.
## Wiederherstellen
- Markiere ein oder mehrere Tools (Checkboxen).
- Klicke auf **Wiederherstellen (N)** — die Tools erscheinen wieder in allen
öffentlichen Ansichten.
> Wiederherstellen steht jeder Person mit Papierkorb-Zugang zur Verfügung.
## Endgültig löschen (nur Admin)
- **Löschen (N)** entfernt die ausgewählten Tools **endgültig** — inklusive
aller Bewertungen, Kosten und Verknüpfungen. Das kann nicht rückgängig
gemacht werden.
- **Papierkorb leeren** entfernt alle soft gelöschten Tools endgültig.
## Tabelle
Der Papierkorb listet: Name, Kategorie, **Gelöscht am** (`tt.MM.jjjj HH:mm`),
**Gelöscht von** sowie Aktionen (Wiederherstellen; Löschen nur Admin). Die Suche
filtert nach Namen.
## API
- [`GET /tools/trash`](/docs/reference/endpoints/tools#listTrashedTools) — Liste
- [`POST /tools/trash/restore`](/docs/reference/endpoints/tools#restoreTools) — Wiederherstellen
- [`DELETE /tools/trash`](/docs/reference/endpoints/tools#deleteTrashedTools) — Endgültig löschen (Admin)
- [`POST /tools/trash/empty`](/docs/reference/endpoints/tools#emptyTrash) — Papierkorb leeren (Admin)
+41
View File
@@ -0,0 +1,41 @@
# Pläne & Berechtigungen
toolr unterscheidet **Tarife** (Tier) und **Rollen**. Admins umgehen alle
Feature-Beschränkungen.
## Tarife
| Tarif | Beschreibung |
| --- | --- |
| **Free** | Grundfunktionen: suchen, filtern, ansehen, Analytics |
| **Premium** | Zusätzlich Watchlist, Vergleichen, Papierkorb, Kosten |
| **Enterprise** | Alle Premium-Features + erweiterter Support |
### Feature-Berechtigungen
Premium/Enterprise schalten folgende Features frei:
| Feature | Funktion | Mehr erfahren |
| --- | --- | --- |
| `compare` | Tools vergleichen | [Vergleichen](/docs/handbook/vergleichen) |
| `watchlist` | Favoritenliste | [Watchlist](/docs/handbook/watchlist) |
| `trash` | Papierkorb (soft gelöschte Tools) | [Papierkorb](/docs/handbook/papierkorb) |
| `costs` | Kosten-/Lizenzmodelle erfassen | [Kosten erfassen](/docs/handbook/kosten) |
Fehlt dir ein Feature, zeigt die App einen **Upgrade-Hinweis** mit Link zur
Tarifverwaltung.
## Rollen
| Rolle | Berechtigungen |
| --- | --- |
| **User** | Standard-Konto: Tools anlegen/bewerten, eigene Tools bearbeiten |
| **Admin** | Alle User-Rechte + Verwaltung, Audit-Log, Redundanz, Papierkorb leeren, Tool-Verknüpfungen |
Admins passieren **alle** Feature-Checks — auch ohne Premium-Tarif.
## Tarif-/Rollenverwaltung
Die Zuordnung von Rolle und Tarif wird durch Admins im Bereich
[Administration](/docs/handbook/administration) (Tab „Nutzer") verwaltet.
@@ -0,0 +1,38 @@
# Redundanz-Dashboard
Das **Redundanz-Dashboard** (`/admin/redundancy`) ist ein Admin-Werkzeug zur
automatischen Erkennung doppelter oder stark überlappender Tools — jeweils
pro Kategorie — inklusive Kosten- und Bewertungsvergleich.
> Der Zugriff ist ausschließlich Admins vorbehalten (die API ist
> admin-geschützt).
## Aufbau
- **Pro Kategorie** wird eine Gruppe angezeigt: Name der Kategorie,
Anzahl Tools und Vergleiche sowie ggf. die **gesamten monatlichen Kosten**
(z. B. `€X.XX/mo gesamt`).
- Jedes Tool wird als Karte dargestellt: Name, monatliche Kosten, Anzahl der
Bewertungen, kombinierte Bewertung, Lizenz-Badges und Feature-Anzahl.
## Vergleiche & Empfehlungen
Für jedes Tool-Paar erscheint:
- Tool A vs. Tool B, jeweils mit Bewertung (`X.X ★`) und monatlichen Kosten.
- **Überlappung** in Prozent (Fortschrittsbalken in der Mitte).
- Eine **Empfehlung** mit Konfidenz-Farbe:
- **hoch** (grün), **mittel** (gelb), **niedrig** (grau)
- Das empfohlene, bessere Tool wird mit „Daumen hoch" markiert und begründet.
## Manuelle Bewertung
Du kannst ein Paar manuell bewerten: Klicke auf Tool A oder Tool B, um
festzuhalten, welches besser ist. Die Auswahl wird gespeichert und die
Darstellung aktualisiert.
## API
- [`GET /api/admin/redundancy`](#) — Daten laden (admin-geschützt)
- [`POST /api/admin/redundancy/evaluate`](#) — manuelle Bewertung speichern
+36
View File
@@ -0,0 +1,36 @@
# Tastenkürzel & Kommandopalette
## Kommandopalette
Die Kommandopalette ist die zentrale Schnellnavigation:
- Öffnen mit **`⌘K`** (macOS) bzw. **`Ctrl+K`** (Windows/Linux).
- Alternativ über die Suchleiste oben rechts („Tools suchen… ⌘K") oder das
Such-Icon auf Mobilgeräten.
### Leerer Zustand
Ohne Eingabe zeigt die Palette:
- **Zuletzt angesehen** — die letzten 5 Tools, die du besucht hast.
- **Navigation** — Tools durchsuchen, Tool hinzufügen, Analytics sowie
(abhängig von Berechtigungen) Watchlist, Papierkorb und Admin.
### Suche
Tippe, um live nach Tools zu suchen (max. 10 Ergebnisse, inkl. Bewertung
`X.X★`).
## Tastenkürzel im Überblick
| Kürzel | Aktion |
| --- | --- |
| `⌘K` / `Ctrl+K` | Kommandopalette öffnen |
| `/` | Suche im Bereich „Tools durchsuchen" fokussieren |
## Weitere Hinweise
- **Zuletzt angesehen** wird lokal im Browser gespeichert (max. 5 Einträge).
- Die Seitenleiste (linke Navigation) ist auf Desktop einklappbar; der
Breadcrumb oben zeigt deinen aktuellen Ort.
@@ -0,0 +1,46 @@
# Tool anlegen
Um ein neues Tool zum Katalog hinzuzufügen, klicke auf **Tool hinzufügen**
(`/tools/new`). Das Anlegen erfordert ein Konto — ohne Anmeldung erscheint ein
Hinweis mit Login-Button.
## Formularfelder
| Feld | Pflicht | Hinweise |
| --- | --- | --- |
| **Name** | Ja | Mind. 2 Zeichen |
| **Kategorie** | Ja | Auswahlliste; neue Kategorien lassen sich direkt anlegen |
| **Website URL** | Nein | Gültige URL (z. B. `https://...`) |
| **Icon / Logo URL** | Nein | Gültige URL; Vorschau wird live angezeigt |
| **Beschreibung** | Ja | Mind. 10 Zeichen; beschreibe, was das Tool tut |
| **Features** | Nein | Dynamische Liste mit Autovervollständigung (max. 6) |
| **Tags** | Nein | Dynamische Liste mit Autovervollständigung |
Neben jedem Feld führt das **?Icon** direkt zur zugehörigen Feldbeschreibung
in der [Datenmodell-Referenz](/docs/reference/schemas/toolinput).
### Kategorie
- Tippe, um nach bestehenden Kategorien zu suchen.
- Wähle **+ Erstelle „..."**, um eine neue Kategorie anzulegen.
### Features & Tags
- **Feature hinzufügen** / **Tag hinzufügen** hängt eine neue Zeile an.
- Die Eingabefelder schlagen bestehende Features/Tags vor
(Autovervollständigung, max. 6 Vorschläge).
- Mit dem **×**Button entfernst du einzelne Zeilen.
- Features und Tags helfen beim Filtern und Wiederfinden.
## Speichern
Klicke auf **Tool hinzufügen**. Nach erfolgreicher Anlage wirst du auf die
Detailseite des neuen Tools weitergeleitet.
## API
- [`POST /tools`](/docs/reference/endpoints/tools#createTool) — Tool anlegen
- [`GET /categories`](/docs/reference/endpoints/tools#listCategories) — Kategorien
- [`GET /features/all`](/docs/reference/endpoints/tools#listAllFeatures) — Features
- [`GET /tags/all`](/docs/reference/endpoints/tools#listAllTags) — Tags
@@ -0,0 +1,33 @@
# Tool bearbeiten & löschen
## Bearbeiten
Auf der Detailseite eines Tools findest du die Schaltfläche **Bearbeiten**
(nur für die Person, die das Tool angelegt hat, sowie für Admins).
Die Bearbeitungsseite (`/tools/:id/edit`) enthält dieselben Felder wie beim
Anlegen (Name, Kategorie, Website/Icon-URL, Beschreibung, Features, Tags) —
bereits mit den aktuellen Werten befüllt.
- **Speichern** übernimmt die Änderungen.
- **Abbrechen** führt zurück zur Detailseite.
API-Referenz: [`PATCH /tools/{id}`](/docs/reference/endpoints/tools#updateTool).
## Löschen
Über **Löschen** auf der Detailseite wird das Tool entfernt. Das Verhalten
hängt von deinem Tarif ab:
- **Mit Papierkorb-Zugang** (Premium/Enterprise oder Admin): Das Tool wird
**soft gelöscht** — es verschwindet aus allen öffentlichen Ansichten, kann
aber im [Papierkorb](/docs/handbook/papierkorb) wiederhergestellt oder
endgültig gelöscht werden.
- **Ohne Papierkorb-Zugang:** Das Tool wird **endgültig** gelöscht und kann
nicht wiederhergestellt werden.
Die Löschung ist nur für die Person, die das Tool angelegt hat, sowie für
Admins möglich.
API-Referenz: [`DELETE /tools/{id}`](/docs/reference/endpoints/tools#deleteTool).
@@ -0,0 +1,67 @@
# Tools finden & durchsuchen
Der Bereich **Tools durchsuchen** (`/tools`) ist der Einstieg in den Katalog.
Hier kombinierst du Suche, Filter und Sortierung, um genau die Tools zu finden,
die dich interessieren.
## Suche
- Die **Suchleiste** durchsucht Name und Beschreibung (Volltext).
- Tastenkürzel: Drücke **`/`**, um die Suche zu fokussieren.
- Die Eingabe ist deaktiviert (Debounce), damit bei jedem Tastendruck sofort
nachgefiltert wird.
## Filtern
Über die Schaltfläche **Filter** (mit Badge für die Anzahl aktiver Filter)
öffnest du den Filter-Popover mit:
- **Tags** — Auswahl über Checkboxen (scrollbare Liste).
- **Features** — Auswahl über Checkboxen.
- **Mindestbewertung** — Schieberegler von 0 bis 5 (Schritte von 0,5); zeigt
z. B. „3.0+" an.
Aktive Filter erscheinen als **entfernbare Chips** über der Ergebnisliste.
Mit **Filter zurücksetzen** bzw. **Alle entfernen** räumst du sie wieder auf.
## Sortieren
Über das Dropdown **Sortieren** stehen folgende Optionen zur Verfügung:
| Sortierung | Beschreibung |
| --- | --- |
| Neueste | Neue Tools zuerst |
| Top bewertet | Nach kombinierter Bewertung |
| Meistbewertet | Nach Anzahl der Bewertungen |
| Name (AZ) | Alphabetisch aufsteigend |
| Name (ZA) | Alphabetisch absteigend |
| Zuletzt aktualisiert | Nach letztem Update |
## Ansicht & Dichte
- **Ansicht wechseln:** Raster / Tabelle / Zeilen.
- **Dichte:** gemütlich / kompakt (Schieberegler).
Deine Auswahl wird gespeichert — lokal im Browser und für angemeldete Nutzer:innen
zusätzlich serverseitig in den Präferenzen. Ansicht, Dichte, Suche, Filter und
Sortierung werden dabei in die URL übernommen, sodass du Ergebnisse teilen
kannst.
## Tabellenansicht
In der Tabellenansicht sind die Spalten **Tool**, **Bewertung** und **Anzahl
Bewertungen** sortierbar. Beim Überfahren einer Zeile erscheint eine Vorschau
mit Bewertungsdetails, Tags und Mini-Balken.
## Auswählen für Vergleich & Watchlist
- Auf jeder Karte/Zeile findest du ein **Vergleichs-Icon**, mit dem du Tools zur
[Vergleichsleiste](/docs/handbook/vergleichen) hinzufügst.
- Das **Lesezeichen-Icon** speichert Tools in deiner
[Watchlist](/docs/handbook/watchlist) (nur mit dem entsprechenden Tarif).
## API
Alle Such-, Filter- und Sortierparameter entsprechen den Query-Parametern von
[`GET /tools`](/docs/reference/endpoints/tools#listTools).
@@ -0,0 +1,42 @@
# Vergleichen
Mit der Vergleichsfunktion stellst du mehrere Tools **nebeneinander** gegenüber —
ideal, um eine fundierte Entscheidung zu treffen.
> Vergleichen ist ein **Premium-Feature** (Premium/Enterprise) und steht Admins
> immer zur Verfügung.
## Tools auswählen
1. Im Bereich **Tools durchsuchen** klickst du auf jeder Karte/Zeile auf das
**Vergleichs-Icon** (Waage).
2. Unten erscheint die **Vergleichsleiste** mit den ausgewählten Tools als
Chips. Du kannst einzelne Tools entfernen (×) oder die Auswahl leeren.
3. Klicke auf **Vergleichen (N)**, um zur Vergleichsansicht zu gelangen.
> Ohne Premium-Tarif ist der Button gesperrt (Schloss-Icon). Über den
> Dialog gelangst du zum Tarifwechsel
> (siehe [Pläne & Berechtigungen](/docs/handbook/plaene)).
## Die Vergleichsansicht
Die Ansicht zeigt eine Tabelle mit einer Spalte pro Tool. Zeilen:
| Zeile | Inhalt |
| --- | --- |
| **Bewertung** | Sterne + Wert (z. B. `4.2/5`) |
| **Nützlichkeit** | Wert (X.X/5) |
| **Bedienbarkeit** | Wert (X.X/5) |
| **Anzahl Bewertungen** | Anzahl |
| **Beschreibung** | Text |
| **Features** | Badges |
| **Tags** | Badges |
| **Zuletzt aktualisiert** | Datum |
Der **beste Wert** pro Zeile wird hervorgehoben (mit Trophäen-Icon).
## API
Die Vergleichsansicht liest die Daten über
[`GET /compare`](/docs/reference/endpoints/tools#listCompareTools).
@@ -0,0 +1,34 @@
# Watchlist
Die **Watchlist** ist eine persönliche Favoritenliste. Tools darin kannst du
jederzeit per Klick wieder aufrufen und vergleichen.
> Die Watchlist ist ein **Premium-Feature** (Premium/Enterprise) und steht
> Admins immer zur Verfügung.
## Voraussetzung
Du benötigst einen Tarif mit `watchlist`-Berechtigung. Fehlt diese, erscheint
beim Lesezeichen ein Hinweis auf den Tarifwechsel
(siehe [Pläne & Berechtigungen](/docs/handbook/plaene)).
## Tool speichern
- Auf jeder Karte/Zeile im Bereich **Tools durchsuchen** findest du das
**Lesezeichen-Icon**.
- Ein Klick speichert das Tool in deiner Watchlist — das Icon wird gefüllt.
- Ein erneuter Klick entfernt es wieder.
## Watchlist ansehen
Öffne die Watchlist über das Benutzermenü oder die Seitenleiste. Sie zeigt alle
gespeicherten Tools als Karten. Das gefüllte Lesezeichen auf einer Karte
entfernt das Tool aus der Liste.
## Wo wird die Watchlist gespeichert?
Die Watchlist ist eine Liste von Tool-IDs in deinen **Benutzerpräferenzen**.
Damit ist sie geräteübergreifend mit deinem Konto verbunden.
API-Referenz: [`GET /auth/me/watchlist`](/docs/reference/endpoints/auth#getMeWatchlist).
File diff suppressed because it is too large Load Diff
+2 -2
View File
@@ -1,6 +1,6 @@
# v0.8.2 — Release Notes
**Datum:** 2026-08-04 · **Tag:** [`v0.8.2`](https://git.kubebase.de/admin/tool-evaluator/tags/v0.8.2)
**Datum:** 2026-08-04 · **Tag:** [`v0.8.2`](https://git.kubebase.de/admin/tool-evaluator/releases/tag/v0.8.2)
## Fixes & Verbesserungen
@@ -33,4 +33,4 @@
## Links
- Commit: [`33cf261`](https://git.kubebase.de/admin/tool-evaluator/commit/33cf261)
- Tag: [`v0.8.2`](https://git.kubebase.de/admin/tool-evaluator/tags/v0.8.2)
- Tag: [`v0.8.2`](https://git.kubebase.de/admin/tool-evaluator/releases/tag/v0.8.2)
@@ -0,0 +1,61 @@
# Administration
Der Bereich **Admin** (`/admin`) ist ausschließlich für Admins zugänglich.
Ohne Admin-Rolle erscheint eine Zugriffsverweigerung.
> Oben rechts führt die Schaltfläche **Redundanz-Dashboard** zur automatischen
> Doppelungs-Erkennung (siehe [Redundanz](/docs/handbook/redundanz)).
## Tab „Nutzer"
Verwaltung der lokalen Konten.
- **Nutzer hinzufügen:** Benutzername (Pflicht), Passwort (mind. 6 Zeichen),
E-Mail (optional), **Rolle** (User/Admin), **Tarif** (Free/Premium/Enterprise).
- **Nutzer bearbeiten:** Rolle, Tarif und (für lokale Konten) ein neues Passwort
setzen. Für OIDC-Konten wird die Passwortverwaltung im Identitätsanbieter
(z. B. Keycloak) angeboten.
- **Nutzer löschen:** Entfernt das Konto endgültig (nicht für das eigene Konto).
API-Referenz:
[`POST /users`](/docs/reference/endpoints/users#createUser),
[`PATCH /users/{id}`](/docs/reference/endpoints/users#updateUser),
[`DELETE /users/{id}`](/docs/reference/endpoints/users#deleteUser).
## Tab „Tools"
Zentraler Zugriff auf den Tool-Katalog.
- **Suchen** nach Tools.
- Tools einzeln ansehen, bearbeiten oder in den Papierkorb verschieben.
- **Massenaktion:** mehrere Tools auswählen und in den Papierkorb verschieben
(Bestätigungsdialog; soft gelöschte Tools sind aus allen öffentlichen Ansichten
entfernt und können wiederhergestellt oder endgültig gelöscht werden).
## Tab „Audit-Log"
Chronologisches Protokoll aller Anlage-, Änderungs- und Löschvorgänge
(max. 100 Einträge): Aktion, Entität + ID, Zeitstempel, ausführende Person und
geänderte Felder.
API-Referenz: [`GET /audit-logs`](/docs/reference/endpoints/audit#listAuditLogs).
## Tab „System"
Versionsinformationen der laufenden Instanz:
- **Version** (z. B. `v0.8.1`),
- **Commit** (7-stelliger SHA, verlinkt zum Repository),
- **Build-Datum**,
- **Papierkorb-Aufbewahrung** („N Tage" oder „Für immer").
## Tool-Verknüpfungen (Admin)
Auf der Detailseite eines Tools kannst du als Admin **Verknüpfungen**
(eigene/„manual" sowie automatisch erkannte) verwalten:
- **Tool verknüpfen:** Dialog mit Tool-ID, **Beziehungstyp**
(Ähnlich / Ersetzt / Abgelöst durch) und optionalen Notizen.
- Beziehungstypen werden als Badges auf der Detailseite angezeigt.
- Manuelle Verknüpfungen lassen sich per Papierkorb-Icon wieder entfernen.
@@ -0,0 +1,29 @@
# Analytics
Der Bereich **Analytics** (`/analytics`) ist ein öffentliches Dashboard mit
Kennzahlen und Diagrammen auf Basis aller Tools und Bewertungen.
## Kennzahlen (KPI-Karten)
- **Anzahl Tools** — wie viele Tools sind im Katalog erfasst.
- **Anzahl Bewertungen** — wie viele Bewertungen wurden insgesamt abgegeben.
- **Aktive Kategorien** — wie viele Kategorien existieren.
- **Durchschnittliche Bewertung** — globaler kombinierter Wert.
## Diagramme
| Diagramm | Inhalt |
| --- | --- |
| **Top 8 Tools** | Balkendiagramm der Tools mit der höchsten kombinierten Punktzahl (05) |
| **Tools je Kategorie** | Radar-Diagramm der Tool-Anzahl pro Kategorie |
| **Punkteverteilung** | Zwei horizontale Balken-Diagramme (Nützlichkeit & Bedienbarkeit) pro Stern |
Die Diagramme sind interaktiv (Tooltips beim Überfahren).
## API
- [`GET /analytics/summary`](/docs/reference/endpoints/analytics#getAnalyticsSummary)
- [`GET /analytics/top-tools`](/docs/reference/endpoints/analytics#getTopTools)
- [`GET /analytics/by-category`](/docs/reference/endpoints/analytics#getAnalyticsByCategory)
- [`GET /analytics/rating-distribution`](/docs/reference/endpoints/analytics#getRatingDistribution)
+39
View File
@@ -0,0 +1,39 @@
# Bewerten
Auf der Detailseite eines Tools kannst du deine Erfahrung teilen. Klicke auf
**Bewertung abgeben** (erfordert ein Konto).
## Formularfelder
| Feld | Pflicht | Hinweise |
| --- | --- | --- |
| **Nützlichkeit** | Ja | 15 Sterne |
| **Bedienbarkeit** | Ja | 15 Sterne |
| **Kommentar** | Nein | Freitext |
| **Name** | Nein | Standard „Anonym" |
Neben den Feldern führt das **?Icon** direkt zur zugehörigen Feldbeschreibung
in der [Datenmodell-Referenz](/docs/reference/schemas/ratinginput).
## Was passiert nach dem Abgeben?
- Deine Bewertung wird sofort gespeichert und erscheint in der
**Bewertungsliste** der Detailseite.
- Die **Durchschnittswerte** (Nützlichkeit, Bedienbarkeit, Kombiniert) und die
**Punkteverteilung** werden aktualisiert.
- Die **Statistiken** im Bereich [Analytics](/docs/handbook/analytics) werden
neu berechnet.
## Statistik-Bereiche auf der Detailseite
- **Bewertungsübersicht:** Nützlichkeit & Bedienbarkeit als Durchschnitt mit
Fortschrittsbalken.
- **Punkteverteilung:** Anzahl der Bewertungen pro Stern (1★–5★).
- **Verlauf:** Linienchart der kombinierten/Teilwerte über die Zeit
(erst ab mehreren Bewertungen sichtbar).
## API
- [`POST /tools/{id}/ratings`](/docs/reference/endpoints/ratings#createRating) — Bewertung abgeben
- [`GET /tools/{id}/ratings`](/docs/reference/endpoints/ratings#listToolRatings) — Bewertungen eines Tools
@@ -0,0 +1,70 @@
# Datenmodell
Dieses Kapitel erklärt die zentralen Datenobjekte von toolr auf Ebene der
Anwendung. Die vollständige, automatisch generierte Referenz aller Felder,
Typen und Constraints findest du in der
[API-Referenz](/docs/reference/schemas/tool).
## Tool
Das Herzstück: ein im Katalog erfasstes Werkzeug.
| Eigenschaft | Beschreibung |
| --- | --- |
| `id` | Eindeutige Kennung |
| `name` | Anzeigename |
| `description` | Beschreibung (Was macht das Tool?) |
| `category` | Kategorie-Zuordnung |
| `websiteUrl` | Offizielle Website (optional) |
| `iconUrl` | Logo-/Icon-URL (optional) |
| `features` | Liste von Fähigkeiten |
| `tags` | Liste von Schlagwörtern |
| `createdAt` / `updatedAt` | Zeitstempel |
| `createdBy` | Erstellende Person |
| `deletedAt` / `deletedBy` | Soft-Löschung (Papierkorb) |
Eingabe-Formulare verwenden die abgeleiteten Schemas
[`ToolInput`](/docs/reference/schemas/toolinput) und
[`ToolUpdate`](/docs/reference/schemas/toolupdate).
Aggregierte Ansichten liefert [`ToolWithStats`](/docs/reference/schemas/toolwithstats)
(z. B. mit Durchschnittsbewertung).
## Rating (Bewertung)
Eine einzelne Bewertung zu einem Tool:
- `usefulness` (Nützlichkeit, 15) und `usability` (Bedienbarkeit, 15)
- optional `comment` und ein Anzeigename (`reviewerName`)
- Zeitstempel
Eingabe-Schema: [`RatingInput`](/docs/reference/schemas/ratinginput).
## User & Auth
- [`User`](/docs/reference/schemas/user) — Benutzerkonto mit Rolle (User/Admin)
und Tarif (Free/Premium/Enterprise).
- [`AuthUser`](/docs/reference/schemas/authuser) — das angemeldete Profil
inklusive `entitlements` (verfügbare Features).
- [`UserPreferences`](/docs/reference/schemas/userpreferences) — Ansichts- und
Dichte-Präferenzen sowie die `watchlist` (Liste von Tool-IDs).
## Analytics
Die Statistik-Endpunkte liefern aggregierte Daten:
- [`AnalyticsSummary`](/docs/reference/schemas/analyticssummary) — globale
Kennzahlen (Anzahl Tools/Bewertungen, Kategorien, Durchschnitt).
- [`TopToolEntry`](/docs/reference/schemas/TopToolEntry) — ein Eintrag der
Top-Tools.- [`CategoryStats`](/docs/reference/schemas/categorystats) — Tool-Anzahl je
Kategorie.
- [`RatingDistribution`](/docs/reference/schemas/ratingdistribution) —
Punkteverteilung (Nützlichkeit & Bedienbarkeit).
- [`ScoreBucket`](/docs/reference/schemas/scorebucket) — ein Werte-Bucket.
## Weitere
- [`VersionInfo`](/docs/reference/schemas/versioninfo) — Version, Commit-SHA,
Build-Datum und Papierkorb-Aufbewahrung der laufenden Instanz.
- [`AuditLog`](/docs/reference/schemas/auditlog) — ein Protokolleintrag
(Aktion, Entität, Zeitstempel, Akteur, Änderungen).
@@ -0,0 +1,53 @@
# Erste Schritte
Diese Seite führt dich durch die wichtigsten Abläufe in toolr — vom ersten
Besuch bis zum Anlegen und Bewerten eines Tools.
## 1. Anmelden
Die meisten Aktionen (Tool anlegen, bewerten, Watchlist, Vergleichen) erfordern
ein Konto. Klicke unten links auf **Anmelden**. Je nach Konfiguration der
Instanz hast du zwei Möglichkeiten:
- **Lokale Konten:** Benutzername + Passwort. Der Zugang wird von einem Admin
angelegt (siehe [Administration](/docs/handbook/administration)).
- **OIDC (SSO):** Anmelden mit dem konfigurierten Identitätsanbieter (z. B.
Keycloak).
Welcher Modus aktiv ist, steht im Endpunkt
[`GET /auth/mode`](/docs/reference/endpoints/auth#getAuthMode). Details findest
du im Abschnitt [Anmelden & Konto](/docs/handbook/konto).
## 2. Tools finden
Öffne den Bereich **Tools durchsuchen**:
- **Suchen** — Volltextsuche über Name & Beschreibung (Tastenkürzel `/`).
- **Filtern** — nach Kategorie, Tags, Features und Mindestbewertung
(`minRating`).
- **Sortieren** — nach Aktualität, Top-Bewertung, meistbewertet, Name
(auf-/absteigend) oder letztem Update.
Alle Optionen im Detail: [Tools finden & durchsuchen](/docs/handbook/tools-finden).
## 3. Tool anlegen
Gehe auf **Tool hinzufügen** und fülle das Formular aus. Details zu jedem Feld
findest du im Abschnitt [Tool anlegen](/docs/handbook/tool-anlegen) und in der
[Feld-Referenz](/docs/reference/schemas/toolinput).
## 4. Bewerten
Auf der Detailseite eines Tools kannst du **Nützlichkeit** und **Bedienbarkeit**
(jeweils 15) vergeben und optional einen Kommentar hinterlassen. Deine
Bewertung fließt sofort in die Statistiken ein.
Siehe [Bewerten](/docs/handbook/bewerten).
## 5. Weiterführend
- [Tools vergleichen](/docs/handbook/vergleichen)
- [Watchlist](/docs/handbook/watchlist)
- [Analytics](/docs/handbook/analytics)
- [Pläne & Berechtigungen](/docs/handbook/plaene)
- [Administration](/docs/handbook/administration)
+104
View File
@@ -0,0 +1,104 @@
[
{
"slug": "index",
"file": "index.md",
"title": "Überblick",
"order": 1
},
{
"slug": "getting-started",
"file": "getting-started.md",
"title": "Erste Schritte",
"order": 2
},
{
"slug": "konto",
"file": "konto.md",
"title": "Anmelden & Konto",
"order": 3
},
{
"slug": "tools-finden",
"file": "tools-finden.md",
"title": "Tools finden & durchsuchen",
"order": 4
},
{
"slug": "tool-anlegen",
"file": "tool-anlegen.md",
"title": "Tool anlegen",
"order": 5
},
{
"slug": "tool-bearbeiten",
"file": "tool-bearbeiten.md",
"title": "Tool bearbeiten & löschen",
"order": 6
},
{
"slug": "bewerten",
"file": "bewerten.md",
"title": "Bewerten",
"order": 7
},
{
"slug": "watchlist",
"file": "watchlist.md",
"title": "Watchlist",
"order": 8
},
{
"slug": "vergleichen",
"file": "vergleichen.md",
"title": "Vergleichen",
"order": 9
},
{
"slug": "analytics",
"file": "analytics.md",
"title": "Analytics",
"order": 10
},
{
"slug": "plaene",
"file": "plaene.md",
"title": "Pläne & Berechtigungen",
"order": 11
},
{
"slug": "kosten",
"file": "kosten.md",
"title": "Kosten erfassen",
"order": 12
},
{
"slug": "administration",
"file": "administration.md",
"title": "Administration",
"order": 13
},
{
"slug": "redundanz",
"file": "redundanz.md",
"title": "Redundanz-Dashboard",
"order": 14
},
{
"slug": "papierkorb",
"file": "papierkorb.md",
"title": "Papierkorb",
"order": 15
},
{
"slug": "tastatur",
"file": "tastatur.md",
"title": "Tastenkürzel & Kommandopalette",
"order": 16
},
{
"slug": "datenmodell",
"file": "datenmodell.md",
"title": "Datenmodell",
"order": 17
}
]
+52
View File
@@ -0,0 +1,52 @@
# Willkommen bei toolr
toolr ist eine Plattform zum **Entdecken, Bewerten und Vergleichen von
Entwicklungstools**. Nutzer:innen pflegen einen gemeinsamen Katalog von Tools,
vergeben Bewertungen (Nützlichkeit & Bedienbarkeit) und nutzen Statistiken, um
die richtige Wahl zu treffen.
## Was kannst du mit toolr tun?
| Funktion | Beschreibung | Sichtbarkeit |
| --- | --- | --- |
| **Tools durchsuchen** | Katalog filtern, sortieren und durchsuchen | Alle |
| **Tool anlegen** | Neues Tool mit Beschreibung, Kategorie, Features & Tags eintragen | Angemeldet |
| **Tool bearbeiten/löschen** | Eigene Tools pflegen (Ersteller:in oder Admin) | Angemeldet |
| **Bewerten** | Nützlichkeit & Bedienbarkeit (15) plus Kommentar vergeben | Angemeldet |
| **Watchlist** | Tools als Favoriten speichern | Premium |
| **Vergleichen** | Tools nebeneinander gegenüberstellen | Premium |
| **Kosten erfassen** | Lizenz- und Kostenmodelle je Tool eintragen | Premium |
| **Analytics** | Statistiken, Top-Tools, Verteilungen | Alle |
| **Papierkorb** | Soft-gelöschte Tools wiederherstellen oder endgültig löschen | Premium |
| **Admin** | Nutzerverwaltung, Audit-Log, Systeminformationen | Admin |
| **Redundanz** | Automatische Doppelungs-Erkennung | Admin |
## Wie diese Doku aufgebaut ist
- **User Guide** (diese Seiten): Schritt-für-Schritt-Anleitungen für alle
Funktionen — von den [Ersten Schritten](/docs/handbook/getting-started) bis
zur [Administration](/docs/handbook/administration).
- **API-Referenz**: automatisch aus der OpenAPI-Spezifikation generiert — alle
[Endpunkte](/docs/reference/endpoints/tools) und
[Datenfelder](/docs/reference/schemas/toolinput) der aktuellen Version.
- **Release-Notes**: Was ist in welcher [Version](/docs/releases/v0.8.1) neu.
## Der Einstieg
Der schnellste Weg:
1. **Anmelden** — ohne Konto kannst du nur stöbern
(siehe [Erste Schritte](/docs/handbook/getting-started#1-anmelden)).
2. **Tools finden** — Suche, Filter und Sortierung im Bereich
[Tools durchsuchen](/docs/handbook/tools-finden).
3. **Tool anlegen** — über „Tool hinzufügen"
([Anleitung](/docs/handbook/tool-anlegen)).
4. **Bewerten** — auf der Detailseite eines Tools
([Anleitung](/docs/handbook/bewerten)).
## Kontakt & Quellcode
Der Quellcode liegt unter
[git.kubebase.de/admin/tool-evaluator](https://git.kubebase.de/admin/tool-evaluator) —
über das Repository-Icon oben rechts erreichst du ihn jederzeit.
+53
View File
@@ -0,0 +1,53 @@
# Anmelden & Konto
## Anmelden
Klicke unten links in der Seitenleiste auf **Anmelden**. Je nach Konfiguration
der Instanz:
- **Lokale Konten:** Benutzername und Passwort eingeben. Die Konten werden von
einem Admin angelegt (siehe [Administration](/docs/handbook/administration)).
- **OIDC (SSO):** Du wirst an den konfigurierten Identitätsanbieter
weitergeleitet und meldest dich dort an.
Der aktive Modus steht im Endpunkt
[`GET /auth/mode`](/docs/reference/endpoints/auth#getAuthMode).
> Die Login-Seite erreichst du direkt unter `/login`. Nach erfolgreicher
> Anmeldung wirst du zur ursprünglich aufgerufenen Seite zurückgeleitet.
## Benutzerprofil
Dein Profil (Avatar, Name, E-Mail, Tarif) siehst du unten links im
Benutzermenü. Dort stehen dir folgende Aktionen zur Verfügung:
- **Watchlist** — deine gespeicherten Tools (nur mit dem entsprechenden Tarif).
- **Papierkorb** — wiederherstellbare, gelöschte Tools (Premium/Enterprise).
- **Passwort ändern** — für lokale Konten direkt in toolr; für OIDC-Konten wird
die Passwortverwaltung im Identitätsanbieter angeboten.
- **Abmelden** — beendet deine Sitzung.
## Passwort ändern (lokales Konto)
1. Öffne das Benutzermenü unten links.
2. Wähle **Passwort ändern**.
3. Gib das **aktuelle** sowie ein **neues** Passwort ein (mind. 6 Zeichen) und
bestätige es.
4. Speichern — das Passwort wird sofort übernommen.
API-Referenz: [`POST /auth/me/password`](/docs/reference/endpoints/auth#changeMyPassword).
## Anzeigeeinstellungen
Über die Schaltflächen oben rechts kannst du:
- **Sprache** wechseln (Deutsch / Englisch),
- **Theme** umschalten (Hell / Dunkel / System),
- die **Listenansicht** und **Dichte** im Bereich Tools durchsuchen anpassen
(siehe [Tools finden & durchsuchen](/docs/handbook/tools-finden)).
Deine Präferenzen (inkl. Watchlist) werden im Endpunkt
[`GET /auth/me/preferences`](/docs/reference/endpoints/auth#getMePreferences)
gespeichert und über [`PUT /auth/me/preferences`](/docs/reference/endpoints/auth#updateMePreferences)
aktualisiert.
+35
View File
@@ -0,0 +1,35 @@
# Kosten erfassen
Auf der Detailseite eines Tools kannst du Kosten- und Lizenzmodelle eintragen,
damit die Gesamtkosten je Tool transparent werden.
> Kosten ist ein **Premium-Feature** (`costs`, Premium/Enterprise). Admins
> haben immer Zugriff.
## Kosten hinzufügen
Klicke auf **Kosten hinzufügen** im Kosten-Bereich der Detailseite und fülle
das Formular aus:
| Feld | Hinweise |
| --- | --- |
| **Lizenztyp** | Free / Subscription / One-Time / Usage-Based |
| **Abrechnungszeitraum** | Nur für „Subscription": Monatlich / Quartalsweise / Jährlich |
| **Kosten** | Betrag als Zahl |
| **Währung** | EUR / USD / GBP / CHF |
| **Notizen** | Optionaler Freitext |
Speichern legt den Eintrag an. Jeder Kosten-Eintrag wird als Karte mit
Lizenz-Badge, Abrechnungszeitraum, Betrag (`Betrag Währung` bzw. „Free") und
Notizen angezeigt.
## Kosten bearbeiten & löschen
Beim Überfahren einer Kosten-Karte erscheinen die Aktionen **Bearbeiten**
(Bleistift) und **Löschen** (Papierkorb).
## API
Die Kosten-Daten werden über die Tool-Endpunkte verwaltet
(siehe [API-Referenz](/docs/reference/endpoints/tools)).
@@ -0,0 +1,41 @@
# Papierkorb
Der **Papierkorb** (`/trash`) enthält soft gelöschte Tools. Mit Papierkorb-Zugang
können sie wiederhergestellt werden; endgültiges Löschen ist Admins vorbehalten.
> Der Papierkorb ist ein **Premium-Feature** (`trash`, Premium/Enterprise).
> Admins haben immer Zugriff.
## Zugang
Der Papierkorb ist über das Benutzermenü oder die Seitenleiste erreichbar.
Ohne `trash`-Berechtigung erscheint ein Hinweis auf den Tarifwechsel.
## Wiederherstellen
- Markiere ein oder mehrere Tools (Checkboxen).
- Klicke auf **Wiederherstellen (N)** — die Tools erscheinen wieder in allen
öffentlichen Ansichten.
> Wiederherstellen steht jeder Person mit Papierkorb-Zugang zur Verfügung.
## Endgültig löschen (nur Admin)
- **Löschen (N)** entfernt die ausgewählten Tools **endgültig** — inklusive
aller Bewertungen, Kosten und Verknüpfungen. Das kann nicht rückgängig
gemacht werden.
- **Papierkorb leeren** entfernt alle soft gelöschten Tools endgültig.
## Tabelle
Der Papierkorb listet: Name, Kategorie, **Gelöscht am** (`tt.MM.jjjj HH:mm`),
**Gelöscht von** sowie Aktionen (Wiederherstellen; Löschen nur Admin). Die Suche
filtert nach Namen.
## API
- [`GET /tools/trash`](/docs/reference/endpoints/tools#listTrashedTools) — Liste
- [`POST /tools/trash/restore`](/docs/reference/endpoints/tools#restoreTools) — Wiederherstellen
- [`DELETE /tools/trash`](/docs/reference/endpoints/tools#deleteTrashedTools) — Endgültig löschen (Admin)
- [`POST /tools/trash/empty`](/docs/reference/endpoints/tools#emptyTrash) — Papierkorb leeren (Admin)
+41
View File
@@ -0,0 +1,41 @@
# Pläne & Berechtigungen
toolr unterscheidet **Tarife** (Tier) und **Rollen**. Admins umgehen alle
Feature-Beschränkungen.
## Tarife
| Tarif | Beschreibung |
| --- | --- |
| **Free** | Grundfunktionen: suchen, filtern, ansehen, Analytics |
| **Premium** | Zusätzlich Watchlist, Vergleichen, Papierkorb, Kosten |
| **Enterprise** | Alle Premium-Features + erweiterter Support |
### Feature-Berechtigungen
Premium/Enterprise schalten folgende Features frei:
| Feature | Funktion | Mehr erfahren |
| --- | --- | --- |
| `compare` | Tools vergleichen | [Vergleichen](/docs/handbook/vergleichen) |
| `watchlist` | Favoritenliste | [Watchlist](/docs/handbook/watchlist) |
| `trash` | Papierkorb (soft gelöschte Tools) | [Papierkorb](/docs/handbook/papierkorb) |
| `costs` | Kosten-/Lizenzmodelle erfassen | [Kosten erfassen](/docs/handbook/kosten) |
Fehlt dir ein Feature, zeigt die App einen **Upgrade-Hinweis** mit Link zur
Tarifverwaltung.
## Rollen
| Rolle | Berechtigungen |
| --- | --- |
| **User** | Standard-Konto: Tools anlegen/bewerten, eigene Tools bearbeiten |
| **Admin** | Alle User-Rechte + Verwaltung, Audit-Log, Redundanz, Papierkorb leeren, Tool-Verknüpfungen |
Admins passieren **alle** Feature-Checks — auch ohne Premium-Tarif.
## Tarif-/Rollenverwaltung
Die Zuordnung von Rolle und Tarif wird durch Admins im Bereich
[Administration](/docs/handbook/administration) (Tab „Nutzer") verwaltet.
@@ -0,0 +1,38 @@
# Redundanz-Dashboard
Das **Redundanz-Dashboard** (`/admin/redundancy`) ist ein Admin-Werkzeug zur
automatischen Erkennung doppelter oder stark überlappender Tools — jeweils
pro Kategorie — inklusive Kosten- und Bewertungsvergleich.
> Der Zugriff ist ausschließlich Admins vorbehalten (die API ist
> admin-geschützt).
## Aufbau
- **Pro Kategorie** wird eine Gruppe angezeigt: Name der Kategorie,
Anzahl Tools und Vergleiche sowie ggf. die **gesamten monatlichen Kosten**
(z. B. `€X.XX/mo gesamt`).
- Jedes Tool wird als Karte dargestellt: Name, monatliche Kosten, Anzahl der
Bewertungen, kombinierte Bewertung, Lizenz-Badges und Feature-Anzahl.
## Vergleiche & Empfehlungen
Für jedes Tool-Paar erscheint:
- Tool A vs. Tool B, jeweils mit Bewertung (`X.X ★`) und monatlichen Kosten.
- **Überlappung** in Prozent (Fortschrittsbalken in der Mitte).
- Eine **Empfehlung** mit Konfidenz-Farbe:
- **hoch** (grün), **mittel** (gelb), **niedrig** (grau)
- Das empfohlene, bessere Tool wird mit „Daumen hoch" markiert und begründet.
## Manuelle Bewertung
Du kannst ein Paar manuell bewerten: Klicke auf Tool A oder Tool B, um
festzuhalten, welches besser ist. Die Auswahl wird gespeichert und die
Darstellung aktualisiert.
## API
- [`GET /api/admin/redundancy`](#) — Daten laden (admin-geschützt)
- [`POST /api/admin/redundancy/evaluate`](#) — manuelle Bewertung speichern
+36
View File
@@ -0,0 +1,36 @@
# Tastenkürzel & Kommandopalette
## Kommandopalette
Die Kommandopalette ist die zentrale Schnellnavigation:
- Öffnen mit **`⌘K`** (macOS) bzw. **`Ctrl+K`** (Windows/Linux).
- Alternativ über die Suchleiste oben rechts („Tools suchen… ⌘K") oder das
Such-Icon auf Mobilgeräten.
### Leerer Zustand
Ohne Eingabe zeigt die Palette:
- **Zuletzt angesehen** — die letzten 5 Tools, die du besucht hast.
- **Navigation** — Tools durchsuchen, Tool hinzufügen, Analytics sowie
(abhängig von Berechtigungen) Watchlist, Papierkorb und Admin.
### Suche
Tippe, um live nach Tools zu suchen (max. 10 Ergebnisse, inkl. Bewertung
`X.X★`).
## Tastenkürzel im Überblick
| Kürzel | Aktion |
| --- | --- |
| `⌘K` / `Ctrl+K` | Kommandopalette öffnen |
| `/` | Suche im Bereich „Tools durchsuchen" fokussieren |
## Weitere Hinweise
- **Zuletzt angesehen** wird lokal im Browser gespeichert (max. 5 Einträge).
- Die Seitenleiste (linke Navigation) ist auf Desktop einklappbar; der
Breadcrumb oben zeigt deinen aktuellen Ort.
@@ -0,0 +1,46 @@
# Tool anlegen
Um ein neues Tool zum Katalog hinzuzufügen, klicke auf **Tool hinzufügen**
(`/tools/new`). Das Anlegen erfordert ein Konto — ohne Anmeldung erscheint ein
Hinweis mit Login-Button.
## Formularfelder
| Feld | Pflicht | Hinweise |
| --- | --- | --- |
| **Name** | Ja | Mind. 2 Zeichen |
| **Kategorie** | Ja | Auswahlliste; neue Kategorien lassen sich direkt anlegen |
| **Website URL** | Nein | Gültige URL (z. B. `https://...`) |
| **Icon / Logo URL** | Nein | Gültige URL; Vorschau wird live angezeigt |
| **Beschreibung** | Ja | Mind. 10 Zeichen; beschreibe, was das Tool tut |
| **Features** | Nein | Dynamische Liste mit Autovervollständigung (max. 6) |
| **Tags** | Nein | Dynamische Liste mit Autovervollständigung |
Neben jedem Feld führt das **?Icon** direkt zur zugehörigen Feldbeschreibung
in der [Datenmodell-Referenz](/docs/reference/schemas/toolinput).
### Kategorie
- Tippe, um nach bestehenden Kategorien zu suchen.
- Wähle **+ Erstelle „..."**, um eine neue Kategorie anzulegen.
### Features & Tags
- **Feature hinzufügen** / **Tag hinzufügen** hängt eine neue Zeile an.
- Die Eingabefelder schlagen bestehende Features/Tags vor
(Autovervollständigung, max. 6 Vorschläge).
- Mit dem **×**Button entfernst du einzelne Zeilen.
- Features und Tags helfen beim Filtern und Wiederfinden.
## Speichern
Klicke auf **Tool hinzufügen**. Nach erfolgreicher Anlage wirst du auf die
Detailseite des neuen Tools weitergeleitet.
## API
- [`POST /tools`](/docs/reference/endpoints/tools#createTool) — Tool anlegen
- [`GET /categories`](/docs/reference/endpoints/tools#listCategories) — Kategorien
- [`GET /features/all`](/docs/reference/endpoints/tools#listAllFeatures) — Features
- [`GET /tags/all`](/docs/reference/endpoints/tools#listAllTags) — Tags
@@ -0,0 +1,33 @@
# Tool bearbeiten & löschen
## Bearbeiten
Auf der Detailseite eines Tools findest du die Schaltfläche **Bearbeiten**
(nur für die Person, die das Tool angelegt hat, sowie für Admins).
Die Bearbeitungsseite (`/tools/:id/edit`) enthält dieselben Felder wie beim
Anlegen (Name, Kategorie, Website/Icon-URL, Beschreibung, Features, Tags) —
bereits mit den aktuellen Werten befüllt.
- **Speichern** übernimmt die Änderungen.
- **Abbrechen** führt zurück zur Detailseite.
API-Referenz: [`PATCH /tools/{id}`](/docs/reference/endpoints/tools#updateTool).
## Löschen
Über **Löschen** auf der Detailseite wird das Tool entfernt. Das Verhalten
hängt von deinem Tarif ab:
- **Mit Papierkorb-Zugang** (Premium/Enterprise oder Admin): Das Tool wird
**soft gelöscht** — es verschwindet aus allen öffentlichen Ansichten, kann
aber im [Papierkorb](/docs/handbook/papierkorb) wiederhergestellt oder
endgültig gelöscht werden.
- **Ohne Papierkorb-Zugang:** Das Tool wird **endgültig** gelöscht und kann
nicht wiederhergestellt werden.
Die Löschung ist nur für die Person, die das Tool angelegt hat, sowie für
Admins möglich.
API-Referenz: [`DELETE /tools/{id}`](/docs/reference/endpoints/tools#deleteTool).
@@ -0,0 +1,67 @@
# Tools finden & durchsuchen
Der Bereich **Tools durchsuchen** (`/tools`) ist der Einstieg in den Katalog.
Hier kombinierst du Suche, Filter und Sortierung, um genau die Tools zu finden,
die dich interessieren.
## Suche
- Die **Suchleiste** durchsucht Name und Beschreibung (Volltext).
- Tastenkürzel: Drücke **`/`**, um die Suche zu fokussieren.
- Die Eingabe ist deaktiviert (Debounce), damit bei jedem Tastendruck sofort
nachgefiltert wird.
## Filtern
Über die Schaltfläche **Filter** (mit Badge für die Anzahl aktiver Filter)
öffnest du den Filter-Popover mit:
- **Tags** — Auswahl über Checkboxen (scrollbare Liste).
- **Features** — Auswahl über Checkboxen.
- **Mindestbewertung** — Schieberegler von 0 bis 5 (Schritte von 0,5); zeigt
z. B. „3.0+" an.
Aktive Filter erscheinen als **entfernbare Chips** über der Ergebnisliste.
Mit **Filter zurücksetzen** bzw. **Alle entfernen** räumst du sie wieder auf.
## Sortieren
Über das Dropdown **Sortieren** stehen folgende Optionen zur Verfügung:
| Sortierung | Beschreibung |
| --- | --- |
| Neueste | Neue Tools zuerst |
| Top bewertet | Nach kombinierter Bewertung |
| Meistbewertet | Nach Anzahl der Bewertungen |
| Name (AZ) | Alphabetisch aufsteigend |
| Name (ZA) | Alphabetisch absteigend |
| Zuletzt aktualisiert | Nach letztem Update |
## Ansicht & Dichte
- **Ansicht wechseln:** Raster / Tabelle / Zeilen.
- **Dichte:** gemütlich / kompakt (Schieberegler).
Deine Auswahl wird gespeichert — lokal im Browser und für angemeldete Nutzer:innen
zusätzlich serverseitig in den Präferenzen. Ansicht, Dichte, Suche, Filter und
Sortierung werden dabei in die URL übernommen, sodass du Ergebnisse teilen
kannst.
## Tabellenansicht
In der Tabellenansicht sind die Spalten **Tool**, **Bewertung** und **Anzahl
Bewertungen** sortierbar. Beim Überfahren einer Zeile erscheint eine Vorschau
mit Bewertungsdetails, Tags und Mini-Balken.
## Auswählen für Vergleich & Watchlist
- Auf jeder Karte/Zeile findest du ein **Vergleichs-Icon**, mit dem du Tools zur
[Vergleichsleiste](/docs/handbook/vergleichen) hinzufügst.
- Das **Lesezeichen-Icon** speichert Tools in deiner
[Watchlist](/docs/handbook/watchlist) (nur mit dem entsprechenden Tarif).
## API
Alle Such-, Filter- und Sortierparameter entsprechen den Query-Parametern von
[`GET /tools`](/docs/reference/endpoints/tools#listTools).
@@ -0,0 +1,42 @@
# Vergleichen
Mit der Vergleichsfunktion stellst du mehrere Tools **nebeneinander** gegenüber —
ideal, um eine fundierte Entscheidung zu treffen.
> Vergleichen ist ein **Premium-Feature** (Premium/Enterprise) und steht Admins
> immer zur Verfügung.
## Tools auswählen
1. Im Bereich **Tools durchsuchen** klickst du auf jeder Karte/Zeile auf das
**Vergleichs-Icon** (Waage).
2. Unten erscheint die **Vergleichsleiste** mit den ausgewählten Tools als
Chips. Du kannst einzelne Tools entfernen (×) oder die Auswahl leeren.
3. Klicke auf **Vergleichen (N)**, um zur Vergleichsansicht zu gelangen.
> Ohne Premium-Tarif ist der Button gesperrt (Schloss-Icon). Über den
> Dialog gelangst du zum Tarifwechsel
> (siehe [Pläne & Berechtigungen](/docs/handbook/plaene)).
## Die Vergleichsansicht
Die Ansicht zeigt eine Tabelle mit einer Spalte pro Tool. Zeilen:
| Zeile | Inhalt |
| --- | --- |
| **Bewertung** | Sterne + Wert (z. B. `4.2/5`) |
| **Nützlichkeit** | Wert (X.X/5) |
| **Bedienbarkeit** | Wert (X.X/5) |
| **Anzahl Bewertungen** | Anzahl |
| **Beschreibung** | Text |
| **Features** | Badges |
| **Tags** | Badges |
| **Zuletzt aktualisiert** | Datum |
Der **beste Wert** pro Zeile wird hervorgehoben (mit Trophäen-Icon).
## API
Die Vergleichsansicht liest die Daten über
[`GET /compare`](/docs/reference/endpoints/tools#listCompareTools).
@@ -0,0 +1,34 @@
# Watchlist
Die **Watchlist** ist eine persönliche Favoritenliste. Tools darin kannst du
jederzeit per Klick wieder aufrufen und vergleichen.
> Die Watchlist ist ein **Premium-Feature** (Premium/Enterprise) und steht
> Admins immer zur Verfügung.
## Voraussetzung
Du benötigst einen Tarif mit `watchlist`-Berechtigung. Fehlt diese, erscheint
beim Lesezeichen ein Hinweis auf den Tarifwechsel
(siehe [Pläne & Berechtigungen](/docs/handbook/plaene)).
## Tool speichern
- Auf jeder Karte/Zeile im Bereich **Tools durchsuchen** findest du das
**Lesezeichen-Icon**.
- Ein Klick speichert das Tool in deiner Watchlist — das Icon wird gefüllt.
- Ein erneuter Klick entfernt es wieder.
## Watchlist ansehen
Öffne die Watchlist über das Benutzermenü oder die Seitenleiste. Sie zeigt alle
gespeicherten Tools als Karten. Das gefüllte Lesezeichen auf einer Karte
entfernt das Tool aus der Liste.
## Wo wird die Watchlist gespeichert?
Die Watchlist ist eine Liste von Tool-IDs in deinen **Benutzerpräferenzen**.
Damit ist sie geräteübergreifend mit deinem Konto verbunden.
API-Referenz: [`GET /auth/me/watchlist`](/docs/reference/endpoints/auth#getMeWatchlist).
File diff suppressed because it is too large Load Diff
+53 -9
View File
@@ -196,7 +196,7 @@ function slugify(name) {
return name.replace(/\.md$/, "").toLowerCase().replace(/[^a-z0-9-]+/g, "-");
}
async function buildHandbookIndex() {
async function readHandbookPages() {
let files;
try {
files = (await readdir(handbookDir)).filter(isHandbookFile);
@@ -213,13 +213,35 @@ async function buildHandbookIndex() {
file,
title: frontmatter.title ?? extractTitle(body) ?? basename(file),
order: typeof frontmatter.order === "number" ? frontmatter.order : 999,
body,
});
await writeFile(join(targetDir, "handbook", file), body);
}
pages.sort((a, b) => a.order - b.order || a.title.localeCompare(b.title));
return pages;
}
async function writeHandbookTo(dir) {
const pages = await readHandbookPages();
await mkdir(dir, { recursive: true });
for (const page of pages) {
await writeFile(join(dir, page.file), page.body);
}
await writeFile(
join(dir, "index.json"),
JSON.stringify(
pages.map(({ slug, file, title, order }) => ({ slug, file, title, order })),
null,
2,
),
);
return pages;
}
async function buildHandbookIndex() {
const pages = await writeHandbookTo(join(targetDir, "handbook"));
return pages;
}
// ---------------------------------------------------------------------------
// Search index
// ---------------------------------------------------------------------------
@@ -295,7 +317,8 @@ async function writeSnapshot(version) {
const dir = join(releasesDir, version);
await mkdir(dir, { recursive: true });
await writeFile(join(dir, "reference.json"), JSON.stringify(reference, null, 2));
console.log(`[generate-docs] snapshot ${version} -> ${join(dir, "reference.json")}`);
await writeHandbookTo(join(dir, "handbook"));
console.log(`[generate-docs] snapshot ${version} -> ${dir}/ (reference.json + handbook)`);
}
// ---------------------------------------------------------------------------
@@ -343,27 +366,48 @@ async function main() {
JSON.stringify(handbookPages, null, 2),
);
// 3. Release notes + versioned reference snapshots
// 3. Release notes + versioned docs snapshots (last 7 versions)
const versions = [];
for (const name of releaseNames) {
for (const name of releaseNames.slice(0, 7)) {
const version = parseVersion(name);
const content = await readFile(join(releasesDir, name), "utf8");
await copyFile(join(releasesDir, name), join(targetDir, "releases", name));
const hasSnapshot = await stat(join(releasesDir, version, "reference.json"))
const snapDir = join(releasesDir, version);
const hasReference = await stat(join(snapDir, "reference.json"))
.then(() => true)
.catch(() => false);
if (hasSnapshot) {
const hasHandbook = await stat(join(snapDir, "handbook", "index.json"))
.then(() => true)
.catch(() => false);
if (hasReference) {
await copyFile(
join(releasesDir, version, "reference.json"),
join(snapDir, "reference.json"),
join(targetDir, "versions", `${version}.json`),
);
}
if (hasHandbook) {
await mkdir(join(targetDir, "versions", version, "handbook"), { recursive: true });
await copyFile(
join(snapDir, "handbook", "index.json"),
join(targetDir, "versions", version, "handbook", "index.json"),
);
const pages = JSON.parse(
await readFile(join(snapDir, "handbook", "index.json"), "utf8"),
);
for (const page of pages) {
await copyFile(
join(snapDir, "handbook", page.file),
join(targetDir, "versions", version, "handbook", page.file),
);
}
}
versions.push({
version,
file: `releases/${name}`,
title: extractTitle(content) ?? version,
date: extractDate(content) ?? null,
hasReference: hasSnapshot,
hasReference,
hasHandbook,
});
}