diff --git a/docs/API.md b/docs/API.md
index 4297673..2e3ff6e 100644
--- a/docs/API.md
+++ b/docs/API.md
@@ -145,15 +145,28 @@ Liefert `totals`, `monthly`, `providers`, `genres` und `yearReview` auf einmal.
### Universen
```http
-GET /api/v1/universen
-POST /api/v1/universen
-GET /api/v1/universen/{id}?reihenfolge={orderId}
-POST /api/v1/universen/{id}
+GET /api/v1/universen
+POST /api/v1/universen
+GET /api/v1/universen/{id}?reihenfolge={orderId}
+POST /api/v1/universen/{id}
+PATCH /api/v1/universen/{id}
```
`GET /api/v1/universen/{id}` gibt die Einträge in der gewählten Reihenfolge
zurück, dazu `progress` und `nextUp`. Ohne `reihenfolge` gilt die
-Erscheinungsreihenfolge.
+Standardreihenfolge des Universums — in `orders` trägt sie `isDefault`.
+
+`PATCH` legt fest, welche das ist. Die Reihenfolge muss zu diesem Universum
+gehören, und es braucht Schreibrecht:
+
+```bash
+curl -X PATCH -H "Authorization: Bearer $KEY" -H "content-type: application/json" \
+ -d '{"defaultOrderId": "…"}' \
+ https://flimmer.example.com/api/v1/universen/$ID
+```
+
+Je Universum trägt immer genau eine Reihenfolge den Standard. Wird die
+Standardreihenfolge gelöscht, übernimmt die Erscheinungsreihenfolge.
### Export
diff --git a/src/app/actions/universes.ts b/src/app/actions/universes.ts
index 14e5613..5c9a18d 100644
--- a/src/app/actions/universes.ts
+++ b/src/app/actions/universes.ts
@@ -12,6 +12,7 @@ import {
removeTitle,
renameOrder,
renameUniverse,
+ setDefaultOrder,
setOrderPositions,
shareUniverse,
trashUniverse,
@@ -124,6 +125,13 @@ export async function deleteOrderAction(orderId: string) {
});
}
+export async function setDefaultOrderAction(orderId: string) {
+ return run(async (userId) => {
+ await setDefaultOrder(userId, id.parse(orderId));
+ return { message: "Standardreihenfolge gesetzt" };
+ });
+}
+
export async function reorderAction(orderId: string, itemIds: string[]) {
return run(async (userId) => {
await setOrderPositions(userId, id.parse(orderId), z.array(id).max(1000).parse(itemIds));
diff --git a/src/app/api/v1/openapi.json/route.ts b/src/app/api/v1/openapi.json/route.ts
index 9d61d71..39758e2 100644
--- a/src/app/api/v1/openapi.json/route.ts
+++ b/src/app/api/v1/openapi.json/route.ts
@@ -287,6 +287,9 @@ export function GET() {
parameters: [{ name: "id", in: "path", required: true, schema: { type: "string" } }],
get: {
summary: "Universum mit Reihenfolge und Fortschritt",
+ description:
+ "Ohne 'reihenfolge' gilt die Standardreihenfolge des Universums — sie trägt in " +
+ "'orders' das Kennzeichen 'isDefault'.",
parameters: [{ name: "reihenfolge", in: "query", schema: { type: "string" } }],
responses: { "200": { description: "Universum" }, "404": { description: "Unbekannt" } },
},
@@ -306,6 +309,33 @@ export function GET() {
},
responses: { "200": { description: "Aufgenommen" } },
},
+ patch: {
+ summary: "Standardreihenfolge festlegen",
+ description:
+ "Bestimmt, welche Reihenfolge beim Öffnen erscheint. Braucht Schreibrecht; je " +
+ "Universum trägt immer genau eine Reihenfolge den Standard.",
+ requestBody: {
+ required: true,
+ content: {
+ "application/json": {
+ schema: {
+ type: "object",
+ properties: {
+ defaultOrderId: {
+ type: "string",
+ description: "Muss eine Reihenfolge dieses Universums sein.",
+ },
+ },
+ required: ["defaultOrderId"],
+ },
+ },
+ },
+ },
+ responses: {
+ "200": { description: "Gesetzt" },
+ "404": { description: "Die Reihenfolge gehört nicht zu diesem Universum" },
+ },
+ },
},
"/export": {
get: {
diff --git a/src/app/api/v1/universen/[id]/route.ts b/src/app/api/v1/universen/[id]/route.ts
index f670157..d39580d 100644
--- a/src/app/api/v1/universen/[id]/route.ts
+++ b/src/app/api/v1/universen/[id]/route.ts
@@ -1,6 +1,7 @@
import { z } from "zod";
import { apiError, readJson, withApi } from "@/lib/api";
-import { addTitle, getUniverse } from "@/lib/universes";
+import { prisma } from "@/lib/db";
+import { addTitle, getUniverse, setDefaultOrder } from "@/lib/universes";
/** GET /api/v1/universen/{id}?reihenfolge=… — Inhalt und Fortschritt. */
export const GET = withApi(async (request, user, context) => {
@@ -25,3 +26,25 @@ export const POST = withApi(async (request, user, context) => {
await addTitle(user.id, id, body.titleId);
return { ok: true };
});
+
+const patchSchema = z.object({ defaultOrderId: z.string().min(1) });
+
+/** PATCH /api/v1/universen/{id} — festlegen, welche Reihenfolge beim Öffnen erscheint. */
+export const PATCH = withApi(async (request, user, context) => {
+ const { id } = await context.params;
+ if (!id) return apiError("Es fehlt die Kennung des Universums.", 400);
+
+ const body = await readJson(request, patchSchema);
+
+ // Die Reihenfolge muss zu genau diesem Universum gehören. Ohne diese Prüfung
+ // setzte ein PATCH auf Universum A den Standard in Universum B — die
+ // Domänenschicht leitet das Universum ja aus der Reihenfolge ab.
+ const order = await prisma.universeOrder.findFirst({
+ where: { id: body.defaultOrderId, universeId: id },
+ select: { id: true },
+ });
+ if (!order) return apiError("Diese Reihenfolge gehört nicht zu diesem Universum.", 404);
+
+ await setDefaultOrder(user.id, order.id);
+ return { ok: true };
+});
diff --git a/src/components/universes/UniverseTools.tsx b/src/components/universes/UniverseTools.tsx
index 2438537..a711c97 100644
--- a/src/components/universes/UniverseTools.tsx
+++ b/src/components/universes/UniverseTools.tsx
@@ -9,6 +9,7 @@ import {
createOrderAction,
createUniverseAction,
deleteOrderAction,
+ setDefaultOrderAction,
shareUniverseAction,
trashUniverseAction,
unshareUniverseAction,
@@ -109,6 +110,24 @@ export function OrderTabs({
style={isActive ? { backgroundImage: "var(--fl-gradient)" } : undefined}
>
{order.name}
+ {order.isDefault && (
+ <>
+ {/* Häkchen an der Reihenfolge, die beim Öffnen erscheint. Das
+ Wort dahinter steht nur für Screenreader — sichtbar würde
+ es die Reiter auseinanderziehen. */}
+
+ (Standard)
+ >
+ )}
);
})}
@@ -158,6 +177,21 @@ export function OrderTabs({
)}
+ {active && !active.isDefault && (
+
+ )}
+
{active && active.kind === "CUSTOM" && (