No results
This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
Decisions
Architectural and pattern decisions made during Chrysopedia development. Append-only — to reverse a decision, add a new entry that supersedes it.
Architecture Decisions
| # | When | Decision | Choice | Rationale |
|---|---|---|---|---|
| D001 | — | Storage layer selection | PostgreSQL + Qdrant + local filesystem | PostgreSQL for JSONB, Qdrant already running on hypervisor, filesystem for transcript JSON |
| D002 | — | Timestamp handling (asyncpg) | datetime.now(timezone.utc).replace(tzinfo=None) |
asyncpg rejects timezone-aware datetimes for TIMESTAMP WITHOUT TIME ZONE columns |
| D004 | — | Sync vs async in Celery tasks | Sync openai, QdrantClient, SQLAlchemy in Celery | Avoids nested event loop errors with gevent/eventlet workers |
| D005 | — | Embedding failure handling | Non-blocking — log errors, don't fail pipeline | Qdrant may be unreachable; core output (PostgreSQL) is preserved |
| D007 | M001/S04 | Review mode toggle persistence | Redis key chrysopedia:review_mode |
Redis already in stack; simpler than DB table for single boolean |
| D009 | M001/S05 | Search service pattern | Separate async SearchService for FastAPI | Keeps sync pipeline clients untouched; 300ms timeout + keyword fallback |
| D015 | M002/S01 | Docker network subnet | 172.32.0.0/24 | 172.24.0.0/24 was taken by xpltd_docs_default |
| D016 | M002/S01 | Embedding service | Ollama container (nomic-embed-text) | OpenWebUI doesn't serve /v1/embeddings |
| D017 | — | CSS theming | 77 semantic custom properties, cyan accent | Full variable-based palette for consistency and future theme switching |
| D018 | M004/S04 | Version snapshot failure handling | Best-effort — failure doesn't block page update | Follows D005 pattern for non-critical side effects |
| D019 | M005/S02 | Technique page layout | CSS grid 2-column (1fr + 22rem sidebar), 64rem max-width | Collapses at 768px; accommodates prose + sidebar |
| D023 | M012/S01 | Qdrant embedding text enrichment | Prepend creator_name, join topic_tags | Enables creator-name and tag-specific semantic search |
| D024 | M014/S01 | Sections with subsections content model | Empty-string content for parent sections | Avoids duplication; substance lives in subsection content fields |
| D025 | M015 | Search query storage | PostgreSQL search_log + Redis cache (5-min TTL) | Full history for analytics; Redis prevents DB hit on every homepage load |
Phase 2 Decisions
| # | Decision | Choice | Rationale |
|---|---|---|---|
| D031 | Phase 2 milestone structure | 8 milestones (M018–M025) with parallel frontend/backend slices | Maps to Sprint 0-8 plan; deploy gate per milestone |
| D032 | RAG framework | LightRAG + Qdrant + NetworkX (MVP) | Graph-enhanced retrieval; supports existing Qdrant; incremental updates |
| D033 | Monetization | Demo build with "Coming Soon" placeholders | Recruit creators first; Stripe Connect deferred to Phase 3 |
| D034 | Documentation strategy | Forgejo wiki, KB slice at end of every milestone | Incremental docs stay current; final pass in M025 |
| D035 | File/object storage | MinIO (S3-compatible) self-hosted | Docker-native, signed URLs, fits existing infrastructure |
Authentication & Infrastructure Decisions
| # | When | Decision | Choice | Rationale |
|---|---|---|---|---|
| D036 | M019/S02 | JWT auth configuration | HS256 with existing app_secret_key, 24h expiry, OAuth2PasswordBearer | Reuses existing secret; integrates with FastAPI dependency injection |
| D037 | — | Search impressions query | Exact case-insensitive title match via EXISTS subquery against SearchLog | MVP approach; expandable to ILIKE later |
| D038 | — | Primary git remote | git.xpltd.co (Forgejo) instead of github.com | Consolidating on self-hosted Forgejo; wiki already there |
Search & Retrieval Decisions
| # | When | Decision | Choice | Rationale |
|---|---|---|---|---|
| D039 | M021/S01 | LightRAG scoring strategy | Position-based (1.0 → 0.5 descending), sequential Qdrant fallback | /query/data has no numeric relevance score |
| D040 | M021/S02 | Creator-scoped retrieval | 4-tier cascade: creator → domain → global → none | Progressive widening; ll_keywords for soft scoping; 3x oversampling for post-filter survival |
M022 Decisions
| # | When | Decision | Choice | Rationale |
|---|---|---|---|---|
| D041 | M022/S05 | Highlight scorer weight distribution | 10 dimensions: original 7 reduced proportionally, 3 audio proxy dims get 0.22 total weight. Neutral fallback (0.5) when word_timings unavailable. | Audio proxy signals from word-level timing data; neutral fallback preserves backward compatibility |
UI/UX Decisions
| # | Decision | Choice |
|---|---|---|
| D014 | Creator equity | Random default sort; no creator privileged |
| D020 | Topics card differentiation | 3px colored left border + dot |
| D021 | M011 findings triage | 12/16 approved; denied beginner paths, YouTube links, hide admin, CTA label |
| D030 | ToC scroll-spy rootMargin | 0px 0px -70% 0px — active when in top 30% of viewport |
M023 Decisions
| # | When | Decision | Choice | Rationale |
|---|---|---|---|---|
| D042 | M023/S01 | Rich text editor for creator posts | Tiptap (headless, React) with StarterKit + Link + Placeholder. Store Tiptap JSON in JSONB column, render client-side via @tiptap/html. | Headless architecture fits dark theme customization. JSON storage is lossless and enables future server-side rendering. No HTML sanitization needed. |
| D043 | M023/S02 | Personality weight modulation strategy | 3-tier intensity (<0.4 subtle, 0.4–0.8 voice, ≥0.8 embody) with temperature scaling 0.3–0.5. Superseded by D044. | Initial stepped approach; replaced by continuous interpolation. |
| D044 | M023/S04 | Personality weight modulation strategy (revision) | 5-tier continuous interpolation. Progressive field inclusion: <0.2 no personality; 0.2+ tone; 0.4+ descriptors; 0.6+ phrases (count scaled); 0.8+ vocabulary/style; 0.9+ summary. Temperature: 0.3 + weight × 0.2. | 3-tier step function had jarring transitions. Continuous interpolation with progressive field inclusion gives finer control. 0.0–0.19 dead zone ensures purely encyclopedic mode. |
M025 Decisions
| # | When | Decision | Choice | Rationale |
|---|---|---|---|---|
| D045 | M025/S01 | Signed unsubscribe token library | PyJWT (already a dependency) over itsdangerous | Avoids adding a new dependency; PyJWT supports exp claims natively for self-expiring tokens |
| D046 | M025/S10 | Sticky section bar for technique pages | Built ReadingHeader with sentinel-based IntersectionObserver | Sticky elements never leave viewport for standard IO detection; sentinel div pattern solves this reliably |
| D047 | M025/S04 | Rate limiter failure mode | Fail-open (allow request on Redis error) | Availability over strictness for a single-admin platform; rate limiting is cost protection, not security |
| D048 | M025/S08 | LLM fallback strategy | Catch-and-retry with secondary client on transient errors | Matches sync LLMClient pipeline pattern; propagates fallback_used through SSE and usage logging |
See also: Architecture, Development-Guide
Chrysopedia Wiki
Architecture
Features
- Chat-Engine
- Search-Retrieval
- Highlights
- Personality-Profiles
- Posts (via Post Editor)
Reference
Operations