docs(02-01): complete config loader & Gemini API client plan

- SUMMARY.md with 18 tests, 6 files, 3min execution
- STATE.md advanced to plan 2/5, 70% progress
- ROADMAP.md updated with plan progress
- Requirements GAPI-01, GAPI-02, GAPI-03, GAPI-06 marked complete

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-03-29 11:57:53 +02:00
co-authored by Claude Opus 4.6
parent 2bea324962
commit c268c6050e
4 changed files with 154 additions and 15 deletions
@@ -0,0 +1,135 @@
---
phase: 02-gemini-integration-asset-pipeline
plan: 01
subsystem: api
tags: [gemini, rest-api, fetch, indexeddb, rate-limiting, config-loader]
# Dependency graph
requires:
- phase: 01-grundgeruest-tippmechanik
provides: "IndexedDB wrapper (openDB, getSettings, saveSettings) and Settings type"
provides:
- "GeminiConfig interface and loadConfig() with caching"
- "generateText() with 3x exponential backoff retry"
- "generateImage() with reference image support as base64 inlineData"
- "checkRateLimit() and incrementApiCall() for daily API call tracking"
- "Extended Settings type with apiCallsToday and lastApiCallDate"
affects: [02-02, 02-03, 02-04, 02-05, asset-pipeline, companion-system, forest-rewards]
# Tech tracking
tech-stack:
added: []
patterns: [gemini-rest-client, exponential-backoff-retry, config-caching, rate-limit-via-settings-store]
key-files:
created:
- src/api/config.ts
- src/api/config.test.ts
- src/api/gemini.ts
- src/api/gemini.test.ts
modified:
- src/types.ts
- src/storage/db.test.ts
key-decisions:
- "Rate limiting stored in Settings singleton via getSettings/saveSettings (no new store)"
- "Image generation has no retry (too expensive), text generation retries 3x with [1s, 2s, 4s] backoff"
- "Config loader caches after first successful fetch, resetConfigCache() for testing"
- "loadConfigFromObject() provided for Node.js build script usage"
patterns-established:
- "Gemini REST pattern: POST to v1beta/models/{model}:generateContent with key param"
- "Null-return pattern: all API functions return null on failure, callers use fallback"
- "Daily reset pattern: compare lastApiCallDate to today, reset counters if different"
requirements-completed: [GAPI-01, GAPI-02, GAPI-03, GAPI-06]
# Metrics
duration: 3min
completed: 2026-03-29
---
# Phase 02 Plan 01: Config Loader & Gemini API Client Summary
**Isomorphic Gemini REST client with config caching, text/image generation, exponential backoff retry, and per-day rate limiting via IndexedDB Settings store**
## Performance
- **Duration:** 3 min
- **Started:** 2026-03-29T09:52:49Z
- **Completed:** 2026-03-29T09:56:41Z
- **Tasks:** 1 (TDD: RED + GREEN)
- **Files modified:** 6
## Accomplishments
- Config loader fetches and caches public/config.json with typed GeminiConfig interface
- generateText sends correct Gemini REST request with systemInstruction, retries 3x on failure with exponential backoff [1s, 2s, 4s]
- generateImage converts reference Blobs to base64 inlineData parts, sets responseModalities: ["IMAGE"]
- Rate limiting tracks text/image API calls per day in Settings store with automatic daily reset
- 18 tests across config.test.ts and gemini.test.ts, all passing (55 total project tests)
## Task Commits
Each task was committed atomically:
1. **Task 1 (RED): Failing tests** - `b31b9fd` (test)
2. **Task 1 (GREEN): Implementation** - `2bea324` (feat)
_TDD task with RED (failing tests) and GREEN (implementation) commits._
## Files Created/Modified
- `src/api/config.ts` - GeminiConfig interface, loadConfig() with caching, resetConfigCache()
- `src/api/config.test.ts` - 6 tests for config loader (fetch, errors, caching)
- `src/api/gemini.ts` - generateText(), generateImage(), checkRateLimit(), incrementApiCall()
- `src/api/gemini.test.ts` - 12 tests for text/image generation and rate limiting
- `src/types.ts` - Extended Settings with apiCallsToday and lastApiCallDate
- `src/storage/db.test.ts` - Updated Settings test fixture with new fields
## Decisions Made
- Rate limiting stored in existing Settings singleton (no new IndexedDB store needed)
- Image generation has no retry logic (too expensive per plan spec), only text retries
- Config loader includes loadConfigFromObject() for future Node.js build script usage
- Blob-to-base64 conversion uses arrayBuffer + manual binary encoding (no FileReader needed)
## Deviations from Plan
### Auto-fixed Issues
**1. [Rule 1 - Bug] Fixed TypeScript strict null errors in array indexing**
- **Found during:** Task 1 GREEN phase
- **Issue:** TypeScript strict mode flagged RETRY_DELAYS[attempt] and split("T")[0] as possibly undefined
- **Fix:** Added nullish coalescing fallbacks (e.g., `?? 1000`, `?? ""`)
- **Files modified:** src/api/gemini.ts, src/api/gemini.test.ts
- **Verification:** `npx tsc --noEmit` passes for all api/ files
- **Committed in:** 2bea324
**2. [Rule 1 - Bug] Updated db.test.ts Settings fixture for extended type**
- **Found during:** Task 1 GREEN phase
- **Issue:** Existing db.test.ts Settings object missing new apiCallsToday and lastApiCallDate fields
- **Fix:** Added missing fields to test fixture
- **Files modified:** src/storage/db.test.ts
- **Verification:** All 55 tests pass
- **Committed in:** 2bea324
---
**Total deviations:** 2 auto-fixed (2 bugs)
**Impact on plan:** Both fixes required for type safety and test correctness. No scope creep.
## Issues Encountered
- Pre-existing TypeScript errors in src/companion/fallbacks.ts (not caused by this plan, out of scope)
## Known Stubs
None - all functions are fully implemented with real logic.
## User Setup Required
None - no external service configuration required.
## Next Phase Readiness
- Gemini API client ready for use by prompt templates (02-02), image pipeline (02-03), and companion dialog (02-04)
- Config must exist at public/config.json with geminiApiKey, geminiModel, imageModel fields
- No blockers for subsequent plans
---
*Phase: 02-gemini-integration-asset-pipeline*
*Completed: 2026-03-29*