TreeMap
무료 오픈소스 디스크 사용량 시각화 도구로, 사각형 트리맵·중복 파일 탐색·디스크 가득 예측·정리 시 파일을 휴지통으로만 이동한다
아직 감지된 업데이트가 없습니다. GitHub 릴리스가 나오면 여기에 보입니다.
개인 계정의 공개 저장소 소유자는 GitHub로 로그인해 운영자를 확인하고 소개를 직접 관리할 수 있습니다. 관리자 승인은 필요하지 않습니다.
로그인한 뒤 확인 파일을 만들어 이 저장소의 기본 브랜치에 30분 안에 커밋해 주세요. 다른 브랜치나 포크의 파일은 인정하지 않습니다. 파일을 올린 뒤 아래에서 확인하면 관리자 승인 없이 관리할 수 있습니다. 자격을 유지하려면 파일을 남겨 두세요.
로그인이 필요하면 로그인 화면으로 이동합니다. 로그인 후 이곳으로 돌아와 원하는 확인 버튼을 다시 눌러 주세요.
프로젝트 폴더에서 /nomorevibe verify를 실행하면 소유권을 확인하고 소개를 직접 관리할 수 있습니다.
1분 만에 확인하기A self-hosted, tamper-proof personal log
저장소 README에서 가져옴
README 전체를 불러오는 중입니다.
README 전문 보기 ↗Tagebuch-Microsite zum Loggen des eigenen Tages, ähnlich einem privaten Microblog. Ein einzelnes Go-Binary mit eingebettetem Vanilla-JS-Frontend und SQLite als Speicher.
#hashtags, Suche, Tages- und Zeitraumansichtdocker compose up -d --build
Danach läuft die App auf http://localhost:8080, die Statistikseite auf /dashboard.
Fertige Images liegen auf Docker Hub unter dettmering/personal-timeline (latest = master, sonst der Git-Tag).
| Variable | Default | Bedeutung |
|---|---|---|
DB_PATH | /data/timeline.db | Pfad zur SQLite-Datei |
LISTEN_ADDR | :8080 | Listen-Adresse |
TZ | Systemzeitzone (Europe/Berlin im Image) | Zeitzone, in der Kalendertage gelten |
API_KEY | – | Wenn gesetzt, nötig für automatisierte Einträge und manuelles Versiegeln |
ENCRYPTION_KEY | – | Base64-kodierter 32-Byte-Schlüssel; aktiviert die Verschlüsselung |
WEBHOOK_URL | – | Ziel für den Webhook bei neuen Einträgen |
SHOW_PERMALINK | false | Permalink-Knopf (🔗) an Einträgen anzeigen |
SHOW_QUOTE | false | Zitier-Knopf (❝) an Einträgen anzeigen |
Statt ENCRYPTION_KEY direkt zu setzen, kann der Schlüssel als Datei nach /run/secrets/timeline_encryption_key gemountet werden (siehe docker-compose.yml). Neuen Schlüssel erzeugen:
openssl rand -base64 32
Beim ersten Start mit Schlüssel werden alle bestehenden Klartext-Einträge verschlüsselt. Die Tagessiegel bleiben dabei gültig. Ohne den Schlüssel sind die Einträge danach nicht mehr lesbar.
Basis-URL ist der Server selbst, z. B. http://localhost:8080. GET /api/schema liefert eine maschinenlesbare Beschreibung aller Ausgabeformate, gedacht für LLM-Clients.
application/json; charset=utf-8), außer dem .ots-Download.2026-06-06T14:03:21.123456789Z.YYYY-MM-DD, bezogen auf die Server-Zeitzone (TZ), nicht auf UTC.merkle_root, seal_hash, …) sind SHA-256-Digests als Standard-Base64.null zu sein.{"error": "<Meldung>"} mit Status 400 (ungültige Eingabe), 401 (API-Key fehlt oder falsch), 403 (nicht bearbeitbar/löschbar), 404 (nicht gefunden) oder 500.Der API-Key wird nur verlangt für POST /api/entries mit "automated": true und für POST /api/seals/{date}. Alle anderen Endpunkte sind offen. Ist API_KEY nicht gesetzt, entfällt die Prüfung ganz.
Übergabe per Header, wahlweise:
Authorization: Bearer <API_KEY>
X-API-Key: <API_KEY>
Entry
| Feld | Typ | |
|---|---|---|
id | Integer | |
text | String | max. 10 000 Zeichen, Markdown, kann #hashtags enthalten |
created_at | Zeitstempel | |
edited_at | Zeitstempel, optional | fehlt, wenn nie bearbeitet |
automated | Boolean | per API-Key angelegt statt in der Oberfläche |
hashtags | String-Array | kleingeschrieben, ohne #; leer, wenn keine |
lat, lon | Zahl, optional | nur gemeinsam vorhanden |
{
"id": 42,
"text": "Morgenlauf am See #sport #morgen",
"created_at": "2026-06-06T05:12:44.123456789Z",
"automated": false,
"hashtags": ["morgen", "sport"],
"lat": 52.5163,
"lon": 13.3777
}
DaySeal
| Feld | Typ | |
|---|---|---|
date | Datum | versiegelter Tag |
entry_count | Integer | Anzahl Einträge an dem Tag |
merkle_root | Base64 | Merkle-Root über die sortierten Eintrags-Hashes |
prev_seal_hash | Base64, optional | seal_hash des Vortags-Siegels; fehlt beim ersten Siegel |
seal_hash | Base64 | SHA-256(date ‖ merkle_root ‖ prev_seal_hash) |
sealed_at | Zeitstempel | |
has_ots_proof | Boolean | OpenTimestamps-Beleg liegt vor |
ots_upgraded_at | Zeitstempel, optional | gesetzt, sobald der Beleg in einem Bitcoin-Block verankert ist |
VerifyResult
| Feld | Typ | |
|---|---|---|
entries_checked | Integer | |
days_checked | Integer | |
chain_ok | Boolean | alle Siegel passen zu ihren Einträgen, Kette intakt |
first_broken_day | Datum, optional | erster Tag mit Abweichung |
break_reason | String, optional | Grund der Abweichung |
ots_present | Integer | Siegel mit OTS-Beleg |
ots_upgraded | Integer | Siegel mit Bitcoin-Verankerung |
GET /api/entriesDie Query-Parameter bestimmen den Modus. Geprüft wird in dieser Reihenfolge, der erste passende gewinnt:
| Modus | Parameter | Antwort |
|---|---|---|
| Hashtag | hashtag=<tag> (# optional), limit=<n> optional | {"hashtag": "<tag>", "entries": [Entry…]} |
| Suche | q=<text>, limit=<n> (Default 20, max. 50) | {"entries": [Entry…]} |
| Zeitraum | from=YYYY-MM-DD&to=YYYY-MM-DD (beide Pflicht, inklusive) | {"from": "…", "to": "…", "entries": [Entry…]} |
| Tag (Default) | date=YYYY-MM-DD (Default: heute) | {"date": "…", "entries": [Entry…]} |
Die Suche findet Teilstrings ohne Beachtung von Groß- und Kleinschreibung. Ein leeres q liefert die neuesten Einträge.
curl 'http://localhost:8080/api/entries?date=2026-06-06'
curl 'http://localhost:8080/api/entries?from=2026-06-01&to=2026-06-07'
curl 'http://localhost:8080/api/entries?hashtag=sport&limit=10'
curl 'http://localhost:8080/api/entries?q=see'
GET /api/entries/{id}Ein einzelner Eintrag. Antwort: Entry.
POST /api/entriesLegt einen Eintrag an. Antwort: Entry mit Status 201.
| Feld | Pflicht | |
|---|---|---|
text | ja | nicht leer, max. 10 000 Zeichen |
automated | nein | true verlangt den API-Key |
lat, lon | nein | nur gemeinsam; -90..90 bzw. -180..180; Zahl oder String |
Koordinaten lassen sich später nicht mehr ändern. Ist WEBHOOK_URL gesetzt, geht der angelegte Eintrag als JSON per POST dorthin. Der Aufruf läuft asynchron mit 10 s Timeout, Fehler landen nur im Log.
curl -X POST http://localhost:8080/api/entries \
-H 'Content-Type: application/json' \
-d '{"text": "Kaffee getrunken #morgen"}'
curl -X POST http://localhost:8080/api/entries \
-H "Authorization: Bearer $API_KEY" \
-H 'Content-Type: application/json' \
-d '{"text": "10 km gelaufen #sport", "automated": true, "lat": 52.5163, "lon": 13.3777}'
PUT /api/entries/{id}Ändert den Text. Body: {"text": "…"}. Antwort: Entry. Erlaubt nur für nicht-automatisierte Einträge vom heutigen Tag, sonst 403.
DELETE /api/entries/{id}Löscht einen Eintrag vom heutigen Tag (auch automatisierte), sonst 403. Antwort: 204 ohne Body.
Ein Hintergrundprozess versiegelt alle zehn Minuten jeden abgeschlossenen Tag, der noch kein Siegel hat. Danach wird der seal_hash bei den OpenTimestamps-Kalendern eingereicht. Stündlich wird geprüft, ob die Bitcoin-Bestätigung vorliegt, was meist ein bis zwei Stunden dauert.
| Endpunkt | Antwort |
|---|---|
GET /api/seals | {"seals": [DaySeal…]} |
GET /api/seals/{date} | DaySeal |
GET /api/seals/{date}/proof.ots | binärer OTS-Beleg als Download (404, solange noch keiner vorliegt) |
POST /api/seals/{date} | versiegelt einen vergangenen Tag sofort (API-Key nötig): {"seal": DaySeal, "created": bool}, Status 201 wenn neu, 200 wenn schon versiegelt |
GET /api/verify | prüft die gesamte Kette: VerifyResult |
Beleg offline prüfen:
curl -O http://localhost:8080/api/seals/2026-06-06/proof.ots
ots verify 2026-06-06.ots # offizielles OTS-CLI
scripts/verify_seal.py 2026-06-06 --api http://localhost:8080 # nur Python-Stdlib
| Endpunkt | Antwort |
|---|---|
GET /api/hashtags | {"hashtags": ["tag", …]}, nach Häufigkeit sortiert |
GET /api/config | {"show_permalink": bool, "show_quote": bool} |
GET /api/health | {"status": "ok"} |
GET /api/schema | Beschreibung der Ausgabeformate als JSON |
scripts/backup.sh: Online-Backup der SQLite-Datei aus dem Docker-Volume, gzip-komprimiert, alte Backups werden nach KEEP_DAYS gelöschtscripts/export.py: exportiert alle Einträge direkt aus der .db als JSON, bei Bedarf mit --key entschlüsseltscripts/verify_seal.py: prüft ein Tagessiegel gegen seinen OTS-Beleg und die Bitcoin-BlockchainGo muss nicht installiert sein, alles läuft über Docker:
docker run --rm -v $(pwd):/src -w /src golang:1.22-alpine go test ./...
docker run --rm -v $(pwd):/src -w /src golang:1.22-alpine go build ./...
Architektur und Designentscheidungen stehen in CLAUDE.md.