Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,8 @@ Create a dev config at `booklore-api/src/main/resources/application-dev.yml`:
app:
path-book: '/path/to/booklore-data/books'
path-config: '/path/to/booklore-data/config'
api-docs:
enabled: true

spring:
datasource:
Expand Down Expand Up @@ -211,6 +213,14 @@ The UI will be available at http://localhost:4200 with hot-reload enabled.

---

## API Reference Docs

When enabled, API documentation is available as both an `openapi.json` and as publicly accessible docs. The endpoints are:
- Scalar UI is available at `http://localhost:6060/api/docs`
- OpenAPI JSON is available at `http://localhost:6060/api/openapi.json`

---

## Running Tests

Always run tests before submitting a pull request.
Expand Down
12 changes: 12 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,9 @@ DATABASE_URL=jdbc:mariadb://mariadb:3306/grimmory
DB_USER=grimmory
DB_PASSWORD=ChangeMe_Grimmory_2025!

# Optional: enable API docs + export OpenAPI JSON (defaults to false)
API_DOCS_ENABLED=false

# Storage: LOCAL (default) or NETWORK (disables file operations; see Network Storage section)
DISK_TYPE=LOCAL

Expand Down Expand Up @@ -117,6 +120,7 @@ services:
- DATABASE_URL=${DATABASE_URL}
- DATABASE_USERNAME=${DB_USER}
- DATABASE_PASSWORD=${DB_PASSWORD}
- API_DOCS_ENABLED=${API_DOCS_ENABLED}
depends_on:
mariadb:
condition: service_healthy
Expand Down Expand Up @@ -194,6 +198,14 @@ just ui dev # Start the frontend dev server

---

## API Reference Docs

When enabled, API reference documentation is available as both an `openapi.json` and as publicly accessible docs. The endpoints are:
- API reference docs are available at `http://localhost:6060/api/docs`
- OpenAPI JSON is available at `http://localhost:6060/api/openapi.json`

---

## BookDrop

Drop book files into a watched folder. Grimmory picks them up, pulls metadata, and queues them for your review.
Expand Down
9 changes: 9 additions & 0 deletions booklore-api/CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,15 @@ just api run
just api check
```

## API Docs (`API_DOCS_ENABLED`)

- `application.yaml` binds `app.api-docs.enabled` to `API_DOCS_ENABLED` (default `false`).
- `application.yaml` binds `springdoc.api-docs.enabled` to `app.api-docs.enabled`.
- `application-dev.yml` enables docs for local dev profile runs by default.
- For runtime/container profiles, set `API_DOCS_ENABLED=true` to expose:
- `/api/openapi.json`
- `/api/docs`

## Backend Conventions

- Use Spring Data JPA repository methods or JPQL. Do not introduce native queries unless a maintainer has explicitly approved them.
Expand Down
2 changes: 1 addition & 1 deletion booklore-api/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ dependencies {
annotationProcessor("org.mapstruct:mapstruct-processor:1.6.3")

// --- API Documentation ---
implementation("org.springdoc:springdoc-openapi-starter-webmvc-ui:3.0.2")
implementation("org.springdoc:springdoc-openapi-starter-webmvc-api:3.0.2")
implementation("org.apache.commons:commons-compress:1.28.0")
implementation("org.tukaani:xz:1.12") // Required by commons-compress for 7z support
implementation("org.apache.commons:commons-text:1.15.0")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,8 @@ public class SecurityConfig {
private static final String[] COMMON_PUBLIC_ENDPOINTS = {
"/ws/**", // WebSocket connections (auth handled in WebSocketAuthInterceptor)
"/kobo/**", // Kobo API requests (auth handled in KoboAuthFilter)
"/api/docs", // API documentation UI
"/api/openapi.json", // OpenAPI spec (used by API documentation UI)
"/api/v1/auth/**", // Login and token refresh endpoints (must remain public)
"/api/v1/public-settings", // Public endpoint for checking OIDC or other app settings
"/api/v1/setup/**", // Setup wizard endpoints (must remain accessible before initial setup)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package org.booklore.controller;

import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;

@Controller
@ConditionalOnProperty(name = "app.api-docs.enabled", havingValue = "true", matchIfMissing = false)
public class ScalarController {

@GetMapping("/api/docs")
public String scalar() {
return "forward:/scalar.html";
}
}
7 changes: 4 additions & 3 deletions booklore-api/src/main/resources/application.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ app:
path-config: '/app/data'
bookdrop-folder: '/bookdrop'
version: ${APP_VERSION:development}
api-docs:
enabled: ${API_DOCS_ENABLED:false}

cors:
# Comma-separated list of allowed CORS origins.
Expand Down Expand Up @@ -93,9 +95,8 @@ spring:

springdoc:
api-docs:
enabled: false
swagger-ui:
enabled: false
enabled: ${app.api-docs.enabled:false}
path: /api/openapi.json

logging:
level:
Expand Down
19 changes: 19 additions & 0 deletions booklore-api/src/main/resources/static/scalar.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<!doctype html>
<html lang="en">
<head>
<title>Grimmory API Reference</title>
<meta charset="UTF-8" />
<meta
name="viewport"
content="width=device-width, initial-scale=1"
/>
</head>
<body>
<script
id="api-reference"
data-url="/api/openapi.json"
data-configuration='{"theme":"default","hideDownloadButton":false,"telemetry":false}'
></script>
<script src="https://cdn.jsdelivr.net/npm/@scalar/[email protected]/dist/browser/standalone.js"></script>
</body>
</html>
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package org.booklore.controller;

import org.junit.jupiter.api.Test;
import org.springframework.core.io.ClassPathResource;
import org.springframework.util.StreamUtils;

import java.io.IOException;
import java.nio.charset.StandardCharsets;

import static org.assertj.core.api.Assertions.assertThat;

class ScalarControllerTest {

private final ScalarController controller = new ScalarController();

@Test
void shouldForwardToStaticScalarPage() {
assertThat(controller.scalar()).isEqualTo("forward:/scalar.html");
}

@Test
void staticScalarPageShouldDisableTelemetryAndPointToApiDocs() throws IOException {
String html = StreamUtils.copyToString(
new ClassPathResource("static/scalar.html").getInputStream(),
StandardCharsets.UTF_8
);
assertThat(html).contains("data-url=\"/api/openapi.json\"");
assertThat(html).contains("\"telemetry\":false");
}
}
Loading