docs: rewrite the README for the working app
Covers what's built versus specified, how to run it, the parser/adapter/ merge layering, and why Arknights: Endfield has no source. Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
This commit is contained in:
co-authored by
Claude Opus 5
parent
b1d18eaf59
commit
62f673161b
@@ -1,2 +1,121 @@
|
|||||||
# gacha-event-tracker
|
# Event Clock
|
||||||
A web application to give an overview over what events are going on, and when they end,
|
|
||||||
|
Live and upcoming events across your gacha games, sorted by what expires next.
|
||||||
|
|
||||||
|
You play three or four gacha games. Each has its own calendar, none of them talk to each other, and
|
||||||
|
the only question that actually matters — *what runs out first?* — takes four browser tabs to
|
||||||
|
answer. This does it in one screen.
|
||||||
|
|
||||||
|
No account. No login. Your completed events are saved in your browser and never leave your device.
|
||||||
|
|
||||||
|
## Status
|
||||||
|
|
||||||
|
Early. The parsing pipeline and the interface work end to end against checked-in fixtures; the
|
||||||
|
server, database and scheduler are specified but not built.
|
||||||
|
|
||||||
|
| Piece | State |
|
||||||
|
|---|---|
|
||||||
|
| Event schema, date parsing, Game8 parser | Built, tested |
|
||||||
|
| Genshin Impact and Neverness to Everness sources | Built, tested |
|
||||||
|
| Cross-source merge and conflict detection | Built, tested |
|
||||||
|
| Web interface | Built |
|
||||||
|
| Bun server, SQLite, refresh scheduler, review queue | Specified in `docs/`, not built |
|
||||||
|
|
||||||
|
Today the feed is generated offline from fixtures. That is deliberate: it let the interface be built
|
||||||
|
against real parsed data, and it produces exactly the shape the server will serve.
|
||||||
|
|
||||||
|
## Try it
|
||||||
|
|
||||||
|
```bash
|
||||||
|
bun install
|
||||||
|
bun run build # parse fixtures → feed, then compile CSS and JS
|
||||||
|
bunx serve public # or any static file server
|
||||||
|
```
|
||||||
|
|
||||||
|
Then open <http://localhost:3000>.
|
||||||
|
|
||||||
|
## Commands
|
||||||
|
|
||||||
|
```bash
|
||||||
|
bun test # full suite, offline, no network
|
||||||
|
bun run typecheck # tsc --noEmit
|
||||||
|
bun run build # feed + css + js + html into public/
|
||||||
|
bun run build:feed # regenerate public/data/events.v1.json from fixtures
|
||||||
|
|
||||||
|
# Run one source against its fixture and print what it yields
|
||||||
|
bun run parse genshin-game8-events fixtures/genshin/game8-events-2026-08-14.html
|
||||||
|
bun run parse nte-game8-events fixtures/nte/game8-events-2026-08-14.html --json
|
||||||
|
```
|
||||||
|
|
||||||
|
## How it works
|
||||||
|
|
||||||
|
```
|
||||||
|
game wikis ──► fetch ──► parse ──► merge ──► validate ──► gate ──► feed ──► browser
|
||||||
|
│ │ │ │
|
||||||
|
per-site per-game hold anything localStorage:
|
||||||
|
parser corroboration uncertain for what you've
|
||||||
|
and conflicts human review finished
|
||||||
|
```
|
||||||
|
|
||||||
|
**Parsers are deterministic code.** There is no LLM anywhere in the pipeline — no API key, no
|
||||||
|
inference, no per-run cost. A source that cannot be parsed reliably does not get an adapter, rather
|
||||||
|
than getting a model that guesses at it.
|
||||||
|
|
||||||
|
**Three layers, so sources multiply cheaply.** A *parser* understands one site template (one Game8
|
||||||
|
parser serves every Game8 page). An *adapter* binds a URL and a game to a parser. *Merge* reconciles
|
||||||
|
several sources for the same game. Adding a source for a site already covered is one registry entry.
|
||||||
|
|
||||||
|
**Nothing is guessed.** Every date function returns null rather than inventing a missing year or
|
||||||
|
end date. An event whose end is unannounced is published with no end and rendered distinctly — never
|
||||||
|
filled in with a plausible-looking date.
|
||||||
|
|
||||||
|
That last rule is the whole product. A missing event sends you to a wiki; a confidently wrong end
|
||||||
|
date makes you miss content. Given the choice, this ships nothing rather than a guess.
|
||||||
|
|
||||||
|
## Games
|
||||||
|
|
||||||
|
| Game | Source | Notes |
|
||||||
|
|---|---|---|
|
||||||
|
| Genshin Impact | Game8 | 9 events |
|
||||||
|
| Neverness to Everness | Game8 | 13 events |
|
||||||
|
| Arknights: Endfield | — | No source yet, see below |
|
||||||
|
|
||||||
|
**Endfield has no adapter on purpose.** Its Game8 page carries no usable dates: every duration reads
|
||||||
|
"Permanently Available", and the schedule is an image grid showing `07/16` with no year and no end
|
||||||
|
date. Supporting it would mean inventing both. It needs a different source.
|
||||||
|
|
||||||
|
Honkai: Star Rail, Zenless Zone Zero, Wuthering Waves and Arknights are defined in the schema and
|
||||||
|
awaiting sources.
|
||||||
|
|
||||||
|
## Adding a source
|
||||||
|
|
||||||
|
1. Check `robots.txt` and the site's terms. If automated access is forbidden, stop — find another
|
||||||
|
source.
|
||||||
|
2. Capture the page once into `fixtures/<game>/<source>-<YYYY-MM-DD>.html`.
|
||||||
|
3. Reuse an existing parser if the site is already covered; otherwise write one implementing
|
||||||
|
`SourceParser`.
|
||||||
|
4. Add an entry to `SOURCES` in `src/ingest/adapters/index.ts`.
|
||||||
|
5. Write the expected output and a test. Then check a few events against the live page by hand — a
|
||||||
|
passing test only proves the parser agrees with a file you wrote yourself.
|
||||||
|
|
||||||
|
Full walkthrough in `docs/INGESTION.md`, or run the `add-game-source` skill.
|
||||||
|
|
||||||
|
## Conduct
|
||||||
|
|
||||||
|
Sources are community wikis, treated as a guest would: `robots.txt` honoured, a descriptive
|
||||||
|
`User-Agent`, one request per source per six hours, conditional requests, and raw snapshots cached
|
||||||
|
so iteration never re-fetches. Every event links back to its source.
|
||||||
|
|
||||||
|
## Documentation
|
||||||
|
|
||||||
|
| Document | Covers |
|
||||||
|
|---|---|
|
||||||
|
| `CLAUDE.md` | Working agreements, domain rules, conventions |
|
||||||
|
| `docs/PRD.md` | What this is, who for, what's out of scope |
|
||||||
|
| `docs/ARCHITECTURE.md` | Process shape, routes, deployment |
|
||||||
|
| `docs/DATA-MODEL.md` | Event schema, SQLite tables, client storage |
|
||||||
|
| `docs/INGESTION.md` | Parser/adapter/merge layers, pipeline stages, review gate |
|
||||||
|
|
||||||
|
## Licence
|
||||||
|
|
||||||
|
Not yet chosen. Event data belongs to the sources it came from and is linked back on every event.
|
||||||
|
|||||||
Reference in New Issue
Block a user