Files
oikos/PROGRESS.md
T
Ulas Kalayci fe0254e225 docs: update PROGRESS.md - all 15 tasks completed
Tasks 14-15 documentation:
- Task 14: OpenAPI routes documented (d0eb638)
- Task 15: CardDAV router mounted (8891097)

All 109 tests passing across 20 suites.
Implementation ready for final review and release.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-05-04 18:39:19 +02:00

14 KiB

CardDAV API Routes Implementation - Fortschritt

Stand: 2026-05-04, alle 15 Tasks abgeschlossen Plan: docs/superpowers/plans/2026-05-04-cardav-api-routes.md Status: Implementierung vollständig, bereit für Final Review

Abgeschlossene Tasks

Task 1: Multi-Value Array Validators

Commit: a715475 + 930800e (fixes)

  • Implementiert: validatePhones(), validateEmails(), validateAddresses()
  • Location: server/routes/contacts.js
  • Tests: 33 neue Tests in test-carddav.js
  • Validierungen: Arrays, Objekt-Struktur, Pflichtfelder, Max-Längen, Email-Format, isPrimary-Typ, Array-Länge (max 20)

Review-Findings & Fixes:

  • Spec Compliance: Minor extras (logging) - akzeptabel
  • Code Quality Issues behoben:
    • Whitespace-Validierung ergänzt
    • Null-Guards hinzugefügt
    • Email-Format-Check ergänzt
    • isPrimary Typ-Validierung
    • DoS-Schutz: Array-Länge begrenzt auf 20

Task 2: CardDAV Router Setup

Commits: cf68bff, 930800e

  • Erstellt: server/routes/cardav.js mit Express Router
  • Implementiert: GET /accounts Endpoint
  • Test-Infrastruktur:
    • _setTestDatabase() / _resetTestDatabase() in server/db.js
    • before()/after() Hooks in test-carddav.js
    • Migration 30 wird in Tests angewendet
  • Tests: 2 Tests (empty array, populated with shape validation)

Review-Findings & Fixes:

  • Unused imports entfernt (wurden für Task 3 wieder gebraucht)
  • Error-Message leakage behoben (generic "Interner Fehler")
  • Test-Cleanup mit after() Hook
  • after aus node:test importiert

Task 3: POST /accounts - Create Account

Commit: f7eb73b

  • Implementiert: POST /accounts mit Validation
  • Validierung: name, cardavUrl, username, password (alle required, mit max lengths)
  • Delegiert an: CardDAVSync.addAccount()
  • Response: 201 mit { account, addressbooks }
  • Tests: 2 Tests (success case, validation failure)

Test-Mocking:

  • _mockTestConnection() in cardav-sync.js hinzugefügt
  • Mock gibt fake addressbooks zurück für Tests
  • Mock wird in before() gesetzt, in after() zurückgesetzt

Wichtige Änderung:

  • addAccount() Return-Wert geändert von { accountId, addressbooks } zu { account: { id, name, cardavUrl, username, createdAt, lastSync }, addressbooks }

Task 4: DELETE /accounts/:id - Delete Account

Commit: ca92cb2

  • Implementiert: DELETE /accounts/:id mit ID-Validierung
  • Validierung: ID muss positive Ganzzahl sein
  • Delegiert an: CardDAVSync.deleteAccount(id)
  • Response: 200 mit { deleted: true }
  • Tests: 2 Tests (success case mit cascade, invalid ID → 400)
  • CASCADE-Verhalten: Foreign Key Constraints löschen addressbooks + contacts automatisch

Task 5: POST /accounts/:id/test - Test Connection

Commit: dd5ac88

  • Implementiert: POST /accounts/:id/test mit ID-Validierung
  • Lädt Account aus DB (404 wenn nicht gefunden)
  • Delegiert an: CardDAVSync.testConnection(url, username, password)
  • Response: 200 mit { ok, addressbooks }
  • Test: 1 Test (success case mit addressbooks)
  • Verwendet gemockten testConnection für konsistente Test-Results

Task 6: GET /accounts/:id/addressbooks - List Addressbooks

