No description
Find a file
2026-09-21 08:07:09 -05:00
assets/css show unread saved items on the hearth 2026-09-06 12:02:12 -05:00
components Persist maintenance jobs and split utilities 2026-09-20 20:23:53 -05:00
composables Persist maintenance jobs and split utilities 2026-09-20 20:23:53 -05:00
layouts Update masonry layout 2026-08-10 20:56:31 -05:00
middleware Initial Commit 2026-08-09 20:41:16 -05:00
pages Save one message from collection recommendations 2026-09-20 21:23:55 -05:00
public Added favicon 2026-09-06 11:27:40 -05:00
server Reset recommended webpage content for extraction 2026-09-21 08:07:09 -05:00
tests Improve unsorted webpage extraction 2026-09-21 08:05:01 -05:00
types Sync evergreen reading progress 2026-09-20 18:20:10 -05:00
utils Fix conversation item counts 2026-09-20 00:21:57 -05:00
.dockerignore Initial Commit 2026-08-09 20:41:16 -05:00
.gitignore Initial Commit 2026-08-09 20:41:16 -05:00
.prettierignore Initial Commit 2026-08-09 20:41:16 -05:00
.prettierrc.json Initial Commit 2026-08-09 20:41:16 -05:00
AGENTS.md add agents.md instructing proactive title-only commits 2026-09-15 15:22:07 -05:00
app.config.ts Update style 2026-08-09 22:42:37 -05:00
app.vue Initial Commit 2026-08-09 20:41:16 -05:00
docker-entrypoint.sh Auto run migrations and document docker container env vars 2026-08-09 20:46:02 -05:00
Dockerfile Auto run migrations and document docker container env vars 2026-08-09 20:46:02 -05:00
drizzle.config.ts Initial Commit 2026-08-09 20:41:16 -05:00
nuxt.config.ts Route Gemma summaries through OpenWebUI 2026-09-18 21:18:54 -05:00
package-lock.json Improve unsorted webpage extraction 2026-09-21 08:05:01 -05:00
package.json Improve unsorted webpage extraction 2026-09-21 08:05:01 -05:00
README.md Reset recommended webpage content for extraction 2026-09-21 08:07:09 -05:00
tsconfig.json Initial Commit 2026-08-09 20:41:16 -05:00

Campfire Core

Campfire Core is a Nuxt 4 application and server API for a personal reading dashboard. It stores ingested items in PostgreSQL with pgvector, ranks them into a three-part dashboard, and uses local or hosted language models for embeddings and news-event processing.

Project outline

  • pages/ contains the dashboard, people, setup, recently-read, and collection views. Collections include unsorted items, promoted evergreen collections, and model-suggested clusters.
  • components/ contains the dashboard item, connection, modal, navigation, login, message, HTML-preview, and loading UI.
  • server/api/ contains the authenticated browser API, setup endpoints, and internal maintenance endpoints for embedding, interests, events, and news.
  • server/domain/ contains ranking, matching, affinity, interest, link, and news-evidence logic that is mostly covered by tests/.
  • server/utils/ contains database access, content extraction, embeddings, news jobs, collection ordering, identity handling, and reinforcement helpers.
  • server/db/ contains the Drizzle schema and checked-in PostgreSQL migrations.

The production container builds the Nuxt server, runs pending migrations at startup, and listens on port 3000.

Development

npm ci
npm run dev

The application expects PostgreSQL with the vector extension (for example, the pgvector/pgvector image). The default connection is postgres://n8n:changeme@postgres:5432/n8n; set NUXT_PG_CONNECTION_STRING for another database.

Runtime configuration

All settings are read from Nuxt runtime configuration. The important variables are:

Variable Purpose Default
NUXT_PG_CONNECTION_STRING PostgreSQL connection string postgres://n8n:changeme@postgres:5432/n8n
NUXT_OPENWEBUI_URL Ollama-compatible Open WebUI endpoint http://openwebui:8080
NUXT_OPENWEBUI_API_KEY Optional Open WebUI bearer token empty
NUXT_OPENROUTER_URL OpenRouter API endpoint https://openrouter.ai/api/v1
NUXT_OPENROUTER_API_KEY Optional hosted news-model token empty
NUXT_EMBED_MODEL Embedding model qwen3-embedding:0.6b
NUXT_EMBED_DIMENSIONS pgvector embedding dimensions 768
NUXT_EMBED_BATCH_SIZE Embeddings per request 32
NUXT_EMBED_MAX_CHARACTERS Maximum embedding chunk size 8000
NUXT_EMBED_NUM_CTX Ollama embedding context size 32768
NUXT_NEWS_MODEL News classification model typesafe/jev-1.13
NUXT_NEWS_SUMMARY_MODEL News summary model gemma4:e4b
NUXT_NEWS_BATCH_SIZE Items processed per news batch 20
NUXT_NEWS_MAX_CANDIDATES Candidate events per item 12
NUXT_NEWS_MAX_CHARACTERS News evidence text limit 6000
NUXT_NEWS_CONVERSATION_CONFIDENCE Conversation-event confidence threshold 0.9
NUXT_NEWS_MIN_MEMBERS Minimum event members 2
NUXT_SETUP_TOKEN Optional token protecting first-user setup empty
NUXT_N8N_ENGAGEMENT_WEBHOOK_URL Optional engagement/collection webhook empty

Embedding operations use Open WebUI. News classification can use OpenRouter when its API key is configured and otherwise uses the Open WebUI Ollama endpoint.

Run the checked-in migrations with:

npm run db:migrate

API and maintenance jobs

