Skip to content

Commit 634f01a

Browse files
Merge pull request #31 from OpenScience-Collective/docs/osa-public-feeds
docs(osa): document public FAQ and citations feeds
2 parents 855602e + f3c3151 commit 634f01a

3 files changed

Lines changed: 161 additions & 1 deletion

File tree

docs/osa/api-reference.md

Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -207,6 +207,126 @@ Ephemeral database mirror management. See [Database Mirrors](mirrors.md) for ful
207207
| `POST` | `/mirrors/{id}/sync` | Run sync pipeline |
208208
| `GET` | `/mirrors/{id}/download/{community}` | Download SQLite file |
209209

210+
## Public Data Feeds
211+
212+
Communities can expose two **read-only, unauthenticated** JSON feeds for building
213+
their own frontends (dashboards, widgets, citation badges). Both are **opt-in per
214+
community** via the `public_feeds` config block and return **404** when the feed is
215+
not enabled. Responses are cacheable (`Cache-Control: public, max-age=3600`).
216+
217+
Currently enabled: **EEGLAB** (FAQ + citations) and **BIDS** (citations).
218+
219+
### FAQ Feed
220+
221+
Synthesized question/answer entries generated from a community's mailing-list and
222+
forum archives.
223+
224+
```
225+
GET /{community}/faq
226+
```
227+
228+
No authentication required. Returns **404** if `public_feeds.faq` is not enabled.
229+
230+
Query parameters:
231+
232+
| Parameter | Type | Default | Description |
233+
|-----------|------|---------|-------------|
234+
| `q` | string || Full-text search phrase. Omit to browse all entries. |
235+
| `category` | string || Filter by category (`how-to`, `troubleshooting`, `reference`, `bug-report`, `feature-request`, `discussion`). |
236+
| `min_quality` | float | `0.0` | Minimum quality score (0.0–1.0). |
237+
| `limit` | int | `50` | Page size (1–200). |
238+
| `offset` | int | `0` | Pagination offset (ignored when `q` is set). |
239+
240+
Response:
241+
242+
```json
243+
{
244+
"community_id": "eeglab",
245+
"total": 1990,
246+
"limit": 50,
247+
"offset": 0,
248+
"entries": [
249+
{
250+
"question": "How do I run ICA in EEGLAB?",
251+
"answer": "Use runica from the Tools menu...",
252+
"tags": ["ica", "preprocessing"],
253+
"category": "how-to",
254+
"quality_score": 0.95,
255+
"message_count": 4,
256+
"first_message_date": "2020-03-11",
257+
"thread_url": "https://sccn.ucsd.edu/pipermail/eeglablist/..."
258+
}
259+
]
260+
}
261+
```
262+
263+
`total` is the count of entries matching the filters (before pagination). Email
264+
addresses are redacted from `question`, `answer`, and `tags`.
265+
266+
```bash
267+
# Browse the highest-quality how-to entries
268+
curl "https://api.osc.earth/osa/eeglab/faq?category=how-to&min_quality=0.8&limit=10"
269+
270+
# Search
271+
curl "https://api.osc.earth/osa/eeglab/faq?q=ICA%20components"
272+
```
273+
274+
### Citations Feed
275+
276+
Per-year citation counts for a community's canonical papers, suitable for a stacked
277+
"citations per year" chart. Counts come from OpenAlex (complete and uncapped); a
278+
paper's preprint and published versions are merged and deduplicated, and counts are
279+
floored at the paper's earliest publication year.
280+
281+
```
282+
GET /{community}/citations
283+
```
284+
285+
No authentication required. Returns **404** if `public_feeds.citations` is not
286+
enabled. Takes no query parameters.
287+
288+
Response:
289+
290+
```json
291+
{
292+
"community_id": "bids",
293+
"total": 3098,
294+
"per_year": { "2016": 22, "2017": 48, "...": 0, "2025": 502 },
295+
"by_paper": {
296+
"10.1038/sdata.2016.44": { "2016": 22, "2017": 48, "...": 0 },
297+
"10.1038/s41597-019-0104-8": { "2019": 12, "...": 0 }
298+
},
299+
"canonical_dois": ["10.1038/sdata.2016.44", "10.1038/s41597-019-0104-8"],
300+
"labels": {
301+
"10.1038/sdata.2016.44": "BIDS (Gorgolewski 2016)",
302+
"10.1038/s41597-019-0104-8": "EEG-BIDS (Pernet 2019)"
303+
}
304+
}
305+
```
306+
307+
| Field | Description |
308+
|-------|-------------|
309+
| `total` | Total citing works across all canonical papers. |
310+
| `per_year` | Citing-work count per publication year, summed across papers. |
311+
| `by_paper` | Stacked breakdown: canonical DOI → year → count. |
312+
| `canonical_dois` | The DOIs tracked for this community (config order). |
313+
| `labels` | Human-readable label per DOI for chart legends (when configured). |
314+
315+
```bash
316+
curl "https://api.osc.earth/osa/bids/citations"
317+
```
318+
319+
```python
320+
import httpx
321+
322+
data = httpx.get("https://api.osc.earth/osa/bids/citations").json()
323+
years = sorted(data["per_year"])
324+
for doi, by_year in data["by_paper"].items():
325+
label = data["labels"].get(doi, doi)
326+
series = [by_year.get(y, 0) for y in years]
327+
print(label, series)
328+
```
329+
210330
## Request Parameters
211331