Commit: 12e8edf

  • Implementiert: GET /accounts/:id/addressbooks mit ID-Validierung
  • Query: carddav_addressbook_selection table, ORDER BY addressbook_name
  • Response: 200 mit Array von { id, url, name, enabled }
  • Tests: 2 Tests (success case mit shape validation, empty array für non-existent account)

Task 7: POST /accounts/:id/addressbooks/refresh - Refresh Addressbooks

Commit: c078a48

  • Implementiert: POST /accounts/:id/addressbooks/refresh mit ID-Validierung
  • Lädt Account aus DB (404 wenn nicht gefunden)
  • Delegiert an: CardDAVSync.discoverAddressbooks(accountId) für PROPFIND
  • Query updated addressbooks nach Discovery
  • Response: 200 mit Array von addressbooks
  • Test: 1 Test (success case)

Task 8: Add bool Validator

Commit: 362f711

  • Implementiert: bool(val, field) Validator in server/middleware/validate.js
  • Validiert: type === 'boolean', required by default
  • Exportiert: bool in export statement
  • Keine Tests (wird in Task 9 verwendet)

Task 9: PUT /addressbooks/:id - Toggle Addressbook

Commit: 9ec7fda

  • Implementiert: PUT /addressbooks/:id Route in server/routes/cardav.js
  • Validierung: ID muss positive Ganzzahl sein, enabled muss boolean sein
  • Delegiert an: CardDAVSync.toggleAddressbook(id, enabled)
  • Response: 200 mit { updated: true, enabled: boolean }
  • Tests: 2 Tests (success case mit toggle, validation failure für invalid enabled)
  • bool Validator verwendet

Task 10: POST /accounts/:id/sync - Sync Account

Commit: 674fe79

  • Implementiert: POST /accounts/:id/sync Route in server/routes/cardav.js
  • Validierung: ID muss positive Ganzzahl sein
  • Lädt Account aus DB (404 wenn nicht gefunden)
  • Delegiert an: CardDAVSync.syncAccount(accountId)
  • Response: 200 mit { synced, contactsAdded, contactsUpdated }
  • Tests: 2 Tests (success case, 404 für non-existent account)
  • Mock: _mockSyncAccount() für Tests hinzugefügt (Pattern wie _mockTestConnection)

Task 11: GET /contacts/:id - With Multi-Value Fields

Commit: fe8af33

  • Implementiert: GET /contacts/:id Route in server/routes/contacts.js
  • Queries: Separate Abfragen für contact_phones, contact_emails, contact_addresses
  • Mapping: is_primary (Integer DB) → isPrimary (Boolean Response), snake_case → camelCase
  • Sortierung: ORDER BY is_primary DESC, id ASC (Primary-Einträge zuerst)
  • Response-Format: { ...contact, phones: [], emails: [], addresses: [] }
  • Tests: 2 neue Tests
    • Contact mit allen Multi-Value Fields (phones, emails, addresses)
    • Contact ohne Multi-Value Fields (leere Arrays)
  • TDD-Workflow eingehalten: RED → GREEN → Commit

Task 12: POST /contacts - Create With Multi-Value Fields

Commit: 966a6d4

  • Implementiert: POST /contacts erweitert um phones, emails, addresses Arrays
  • Validierung: validatePhones(), validateEmails(), validateAddresses() vor Insert
  • Transaktionen: db.transaction() für atomare Contact + Multi-Values Inserts
  • Backward Compatible: Optional fields, leere Arrays wenn nicht angegeben
  • Response: Contact mit allen Multi-Value Fields inkl. generierte IDs
  • Tests: 3 neue Tests
    • Contact mit allen Multi-Value Fields erstellen
    • Validierung: Fehler bei invaliden Phone-Daten (400)
    • Backward Compatibility: Contact ohne Multi-Values (leere Arrays)
  • Refactoring: loadMultiValueFields(contactId) Helper extrahiert (DRY)
  • TDD-Workflow eingehalten: RED → GREEN → REFACTOR → Commit

Task 13: PUT /contacts/:id - Update With Multi-Value Fields

