linkleaf-core 0.1.2

Local-first protobuf-only link feed manager (linkleaf.v1) library
Documentation
<h1 align="center">Linkleaf</h1>

<p align="center">
  Manage <strong>protobuf-only</strong> Linkleaf feeds (<code>linkleaf.v1</code>)
</p>

A tiny library for storing, updating, and querying a personal link feed backed by a compact **Protocol Buffers** file. It gives you ergonomic helpers to:

- Add or update links (upsert) and keep them newest-first
- List links with optional tag and date filters
- Read and write feeds from disk (atomic write, best-effort)
- Parse tags from a comma-separated string

It’s built on `prost` (for protobuf).

## Data model

```
// Generated by prost (simplified):
pub struct DateTime {
    pub year: i32,
    pub month: i32,
    pub day: i32,
    pub hours: i32,
    pub minutes: i32,
    pub seconds: i32,
    pub nanos: i32,
}

pub struct Summary {
    pub content: String,
}

pub struct Via {
    pub url: String,
}

pub struct Link {
    pub id: String,            // UUID v4 (string)
    pub title: String,         // required
    pub url: String,           // required
    pub datetime: Option<DateTime>,    // always present
    pub summary: Option<Summary>,
    pub tags: Vec<String>,
    pub via: Option<Via>,
}

pub struct Feed {
    pub title: String,
    pub version: u32,
    pub links: Vec<Link>,      // newest-first
}
```

### Feed and Link Schemas

Defined in [`feed.proto`](proto/linkleaf/v1/feed.proto):

- DateTime
  - `year`, `month`, `day`, `hours`, `minutes`, `seconds`, `nanos`
- Summary
  - `content` (string)

- Via
  - `url` (string)

- Link
  - `id` (string) — auto-derived if omitted
  - `title` (string, required)
  - `url` (string, required)
  - `datetime` (DateTime, YYYY-MM-DD HH:MM:SS)
  - `summary` (optional Summary)
  - `tags` (optional repeated strings)
  - `via` (optional Via)

- Feed
  - `title` (string)
  - `version` (uint32)
  - `links` (repeated Link, newest first)

## Examples
```
# run the minimal flow
cargo run --example quickstart

# upsert by id (moves updated link to front)
cargo run --example upsert_by_id

# upsert by URL when id=None
cargo run --example upsert_by_url

# tag & date filtering
cargo run --example filter

# generate rss feed from linkleaf feed
cargo run --example gen_rss_feed

```

## Design notes

- Timestamps are stored as local time strings ("YYYY-MM-DD HH:MM:SS"). Filtering compares the date component only.
- Ordering is newest-first (index 0). Inserts and updates are re-inserted at the front.
- Concurrency: writes are not lock-guarded; concurrent writers can race. Add a lock if multiple processes may write at once.

## TODO
- add tag next release
- use git-cliff