Skip to content
This repository was archived by the owner on Jun 22, 2026. It is now read-only.

Commit f36990a

Browse files
authored
Merge pull request #10 from boringcode-dev/docs/agent-artifacts
docs: add AGENTS.md and architecture/deployment docs for AI agents
2 parents 6c21e40 + 033f4f3 commit f36990a

4 files changed

Lines changed: 135 additions & 0 deletions

File tree

AGENTS.md

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
# AGENTS.md
2+
3+
## Project overview
4+
5+
`feedreader` is a small Go service that aggregates Hacker News, GitHub Trending,
6+
Hugging Face Papers Trending, and alphaXiv into a private, server-rendered feed
7+
reader backed by SQLite. It ships as a Docker container.
8+
9+
## Build & run
10+
11+
```bash
12+
go run ./cmd/feedreader serve --host 127.0.0.1 --port 8080
13+
```
14+
15+
Configuration is env-var driven — see [internal/config/config.go](internal/config/config.go)
16+
for the full list and defaults rather than duplicating it here.
17+
18+
## Test
19+
20+
```bash
21+
gofmt -l $(git ls-files '*.go') # must print nothing
22+
go test ./...
23+
```
24+
25+
Both checks run in CI ([.github/workflows/ci.yml](.github/workflows/ci.yml)) on every PR.
26+
27+
## Code style
28+
29+
`gofmt` is the only formatter. No additional linter is configured.
30+
31+
## Architecture
32+
33+
See [docs/ARCHITECTURE.md](docs/ARCHITECTURE.md) for the package-by-package layout.
34+
35+
## Adding a new feed source
36+
37+
Implement the `sources.Source` interface and register it in `sources.Build()`
38+
in [internal/sources/sources.go](internal/sources/sources.go).
39+
40+
## Security considerations
41+
42+
There is no authentication on the HTTP API surface — this is designed for
43+
private/personal deployment behind your own network or reverse proxy. Do not
44+
add public write endpoints beyond the existing `POST /api/refresh`.
45+
46+
## Commit / PR conventions
47+
48+
Conventional Commits (`feat:`, `fix:`, `chore:`, ...) — releases are automated
49+
via [release-please](.github/workflows/release-please.yml) based on commit
50+
messages.

CLAUDE.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
@AGENTS.md
2+
3+
## Claude-specific notes
4+
5+
- Don't read or modify files under `data/` (gitignored local SQLite DBs).
6+
- Prefer `go test ./internal/<package>/...` over a full `go test ./...` run
7+
when iterating on a single package.

docs/ARCHITECTURE.md

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
# Architecture
2+
3+
## Packages
4+
5+
| Package | Responsibility |
6+
| --- | --- |
7+
| [`cmd/feedreader`](../cmd/feedreader) | CLI entrypoint: `serve`, `fetch`, `healthcheck` subcommands. |
8+
| [`internal/config`](../internal/config) | Env-var configuration loading and defaults. |
9+
| [`internal/db`](../internal/db) | SQLite bootstrap: schema DDL, WAL/pragma setup. |
10+
| [`internal/domain`](../internal/domain) | Plain data types shared across packages (`FeedItem`, `SyncState`, `CardView`, ...). |
11+
| [`internal/repository`](../internal/repository) | Persistence: upserts, sync-state tracking, feed queries. |
12+
| [`internal/service`](../internal/service) | Refresh orchestration, scheduler, card-building/display logic. |
13+
| [`internal/sources`](../internal/sources) | Upstream source adapters (Hacker News, GitHub Trending, Hugging Face Papers, alphaXiv). |
14+
| [`internal/web`](../internal/web) | HTTP routes, SSR page rendering, JSON APIs. |
15+
16+
## Data model and refresh behavior
17+
18+
- Items are upserted by `(source, external_id)`. A refresh never deletes
19+
existing rows — a failed fetch just records the failure in `sync_state` and
20+
leaves prior data in place.
21+
- The original `published_at` is preserved across re-fetches via
22+
`coalesce(items.published_at, excluded.published_at)` — a source that later
23+
starts reporting a different date for the same item doesn't reorder it.
24+
- `internal/repository/sqlite.go`'s `ListFeedItems` sorts and paginates **in
25+
application memory**, not in SQL. This is intentional: total item count
26+
across all 4 sources is small (a few hundred rows), so the simplicity of one
27+
in-memory comparator outweighs the complexity of expressing the same
28+
fallback-ordering (published date, else first-seen date, else source rank)
29+
in SQL.
30+
- The scheduler in `internal/service/service.go` wakes on N-hour wall-clock
31+
boundaries in `Asia/Ho_Chi_Minh` (UTC+7, no DST) — default hourly via
32+
`FEEDREADER_REFRESH_INTERVAL_HOURS`. It does not refresh immediately on
33+
startup.
34+
35+
## Frontend
36+
37+
Server-rendered HTML (`web/templates/index.html`) plus vanilla JS
38+
(`web/static/app.js`) — no frontend build step. The service worker
39+
(`web/static/service-worker.js`) caches the app shell and visited
40+
`/api/items` responses for offline reuse.

docs/DEPLOYMENT.md

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
# Deployment (Docker)
2+
3+
This is the only supported deployment for this repo. A Cloudflare Workers
4+
port lives in a separate repo, `boringcode-dev/feedreader-edge`.
5+
6+
## Build
7+
8+
```bash
9+
docker build -t feedreader .
10+
```
11+
12+
CI publishes multi-arch images (`linux/amd64`, `linux/arm64`) to
13+
`ghcr.io/boringcode-dev/feedreader` on `v*.*.*` tag pushes
14+
([.github/workflows/cd.yml](../.github/workflows/cd.yml)).
15+
16+
## Run
17+
18+
```bash
19+
docker run --rm -p 8080:8080 -v $(pwd)/data:/data feedreader
20+
```
21+
22+
The `/data` volume holds the SQLite database (`FEEDREADER_DB_PATH`, default
23+
`/data/feedreader.db` inside the container). Losing this volume loses all
24+
fetched history; sources are re-fetched from scratch on the next refresh.
25+
26+
## Configuration
27+
28+
See the env var table in [README.md](../README.md#configuration) — this doc
29+
intentionally doesn't duplicate it.
30+
31+
## Release flow
32+
33+
1. Merge to `main` — CI runs `gofmt -l` + `go test ./...`.
34+
2. [release-please](../.github/workflows/release-please.yml) opens a release
35+
PR based on Conventional Commit messages; merging it tags a version and
36+
updates `CHANGELOG.md`.
37+
3. The tag push triggers `cd.yml`, which builds and pushes the image, then
38+
appends container-pull instructions to the GitHub release notes.

0 commit comments

Comments
 (0)