Commit: 0dc303b

  • Implementiert: PUT /contacts/:id erweitert um phones, emails, addresses Arrays
  • Validierung: validatePhones(), validateEmails(), validateAddresses() vor Update
  • Replacement-Semantik: DELETE alle existierenden Multi-Values, dann INSERT neue
  • Transaktionen: db.transaction() für atomare Contact + Multi-Values Updates
  • Backward Compatible: Multi-Value Fields nur ersetzt wenn im Body vorhanden
  • Response: Contact mit allen Multi-Value Fields via loadMultiValueFields()
  • Tests: 3 neue Tests
    • Update mit Multi-Value Fields (Replacement-Semantik verifiziert)
    • Validierung: Fehler bei invaliden Phone-Daten (400)
    • Backward Compatibility: Update ohne Multi-Values lässt sie unverändert
  • TDD-Workflow eingehalten: RED → Verify RED → GREEN → Verify GREEN → Commit

Task 14: OpenAPI Documentation

Commit: d0eb638

  • Dokumentiert: Alle 8 CardDAV Management Routes in server/openapi.js
    • GET /api/v1/contacts/cardav/accounts
    • POST /api/v1/contacts/cardav/accounts
    • DELETE /api/v1/contacts/cardav/accounts/{id}
    • POST /api/v1/contacts/cardav/accounts/{id}/test
    • GET /api/v1/contacts/cardav/accounts/{id}/addressbooks
    • POST /api/v1/contacts/cardav/accounts/{id}/addressbooks/refresh
    • PUT /api/v1/contacts/cardav/addressbooks/{id}
    • POST /api/v1/contacts/cardav/accounts/{id}/sync
  • Aktualisiert: Bestehende Contacts-Routes mit Multi-Value-Beschreibungen
    • POST /api/v1/contacts: "Create contact with multi-value fields"
    • GET /api/v1/contacts/{id}: "Get contact with multi-value fields"
    • PUT /api/v1/contacts/{id}: "Update contact with multi-value fields"
  • Alle Routes mit korrektem Tag ('Contacts'), CSRF-Header-Params für stateChanging
  • OpenAPI Schema baut ohne Fehler

Task 15: Mount CardDAV Router

Commit: 8891097

  • Import hinzugefügt: import cardavRouter from './routes/cardav.js'
  • Router gemountet: app.use('/api/v1/contacts/cardav', cardavRouter)
  • Montage-Reihenfolge: CardDAV-Router VOR Contacts-Router (Express route matching order)
  • Auth-Middleware: Bereits global angewendet via requireAuth in index.js
  • CSRF-Middleware: Automatisch über stateChanging-Flag in OpenAPI + CSRF-Middleware
  • Integration Tests: Alle 109 Tests bestehen (20 Suites)
  • Server startet erfolgreich auf Port 3000

Wichtige Erkenntnisse

Test-Infrastruktur

  1. DB-Mocking: _setTestDatabase() / _resetTestDatabase() in db.js
  2. CardDAV-Mocking: _mockTestConnection() in cardav-sync.js
  3. before()/after() Pattern: Setup in before(), Cleanup in after()
  4. Migration 30: Muss in jedem Test-Setup angewendet werden für CardDAV-Tabellen

Code-Patterns

  1. Error-Handling: Immer generic "Interner Fehler", niemals err.message leaken
  2. Validation: str(), collectErrors(), MAX_TITLE (100), MAX_URL (500)
  3. Response-Format: { data: ... } für Success, { error: ..., code: ... } für Fehler
  4. Status Codes: 200 (GET), 201 (POST create), 400 (validation), 500 (server error)

Konventionen

  • Tests nutzen Node built-in test runner (node:test)
  • Test-DB ist in-memory SQLite (:memory:)
  • Commits mit Co-Authored-By: Claude Sonnet 4.5
  • TDD-Workflow: Test → Run (fail) → Implement → Run (pass) → Commit

Zusammenfassung

Alle 15 Tasks vollständig implementiert:

  • Phase 0: Setup & Validators (Tasks 1-2)
  • Phase 1: Account Management Routes (Tasks 3-4)
  • Phase 2: Connection & Discovery Routes (Tasks 5-7)
  • Phase 3: Toggle & Sync Routes (Tasks 8-10)
  • Phase 4: Extended Contacts Routes (Tasks 11-13)
  • Phase 5: OpenAPI Integration (Task 14)
  • Phase 6: Server Integration (Task 15)

