mirror of
https://github.com/skoelle/icloud-contacts-sync.git
synced 2026-09-17 15:30:24 +00:00
Update README.md and more
This commit is contained in:
@@ -9,7 +9,7 @@ Automated CardDAV delta-sync (RFC 6578) of multiple iCloud accounts into a share
|
|||||||
- **Language:** Python 3.12
|
- **Language:** Python 3.12
|
||||||
- **Framework:** FastAPI (API), PyMySQL (DB), vobject (vCard), lxml (XML), requests (HTTP)
|
- **Framework:** FastAPI (API), PyMySQL (DB), vobject (vCard), lxml (XML), requests (HTTP)
|
||||||
- **Database:** MariaDB (InnoDB, utf8mb4)
|
- **Database:** MariaDB (InnoDB, utf8mb4)
|
||||||
- **Container:** python:3.12-slim, supercronic for cron
|
- **Container:** python:3.12-slim, Python-based scheduler (no external cron)
|
||||||
- **CI/CD:** GitHub Actions — lint (ruff), build+push (ghcr.io)
|
- **CI/CD:** GitHub Actions — lint (ruff), build+push (ghcr.io)
|
||||||
- **Auth:** Authelia reverse-proxy header (`Remote-User`), no built-in login
|
- **Auth:** Authelia reverse-proxy header (`Remote-User`), no built-in login
|
||||||
|
|
||||||
@@ -19,11 +19,11 @@ Automated CardDAV delta-sync (RFC 6578) of multiple iCloud accounts into a share
|
|||||||
src/
|
src/
|
||||||
sync.py — Main sync orchestrator (cron entry point)
|
sync.py — Main sync orchestrator (cron entry point)
|
||||||
mailer.py — Birthday email sender (cron entry point)
|
mailer.py — Birthday email sender (cron entry point)
|
||||||
config.py — Reads accounts.yml + env vars
|
config.py — Reads accounts.json + env vars
|
||||||
db.py — MariaDB connection and queries
|
db.py — MariaDB connection and queries
|
||||||
carddav_client.py — CardDAV HTTP client (sync-collection, addressbook-query)
|
carddav_client.py — CardDAV HTTP client (sync-collection, addressbook-query)
|
||||||
vcard_parser.py — vCard parsing via vobject
|
vcard_parser.py — vCard parsing via vobject
|
||||||
scheduler.py — supercronic crontab generation
|
scheduler.py — Python-based scheduler (PID 1 in container)
|
||||||
api/
|
api/
|
||||||
main.py — FastAPI app (uvicorn entry point)
|
main.py — FastAPI app (uvicorn entry point)
|
||||||
auth.py — Remote-User header dependency
|
auth.py — Remote-User header dependency
|
||||||
@@ -34,9 +34,9 @@ sql/
|
|||||||
schema.sql — Full schema (contacts, sync_state, sync_runs, birthday_mail_log)
|
schema.sql — Full schema (contacts, sync_state, sync_runs, birthday_mail_log)
|
||||||
db-and-user.sql — One-time DB + user setup
|
db-and-user.sql — One-time DB + user setup
|
||||||
config/
|
config/
|
||||||
accounts.yml — Per-account credentials (NOT in git, volume-mounted)
|
accounts.json — Per-account credentials (NOT in git, volume-mounted)
|
||||||
docker/
|
docker/
|
||||||
entrypoint.sh — Generates crontab, starts supercronic
|
entrypoint.sh — Starts scheduler.py (or exec's custom command)
|
||||||
```
|
```
|
||||||
|
|
||||||
## Key Files
|
## Key Files
|
||||||
@@ -46,7 +46,7 @@ docker/
|
|||||||
| `src/sync.py` | CLI entry point for sync (`python3 sync.py`) |
|
| `src/sync.py` | CLI entry point for sync (`python3 sync.py`) |
|
||||||
| `src/mailer.py` | CLI entry point for birthday mailer (`python3 mailer.py`) |
|
| `src/mailer.py` | CLI entry point for birthday mailer (`python3 mailer.py`) |
|
||||||
| `src/api/main.py` | FastAPI app entry point (`uvicorn api.main:app`) |
|
| `src/api/main.py` | FastAPI app entry point (`uvicorn api.main:app`) |
|
||||||
| `src/config.py` | Loads `accounts.yml` + all env vars |
|
| `src/config.py` | Loads `accounts.json` + all env vars |
|
||||||
| `src/db.py` | All MariaDB queries |
|
| `src/db.py` | All MariaDB queries |
|
||||||
| `sql/schema.sql` | Canonical schema definition |
|
| `sql/schema.sql` | Canonical schema definition |
|
||||||
| `.env.example` | All supported environment variables |
|
| `.env.example` | All supported environment variables |
|
||||||
@@ -88,7 +88,7 @@ docker compose up -d
|
|||||||
- All source in `src/`, single package, no `setup.py`/`pyproject.toml`.
|
- All source in `src/`, single package, no `setup.py`/`pyproject.toml`.
|
||||||
- No comments in code unless explicitly requested.
|
- No comments in code unless explicitly requested.
|
||||||
- Follow existing code style; no new dependencies unless absolutely necessary.
|
- Follow existing code style; no new dependencies unless absolutely necessary.
|
||||||
- Secrets must never be committed. `config/accounts.yml` and `.env` are gitignored.
|
- Secrets must never be committed. `config/accounts.json` and `.env` are gitignored.
|
||||||
- The DB schema uses `account` column as tenant key — all queries are scoped per account.
|
- The DB schema uses `account` column as tenant key — all queries are scoped per account.
|
||||||
- JSON columns (`emails`, `phones`, etc.) store multi-value vCard fields.
|
- JSON columns (`emails`, `phones`, etc.) store multi-value vCard fields.
|
||||||
|
|
||||||
@@ -113,27 +113,34 @@ See `.env.example` for full list. Key variables:
|
|||||||
|
|
||||||
## Architecture Notes
|
## Architecture Notes
|
||||||
|
|
||||||
- Single Docker image, two roles: cron (sync+mailer) and API (uvicorn).
|
- Single Docker image, two roles: scheduler (sync+mailer) and API (uvicorn).
|
||||||
- API is read-only; only the sync container writes to MariaDB.
|
- API is read-only; only the sync container writes to MariaDB.
|
||||||
- Sync uses CardDAV `sync-collection` (RFC 6578) for efficient delta sync.
|
- Sync uses CardDAV `sync-collection` (RFC 6578) for efficient delta sync.
|
||||||
- Token expiry (~29 days) triggers automatic full re-sync.
|
- Token expiry (~29 days) triggers automatic full re-sync.
|
||||||
- Deleted contacts are removed from DB (no archival).
|
- Deleted contacts are removed from DB (no archival).
|
||||||
|
|
||||||
|
## Documentation
|
||||||
|
|
||||||
|
**IMPORTANT:** `README.md` and `SPEC.md` are the authoritative German-language documentation for this project. They must be kept up to date whenever code, configuration, schema, or architecture changes. Always update these files as part of any feature or fix implementation.
|
||||||
|
|
||||||
## Common Tasks
|
## Common Tasks
|
||||||
|
|
||||||
### Adding a new API endpoint
|
### Adding a new API endpoint
|
||||||
1. Add route in `src/api/main.py`
|
1. Add route in `src/api/main.py`
|
||||||
2. Add Pydantic model in `src/api/schemas.py` if needed
|
2. Add Pydantic model in `src/api/schemas.py` if needed
|
||||||
3. Add DB query in `src/db.py` if needed
|
3. Add DB query in `src/db.py` if needed
|
||||||
4. Test with: `curl -H "Remote-User: <user>" http://127.0.0.1:8000/<path>`
|
4. Update endpoint table in `SPEC.md` and `README.md`
|
||||||
|
5. Test with: `curl -H "Remote-User: <user>" http://127.0.0.1:8000/<path>`
|
||||||
|
|
||||||
### Adding a new contact field
|
### Adding a new contact field
|
||||||
1. Add column to `contacts` table in `sql/schema.sql`
|
1. Add column to `contacts` table in `sql/schema.sql`
|
||||||
2. Update `src/vcard_parser.py` to extract the field
|
2. Update `src/vcard_parser.py` to extract the field
|
||||||
3. Update `src/db.py` upsert query
|
3. Update `src/db.py` upsert query
|
||||||
4. Update `src/api/schemas.py` if exposing via API
|
4. Update `src/api/schemas.py` if exposing via API
|
||||||
|
5. Update `SPEC.md` (data model section)
|
||||||
|
|
||||||
### Changing the sync logic
|
### Changing the sync logic
|
||||||
1. Edit `src/carddav_client.py` for CardDAV protocol changes
|
1. Edit `src/carddav_client.py` for CardDAV protocol changes
|
||||||
2. Edit `src/sync.py` for orchestration changes
|
2. Edit `src/sync.py` for orchestration changes
|
||||||
3. Test with a single account first: set `LOG_LEVEL=DEBUG`
|
3. Update `SPEC.md` if sync behavior changes
|
||||||
|
4. Test with a single account first: set `LOG_LEVEL=DEBUG`
|
||||||
|
|||||||
@@ -28,14 +28,16 @@ Für jede Apple-ID, die du syncen willst:
|
|||||||
## 2. Multi-User-Konfiguration anlegen
|
## 2. Multi-User-Konfiguration anlegen
|
||||||
|
|
||||||
```
|
```
|
||||||
cp config/accounts.yml.example config/accounts.yml
|
cp config/accounts.json.example config/accounts.json
|
||||||
vim config/accounts.yml
|
vim config/accounts.json
|
||||||
```
|
```
|
||||||
|
|
||||||
Trage für jede Apple-ID einen Eintrag mit eindeutigem `name`,
|
Trage für jede Apple-ID einen Eintrag mit eindeutigem `name`,
|
||||||
`apple_email` und `apple_app_password` ein. Diese Datei bleibt lokal
|
`apple_email`, `apple_app_password` und `authelia_user` ein. Diese Datei
|
||||||
auf dem Host, sie ist in `.gitignore` ausgeschlossen und wird nur als
|
bleibt lokal auf dem Host, sie ist in `.gitignore` ausgeschlossen und
|
||||||
Volume in den Container gemountet.
|
wird nur als Volume in den Container gemountet.
|
||||||
|
|
||||||
|
Siehe `config/README.md` für eine vollständige Beschreibung der Felder.
|
||||||
|
|
||||||
## 3. Datenbank vorbereiten
|
## 3. Datenbank vorbereiten
|
||||||
|
|
||||||
@@ -109,6 +111,8 @@ ORDER BY sent_date DESC LIMIT 10;
|
|||||||
|
|
||||||
- Läuft automatisch täglich um die in `MAIL_SEND_HOUR` konfigurierte
|
- Läuft automatisch täglich um die in `MAIL_SEND_HOUR` konfigurierte
|
||||||
Stunde (Default 7 Uhr) innerhalb desselben Containers.
|
Stunde (Default 7 Uhr) innerhalb desselben Containers.
|
||||||
|
- Versendet eine HTML-E-Mail mit stylisierten Geburtstagskarten und
|
||||||
|
Links zur Kontakt-Detailseite (falls `WEB_URL` gesetzt).
|
||||||
- Über `MAILER_ENABLED=false` lässt sich der Mailer ganz abschalten,
|
- Über `MAILER_ENABLED=false` lässt sich der Mailer ganz abschalten,
|
||||||
ohne den Kontakt-Sync zu beeinträchtigen.
|
ohne den Kontakt-Sync zu beeinträchtigen.
|
||||||
- Manueller Testlauf im laufenden Container:
|
- Manueller Testlauf im laufenden Container:
|
||||||
@@ -143,10 +147,6 @@ python3 mailer.py
|
|||||||
keine vollständige Historie: ein gelöschter iCloud-Kontakt wird auch
|
keine vollständige Historie: ein gelöschter iCloud-Kontakt wird auch
|
||||||
aus MariaDB entfernt, ohne Archiv.
|
aus MariaDB entfernt, ohne Archiv.
|
||||||
- Nur iCloud als Quelle, Google/Microsoft sind nicht Teil dieses Repos.
|
- Nur iCloud als Quelle, Google/Microsoft sind nicht Teil dieses Repos.
|
||||||
- Eine separate Web-Ansicht mit API ist als eigenständiges,
|
|
||||||
nachgelagertes Container-Projekt geplant, das nur lesend auf dieselbe
|
|
||||||
MariaDB zugreift (siehe SPEC.md, Abschnitt 11).
|
|
||||||
|
|
||||||
|
|
||||||
## 11. Web-Ansicht und API (interner Zugriff über Authelia)
|
## 11. Web-Ansicht und API (interner Zugriff über Authelia)
|
||||||
|
|
||||||
@@ -205,9 +205,10 @@ Zugriff ohne den Reverse-Proxy ist damit nicht möglich.
|
|||||||
| Methode | Pfad | Beschreibung |
|
| Methode | Pfad | Beschreibung |
|
||||||
|---------|------|--------------|
|
|---------|------|--------------|
|
||||||
| `GET` | `/` | Web-UI — zeigt Kontakte des eingeloggten Users (HTML) |
|
| `GET` | `/` | Web-UI — zeigt Kontakte des eingeloggten Users (HTML) |
|
||||||
|
| `GET` | `/contacts/{id}` | Web-UI — Detailseite eines einzelnen Kontakts |
|
||||||
| `GET` | `/api/health` | Health Check (`{"status": "ok"}`), kein Login nötig |
|
| `GET` | `/api/health` | Health Check (`{"status": "ok"}`), kein Login nötig |
|
||||||
| `GET` | `/api/contacts` | Kontaktsuche mit Pagination (`?q=...&limit=...&offset=...`) |
|
| `GET` | `/api/contacts` | Kontaktsuche mit Pagination (`?q=...&limit=...&offset=...`) |
|
||||||
| `GET` | `/api/contacts/{contact_id}` | Einzelnen Kontakt per ID abrufen |
|
| `GET` | `/api/contacts/{id}` | Einzelnen Kontakt per ID abrufen |
|
||||||
| `GET` | `/api/contacts/birthdays/today` | Heutige Geburtstage |
|
| `GET` | `/api/contacts/birthdays/today` | Heutige Geburtstage |
|
||||||
| `GET` | `/api/sync-runs` | Letzte 50 Sync-Runs (Status, Zeitstempel, Fehler) |
|
| `GET` | `/api/sync-runs` | Letzte 50 Sync-Runs (Status, Zeitstempel, Fehler) |
|
||||||
|
|
||||||
|
|||||||
@@ -34,16 +34,16 @@ außerhalb des Apple-Ökosystems.
|
|||||||
|
|
||||||
## 3. Multi-User-Konfiguration
|
## 3. Multi-User-Konfiguration
|
||||||
|
|
||||||
- Datei `config/accounts.yml` (gemountet, nicht im Image, nicht im Git,
|
- Datei `config/accounts.json` (gemountet, nicht im Image, nicht im Git,
|
||||||
siehe `.gitignore`), Struktur:
|
siehe `.gitignore`), Struktur:
|
||||||
```yaml
|
```json
|
||||||
accounts:
|
{
|
||||||
- name: markus
|
"accounts": [
|
||||||
apple_email: markus@icloud.com
|
{ "name": "markus", "apple_email": "markus@icloud.com", "apple_app_password": "xxxx-xxxx-xxxx-xxxx", "authelia_user": "mmustermann" },
|
||||||
apple_app_password: "xxxx-xxxx-xxxx-xxxx"
|
{ "name": "partner", "apple_email": "partner@icloud.com", "apple_app_password": "yyyy-yyyy-yyyy-yyyy", "authelia_user": "pmustermann" }
|
||||||
- name: partner
|
],
|
||||||
apple_email: partner@icloud.com
|
"admins": ["mmustermann"]
|
||||||
apple_app_password: "yyyy-yyyy-yyyy-yyyy"
|
}
|
||||||
```
|
```
|
||||||
- `name` ist der interne, eindeutige Account-Bezeichner und wird 1:1 als
|
- `name` ist der interne, eindeutige Account-Bezeichner und wird 1:1 als
|
||||||
`account`-Spalte in `contacts`, `sync_state` und `sync_runs`
|
`account`-Spalte in `contacts`, `sync_state` und `sync_runs`
|
||||||
@@ -107,9 +107,10 @@ Siehe `sql/schema.sql`. Wichtigste Änderungen gegenüber v1:
|
|||||||
Eintrag für den heutigen Tag geprüft; existiert bereits einer, wird
|
Eintrag für den heutigen Tag geprüft; existiert bereits einer, wird
|
||||||
der Lauf ohne erneuten Versand beendet.
|
der Lauf ohne erneuten Versand beendet.
|
||||||
- Feature-Flag `MAILER_ENABLED` erlaubt das komplette Deaktivieren ohne
|
- Feature-Flag `MAILER_ENABLED` erlaubt das komplette Deaktivieren ohne
|
||||||
Codeänderung.
|
Codeänderung (Default: `false`).
|
||||||
- E-Mail-Inhalt aktuell reiner Text (Name, Alter, Account), HTML-Format
|
- E-Mail-Inhalt: HTML-E-Mail mit stylisierten Geburtstagskarten
|
||||||
ist als spätere Erweiterung denkbar, aber nicht im Scope.
|
(Name, Alter, Account, Link zur Kontakt-Detailseite falls `WEB_URL`
|
||||||
|
gesetzt). Zusätzlich reiner Text-Alternative als Fallback.
|
||||||
|
|
||||||
## 7. Konfiguration (Umgebungsvariablen)
|
## 7. Konfiguration (Umgebungsvariablen)
|
||||||
|
|
||||||
@@ -120,9 +121,9 @@ Siehe `sql/schema.sql`. Wichtigste Änderungen gegenüber v1:
|
|||||||
| MARIADB_DATABASE | nein | Default: contacts |
|
| MARIADB_DATABASE | nein | Default: contacts |
|
||||||
| MARIADB_USER | ja | DB-Benutzer mit Schreibrechten |
|
| MARIADB_USER | ja | DB-Benutzer mit Schreibrechten |
|
||||||
| MARIADB_PASSWORD | ja | Passwort des DB-Benutzers |
|
| MARIADB_PASSWORD | ja | Passwort des DB-Benutzers |
|
||||||
| ACCOUNTS_CONFIG_PATH | nein | Default: /app/config/accounts.yml |
|
| ACCOUNTS_CONFIG_PATH | nein | Default: /app/config/accounts.json |
|
||||||
| LOG_LEVEL | nein | Default: INFO |
|
| LOG_LEVEL | nein | Default: INFO |
|
||||||
| MAILER_ENABLED | nein | Default: true, deaktiviert Mailer bei false |
|
| MAILER_ENABLED | nein | Default: false, aktiviert Mailer bei true |
|
||||||
| SMTP_HOST | ja (Mailer) | SMTP-Relay-Host |
|
| SMTP_HOST | ja (Mailer) | SMTP-Relay-Host |
|
||||||
| SMTP_PORT | nein | Default: 587 |
|
| SMTP_PORT | nein | Default: 587 |
|
||||||
| SMTP_USER | nein | leer, falls Relay ohne Auth |
|
| SMTP_USER | nein | leer, falls Relay ohne Auth |
|
||||||
@@ -131,18 +132,26 @@ Siehe `sql/schema.sql`. Wichtigste Änderungen gegenüber v1:
|
|||||||
| MAIL_FROM | ja (Mailer) | Absenderadresse |
|
| MAIL_FROM | ja (Mailer) | Absenderadresse |
|
||||||
| MAIL_TO | ja (Mailer) | Empfängeradresse(n) |
|
| MAIL_TO | ja (Mailer) | Empfängeradresse(n) |
|
||||||
| MAIL_SEND_HOUR | nein | Default: 7, Stunde (0-23) für täglichen Mailversand |
|
| MAIL_SEND_HOUR | nein | Default: 7, Stunde (0-23) für täglichen Mailversand |
|
||||||
|
| WEB_URL | nein | Web-URL für Links in Geburtstags-Mails (z.B. https://kontakte.example.de) |
|
||||||
|
| AUTH_REMOTE_USER_HEADER | nein | Default: Remote-User, Header-Name für Authelia-User |
|
||||||
|
| API_HOST | nein | Default: 0.0.0.0, Bindungs-Adresse des API-Services |
|
||||||
|
| API_PORT | nein | Default: 8000, Port des API-Services |
|
||||||
|
|
||||||
Secrets werden weiterhin als klassische Umgebungsvariablen übergeben,
|
Secrets werden weiterhin als klassische Umgebungsvariablen übergeben,
|
||||||
mit Ausnahme der Multi-Account-Zugangsdaten, die aus `accounts.yml`
|
mit Ausnahme der Multi-Account-Zugangsdaten, die aus `accounts.json`
|
||||||
gelesen werden (per Volume-Mount, nicht im Image, nicht im Git).
|
gelesen werden (per Volume-Mount, nicht im Image, nicht im Git).
|
||||||
|
|
||||||
## 8. Container-Image
|
## 8. Container-Image
|
||||||
|
|
||||||
- Basis: `python:3.12-slim`, Zeitsteuerung über `supercronic`.
|
- Basis: `python:3.12-slim`.
|
||||||
- Zwei Cron-Einträge im dynamisch generierten Crontab: Sync (`*/15`)
|
- Python-basierter Scheduler (`src/scheduler.py`) als PID 1 im Container:
|
||||||
und Mailer (`0 <MAIL_SEND_HOUR> * * *`).
|
- Keine externe Cron-Abhängigkeit (kein supercronic nötig).
|
||||||
|
- Sync: alle 15 Minuten (`SYNC_INTERVAL_MINUTES`).
|
||||||
|
- Mailer: täglich um `MAIL_SEND_HOUR` Uhr (falls `MAILER_ENABLED=true`).
|
||||||
|
- Initialer Sync sofort beim Container-Start.
|
||||||
|
- Sauberes Herunterfahren via SIGTERM/SIGINT.
|
||||||
- Läuft als non-root User (`syncuser`, UID 10001).
|
- Läuft als non-root User (`syncuser`, UID 10001).
|
||||||
- `HEALTHCHECK` prüft weiterhin die Marker-Datei des letzten
|
- `HEALTHCHECK` prüft die Marker-Datei `/tmp/last_sync_ok` des letzten
|
||||||
erfolgreichen Sync-Laufs.
|
erfolgreichen Sync-Laufs.
|
||||||
|
|
||||||
## 9. CI/CD (GitHub Actions)
|
## 9. CI/CD (GitHub Actions)
|
||||||
@@ -174,7 +183,7 @@ Unverändert gegenüber v1:
|
|||||||
- **Weitere Quellen**: Google Contacts und Microsoft 365 nach
|
- **Weitere Quellen**: Google Contacts und Microsoft 365 nach
|
||||||
demselben Account-Muster (eigene `source`-Werte, eigene
|
demselben Account-Muster (eigene `source`-Werte, eigene
|
||||||
Sync-Strategie je Anbieter-API).
|
Sync-Strategie je Anbieter-API).
|
||||||
- **HTML-Mails, mehrere Empfänger je Kontakt, Vorlauf-Erinnerungen**
|
- **Mehrere Empfänger je Kontakt, Vorlauf-Erinnerungen**
|
||||||
(z. B. "in 3 Tagen") sind funktional einfach nachrüstbar, aktuell
|
(z. B. "in 3 Tagen") sind funktional einfach nachrüstbar, aktuell
|
||||||
aber nicht Teil des Scopes.
|
aber nicht Teil des Scopes.
|
||||||
|
|
||||||
@@ -191,10 +200,10 @@ geteilt wird. Getrennt ist nur die **Rolle**, in der der Container läuft.
|
|||||||
sowohl `src/sync.py`, `src/mailer.py` als auch das komplette
|
sowohl `src/sync.py`, `src/mailer.py` als auch das komplette
|
||||||
`src/api/`-Package.
|
`src/api/`-Package.
|
||||||
- `docker-compose.yml` definiert zwei Services aus demselben Image:
|
- `docker-compose.yml` definiert zwei Services aus demselben Image:
|
||||||
- `icloud-contacts-sync`: Standard-Entrypoint, startet `supercronic`
|
- `icloud-contacts-sync`: Standard-Entrypoint, startet den
|
||||||
mit Sync- und Mailer-Cron (unverändert zu v2).
|
Python-Scheduler (`scheduler.py`) mit Sync- und Mailer-Intervallen.
|
||||||
- `icloud-contacts-api`: überschreibt `command` komplett mit
|
- `icloud-contacts-api`: überschreibt `command` komplett mit
|
||||||
`uvicorn api.main:app`, ignoriert den Cron-Entrypoint des Images.
|
`uvicorn api.main:app`, ignoriert den Scheduler-Entrypoint des Images.
|
||||||
- Beide Services teilen sich dieselbe MariaDB und dieselbe
|
- Beide Services teilen sich dieselbe MariaDB und dieselbe
|
||||||
`config/accounts.json`, der API-Service greift ausschließlich lesend
|
`config/accounts.json`, der API-Service greift ausschließlich lesend
|
||||||
auf `contacts`, `sync_runs` zu, schreibt nichts.
|
auf `contacts`, `sync_runs` zu, schreibt nichts.
|
||||||
@@ -232,9 +241,10 @@ geteilt wird. Getrennt ist nur die **Rolle**, in der der Container läuft.
|
|||||||
| Endpunkt | Beschreibung |
|
| Endpunkt | Beschreibung |
|
||||||
|---|---|
|
|---|---|
|
||||||
| `GET /` | Einfache HTML-Übersicht (Jinja2-Template), zeigt Kontakte des zugeordneten Accounts |
|
| `GET /` | Einfache HTML-Übersicht (Jinja2-Template), zeigt Kontakte des zugeordneten Accounts |
|
||||||
|
| `GET /contacts/{id}` | HTML-Detailseite eines einzelnen Kontakts (Jinja2-Template) |
|
||||||
| `GET /api/health` | Health-Check ohne Auth-Anforderung |
|
| `GET /api/health` | Health-Check ohne Auth-Anforderung |
|
||||||
| `GET /api/contacts` | Kontaktliste, Filter `q` (Freitext), Pagination `limit`/`offset` |
|
| `GET /api/contacts` | Kontaktliste, Filter `q` (Freitext), Pagination `limit`/`offset` |
|
||||||
| `GET /api/contacts/{id}` | Einzelner Kontakt |
|
| `GET /api/contacts/{id}` | Einzelner Kontakt (JSON) |
|
||||||
| `GET /api/contacts/birthdays/today` | Heutige Geburtstage (kontospezifisch bzw. global für Admins) |
|
| `GET /api/contacts/birthdays/today` | Heutige Geburtstage (kontospezifisch bzw. global für Admins) |
|
||||||
| `GET /api/sync-runs` | Sync-Historie (kontospezifisch bzw. global für Admins) |
|
| `GET /api/sync-runs` | Sync-Historie (kontospezifisch bzw. global für Admins) |
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user