Browser-facing routes are under /api/v1: the dashboard feed (fire), collections and recommendations, item content and connections, people, unread state, recently-read items, evergreen saves, and engagement. /api/auth holds the setup and authentication checks. /api/v1/internal contains authenticated automation and maintenance endpoints and should not be exposed publicly.

The news endpoints are designed for scheduled n8n calls:

  • POST /api/v1/internal/news/process starts classification and returns a jobId; poll its status endpoint.
  • POST /api/v1/internal/news/reconcile merges or splits event records; poll its status endpoint.
  • POST /api/v1/internal/news/expire removes expired events.
  • GET /api/v1/internal/news/visibility diagnoses event visibility gates.

Embedding backfills, interest synchronization, event insertion/regeneration, Semble confirmations, and unsorted-content backfills are also available under the internal namespace. Engagement synchronization reconciles self-authored items and updates interest and affinity models. Daily interest synchronization also expires old dashboard items. Collection recommendation maintenance refreshes suggested clusters and cached collection links. These jobs keep maintenance out of client-facing requests. Inspect server/api/v1/internal/ for the exact request shapes.

Verification

npm run lint
npm test
npm run typecheck
npm run build
npx drizzle-kit check

Container

The Dockerfile builds a production Node server, runs database migrations on startup, and exposes port 3000. A Compose service can use this repository directly as its build context:

services:
  campfire:
    build: https://code.incremental.social/thepaperpilot/campfire-core.git
    ports:
      - '3000:3000'
    environment:
      NUXT_PG_CONNECTION_STRING: postgres://n8n:changeme@postgres:5432/n8n
      NUXT_OPENWEBUI_URL: http://openwebui:8080
      NUXT_OPENROUTER_API_KEY: ${OPENROUTER_API_KEY:-}
      NUXT_EMBED_MODEL: qwen3-embedding:0.6b
      NUXT_EMBED_DIMENSIONS: '768'
      NUXT_EMBED_BATCH_SIZE: '32'
      NUXT_EMBED_MAX_CHARACTERS: '8000'
      NUXT_EMBED_NUM_CTX: '32768'
      NUXT_NEWS_MODEL: typesafe/jev-1.13
      NUXT_NEWS_SUMMARY_MODEL: gemma4:e4b
      NUXT_NEWS_CONVERSATION_CONFIDENCE: '0.9'
      NUXT_NEWS_MIN_MEMBERS: '2'
      NUXT_SETUP_TOKEN: ${CAMPFIRE_SETUP_TOKEN:-}

Provide the runtime variables through Compose. The container waits for the database connection and runs pending migrations before serving traffic.

Automated News Events

The n8n event workflow should periodically call the authenticated POST /api/v1/internal/news/process endpoint. Campfire scans recent unassigned items, asks the configured Ollama model whether each belongs to an active event, and creates or updates the event automatically. Processing runs as a background job, so the POST responds immediately with a jobId:

POST /api/v1/internal/news/process        (empty body)
GET  /api/v1/internal/news/process/status?jobId=...

Poll the status endpoint until status is completed (the full result is in result) or failed (details in error). Pass {"lookbackMinutes": 4320} in the body only when recovering a backlog; the default 30-minute window is right for steady state. The lower-level POST /api/v1/internal/events endpoint is also available when n8n has already performed classification.

{
  "title": "Example event",
  "summary": "What happened and why it matters.",
  "members": [
    {
      "itemId": "00000000-0000-0000-0000-000000000000",
      "confidence": 0.94,
      "relationship": "report"
    }
  ],
  "model": "llama3.2:3b",
  "modelVersion": "news-v1"
}

Events appear as priority items in Hearth. Their members are read individually, including messages selected from otherwise unrelated source conversations.

Run reconciliation less frequently, such as every 3-4 hours:

POST /api/v1/internal/news/reconcile        (empty body)
GET  /api/v1/internal/news/reconcile/status?jobId=...

Poll the status endpoint for the result. It uses event-vector similarity followed by Ollama verification before merging duplicate event records, splitting events that contain distinct topics, and regenerating the resulting summaries.

Run expiration cleanup daily:

POST /api/v1/internal/news/expire

If the dashboard shows no events despite related articles, score every active event against each visibility gate with:

GET /api/v1/internal/news/visibility

It reports how many events pass recency, expiry, member-count, confidence, and unread filters, plus per-event details for the largest events.

It marks past-due events expired and removes expired records after the default 30-day retention period.

Backfill title and content for unsorted and recommended URL items with:

POST /api/v1/internal/unsorted/backfill

The endpoint is safe to rerun; items with existing content and items with medium conversation or status are skipped. It processes pending and failed entries in both unsorted and collection recommendations. Migration 0042_reset_webpage_content clears existing content for eligible URL items once so the next scheduled backfill re-extracts them as Markdown.

Re-evaluate existing unsorted items against all writable collections with:

POST /api/v1/internal/collections/recommend

This runs as a background job and can create recommendations for multiple collections from one item. Poll the returned job ID with the news process status endpoint. Items are only re-evaluated when they have not been recommended yet or when a writable collection has changed, so this endpoint can safely run from a regular cron job. The same run refreshes suggested clusters and cached Semble collection links.

Reconcile self-authored activity and synchronize engagement-derived models with:

POST /api/v1/internal/engagement/sync

Run this endpoint in the 15-minute maintenance sequence so new engagement affects ranking promptly.

Run daily interest lifecycle maintenance and expire old dashboard items with:

POST /api/v1/internal/sync-interests

Client-facing routes only record the immediate user action and do not perform this maintenance.