Nächste Schritte:

  1. Final Code Review (optional)
  2. Release Prep via /release-prep Skill
  3. Merge in main Branch

Commits-Übersicht

a715475 feat(contacts): add multi-value array validators
cf68bff feat(cardav): create cardav router with GET /accounts
930800e fix(cardav): improve router security and test coverage
f7eb73b feat(cardav): implement POST /accounts endpoint
ca92cb2 feat(cardav): implement DELETE /accounts/:id endpoint
38fa84c docs: update PROGRESS.md for completed Task 4
dd5ac88 feat(cardav): implement POST /accounts/:id/test endpoint
2964696 docs: update PROGRESS.md for completed Task 5
12e8edf feat(cardav): implement GET /accounts/:id/addressbooks endpoint
c078a48 feat(cardav): implement POST /accounts/:id/addressbooks/refresh endpoint
362f711 feat(validate): add bool validator
9ec7fda feat(cardav): implement PUT /addressbooks/:id endpoint
674fe79 feat(cardav): implement POST /accounts/:id/sync endpoint
fe8af33 feat(contacts): extend GET /contacts/:id with multi-value fields
966a6d4 feat(contacts): extend POST /contacts with multi-value fields
0dc303b feat(contacts): extend PUT /contacts/:id with multi-value fields
d0eb638 docs(openapi): add CardDAV routes and update contacts routes
8891097 feat(server): mount CardDAV router at /api/v1/contacts/cardav

Test-Status

  • Gesamt: 109 Tests, alle bestehen
  • Suites: 20 Suites
  • CardDAV API Routes Suite: 14 Tests
  • Contacts API - Multi-Value Fields Suite: 8 Tests
    • GET /contacts/🆔 2 Tests
    • POST /contacts: 3 Tests
    • PUT /contacts/🆔 3 Tests
    • Account Management (6 Tests):
      • GET /accounts (empty)
      • GET /accounts (populated with shape)
      • POST /accounts (success)
      • POST /accounts (validation failure)
      • DELETE /accounts/:id (success with cascade)
      • DELETE /accounts/:id (invalid ID → 400)
    • Connection & Discovery (4 Tests):
      • POST /accounts/:id/test (success)
      • GET /accounts/:id/addressbooks (success with addressbooks)
      • GET /accounts/:id/addressbooks (empty array)
      • POST /accounts/:id/addressbooks/refresh (success)
    • Addressbook Management (2 Tests):
      • PUT /addressbooks/:id (toggle enabled/disabled)
      • PUT /addressbooks/:id (validation failure)
    • Sync (2 Tests):
      • POST /accounts/:id/sync (success)
      • POST /accounts/:id/sync (404 for non-existent account)

Branch & Remote

  • Branch: feature/cardav-contacts
  • Worktree: /home/ulsklyc/Workspace/oikos/.worktrees/feature/cardav-contacts
  • Base: main (commit 6cc7267)
  • Bereit zum Pushen: Ja, nach diesem Status-Commit

Task-Liste Status

#1. [completed] Task 1: Multi-Value Array Validators
#2. [completed] Task 2: CardDAV Router Setup
#3. [completed] Task 3: POST /accounts - Create Account
#4. [completed] Task 4: DELETE /accounts/:id - Delete Account
#5. [completed] Task 5: POST /accounts/:id/test - Test Connection
#6. [completed] Task 6: GET /accounts/:id/addressbooks - List Addressbooks
#7. [completed] Task 7: POST /accounts/:id/addressbooks/refresh - Refresh Addressbooks
#8. [completed] Task 8: Add bool validator to validate.js
#9. [completed] Task 9: PUT /addressbooks/:id - Toggle Addressbook
#10. [completed] Task 10: POST /accounts/:id/sync - Sync Account
#11. [completed] Task 11: GET /contacts/:id - With Multi-Values
#12. [completed] Task 12: POST /contacts - Create With Multi-Values
#13. [completed] Task 13: PUT /contacts/:id - Update With Multi-Values
#14. [completed] Task 14: Document All Routes in OpenAPI
#15. [completed] Task 15: Mount CardDAV Router

Alle 15 Tasks abgeschlossen! 🎉