212332
### Ask Request

docs/osa/registry/schema-reference.md

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ Complete reference for the community `config.yaml` file format.
2020
| `documentation` | list | No | `[]` | Documentation sources |
2121
| `github` | object | No | `null` | GitHub sync configuration |
2222
| `citations` | object | No | `null` | Paper/citation search config |
23+
| `public_feeds` | object | No | `null` | Opt-in public read-only JSON feeds (FAQ, citations) |
2324
| `docstrings` | object | No | `null` | Code docstring extraction config |
2425
| `mailman` | list | No | `[]` | Mailing list archive configs |
2526
| `faq_generation` | object | No | `null` | LLM-based FAQ generation config |
@@ -222,6 +223,9 @@ Paper search and citation tracking configuration for the knowledge database.
222223
|-------|------|----------|---------|-------------|
223224
| `queries` | list[string] | No | `[]` | Search queries for OpenALEX |
224225
| `dois` | list[string] | No | `[]` | Core paper DOIs to track (format: `10.xxxx/yyyy`) |
226+
| `live_search` | bool | No | `false` | Expose an on-demand live paper-search tool |
227+
| `paper_labels` | map[string, string] | No | `{}` | Human-readable label per DOI for the citations dashboard legend |
228+
| `aliases` | map[string, list[string]] | No | `{}` | Version DOIs (preprint, etc.) to merge into a primary DOI's citation count |
225229

226230
```yaml
227231
citations:
@@ -231,9 +235,44 @@ citations:
231235
dois:
232236
- "10.1016/j.neuroimage.2021.118766"
233237
- "10.1007/s12021-023-09628-4"
238+
# Labels shown in the public citations chart legend
239+
paper_labels:
240+
"10.1016/j.neuroimage.2021.118766": "HED-NeuroImage (2021)"
241+
# Merge a preprint into the published paper's citation count (deduplicated)
242+
aliases:
243+
"10.1016/j.neuroimage.2021.118766":
244+
- "10.1101/2021.01.01.000000"
234245
```
235246

236-
DOIs are validated against the `10.xxxx/yyyy` pattern. Common URL prefixes (`https://doi.org/`, `https://dx.doi.org/`) are automatically stripped.
247+
DOIs are validated against the `10.xxxx/yyyy` pattern. Common URL prefixes (`https://doi.org/`, `https://dx.doi.org/`) are automatically stripped. The same normalization and validation apply to `paper_labels` keys and `aliases` keys/values; every `aliases` primary key must also appear in `dois`.
248+
249+
**`aliases` — why:** OpenAlex keeps separate records for a paper's preprint and published versions and splits citations across them. Listing the version DOIs under `aliases` makes the citation sync query them together (OR-joined, deduplicated) and attribute the merged per-year counts to the primary DOI. Counts are floored at the earliest version's publication year, so no paper reports citations before it existed.
250+
251+
`paper_labels` and `aliases` feed the public [citations dashboard](#public_feeds) and the `GET /{community}/citations` endpoint.
252+
253+
## `public_feeds`
254+
255+
Opt-in flags that expose community data as **public, read-only JSON feeds** so
256+
communities can build their own frontends. Both are **off by default**.
257+
258+
| Field | Type | Required | Default | Description |
259+
|-------|------|----------|---------|-------------|
260+
| `faq` | bool | No | `false` | Expose generated FAQ entries at `GET /{community}/faq` |
261+
| `citations` | bool | No | `false` | Expose citation counts at `GET /{community}/citations` |
262+
263+
```yaml
264+
public_feeds:
265+
faq: true
266+
citations: true
267+
```
268+
269+
- `faq: true` requires a configured FAQ pipeline (`mailman` + `faq_generation`) with
270+
synced entries; otherwise the feed is empty.
271+
- `citations: true` requires `citations.dois`; counts populate on the next citation
272+
sync.
273+
274+
See the [API Reference](../api-reference.md#public-data-feeds) for the endpoint
275+
shapes, query parameters, and examples.
237276

238277
## `maintainers`
239278

docs/osa/status.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ The new dashboard includes:
1010

1111
- **Aggregate overview** with total requests, error rates, and community breakdown
1212
- **Per-community views** with usage charts and tool statistics
13+
- **Publication citations** chart (stacked by canonical paper, per year) for communities that expose the [citations feed](api-reference.md#citations-feed)
1314
- **Sync health status** for GitHub and papers knowledge sources
1415
- **Admin section** for token usage and cost metrics (requires API key)
1516

0 commit comments

Comments
 (0)