Move early lessons (fixes baked into codebase) to docs/LESSONS-ARCHIVE.md. Condense lessons 41-65 to one-liners. Reduces system prompt token usage by ~34% while preserving all actively relevant context. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
4.9 KiB
Lessons Archive (1-40)
These lessons were originally in CLAUDE.md. They've been archived because the fixes are now baked into the codebase. Consult this file if you encounter a regression in any of these areas.
1. DateTime Handling — Always timezone-aware: Column(DateTime(timezone=True), default=lambda: datetime.now(timezone.utc)). NEVER use datetime.utcnow().
2. SQLAlchemy Async — No lazy loading on new objects: Use direct SQL for junction tables: await db.execute(tree_tag_assignments.insert().values(...)).
3. React State — Don't store object snapshots: Store IDs, derive objects: const editingNode = editingNodeId ? findNode(editingNodeId, tree?.tree_structure) : null.
4. Modal Draft State — Exclude store-managed fields: const { children, ...draftWithoutChildren } = draft; updateNode(node.id, draftWithoutChildren).
5. Multiple FKs to same table: Specify foreign_keys on BOTH sides: author = relationship("User", foreign_keys=[author_id], back_populates="trees").
6. PostgreSQL NULL in UUID columns: SELECT 'tag', 'slug', NULL::uuid as team_id — must cast NULL to uuid.
7. API Path Gotcha: Frontend apiClient baseURL is http://localhost:8000/api/v1 — use relative paths WITHOUT /api/v1/ prefix. Invite codes endpoint is /invites (NOT /invite-codes).
8. CORS errors can mask 500s: Check backend logs first. Also run alembic upgrade head after pulling changes.
9. Public endpoints with optional auth: Use manual _get_optional_user(request, db) helper, NOT Optional[User] param.
10. React Router — Clear dirty state before navigation: markSaved() before navigate().
11. CORS expose_headers for custom response headers: Must be set in BOTH CORS branches in main.py.
12. TreeStructure vs Tree types: TreeStructure is for node structure only — it does NOT have tree_type, name, etc. Those are on Tree.
13. Login redirect state format: navigate('/login', { state: { from: { pathname: '/path' } } }) — expects state.from.pathname (object), NOT a plain string.
14. Type-aware routing: Always use getTreeNavigatePath(treeId, treeType) from @/lib/routing. Procedural flows use /flows/:id/navigate.
15. Session sharing types: Use tree_snapshot?.tree_type to determine flow type from session data.
16. tree_type has three values: 'troubleshooting' | 'procedural' | 'maintenance'. Use PROCEDURAL_TREE_TYPES set when checking for step-based flow types.
17. Alembic autogenerate can be destructive: Always review generated migrations. Prefer manual migrations for new tables.
18. Pydantic partial updates — use model_fields_set: Check data.model_fields_set to distinguish "field not sent" from "field sent as null".
19. gh pr merge fails with worktrees: Use the API: gh api repos/ORG/REPO/pulls/N/merge --method PUT --field merge_method=squash.
20. 'answer' node type in TreeStructure: Transient stub type used only in the canvas editor. Must explicitly handle in any node.type switch.
21. Test fixtures in conftest.py: client, test_db, test_user, auth_headers, test_tree, test_admin, admin_auth_headers. NO async_client or engineer_token.
22. Worktree venv path: Use backend/venv/bin/python -m pytest ... from the worktree directory.
23. Action nodes navigate via next_node_id, not children: Must set next_node_id on action nodes for AI generation or manual editing.
24. Anthropic model IDs: Both alias (claude-sonnet-4-6) and dated forms work. Default: claude-sonnet-4-6.
25. Claude API may wrap JSON responses in markdown fences: Always strip fences before parsing. See _strip_markdown_fences().
26. sessionsApi.list supports batch_id filter.
27. Maintenance batch sessions are created all-at-once at launch.
28. AI tests in CI need ai_enabled mock: Mock settings.ai_enabled = True via PropertyMock. See tests/test_ai_chat.py.
29. ESLint no-unused-vars has no argsIgnorePattern: Use // eslint-disable-next-line or remove the param.
30. Alembic env.py must import all models.
31. JSONB fields — convert datetime to .isoformat() string.
32. Export pipeline order matters: Generate → resolve variables → apply redaction. Redaction MUST run last.
33. Railway: DATABASE_URL_SYNC is a property, not an env var.
34. Railway: run migrations in Docker CMD, not releaseCommand.
35. bcrypt==4.0.1 pinned for passlib compatibility.
36. Email validator rejects .local TLD: Use example.com for test/seed emails.
37. First deployed user needs manual admin promotion via SQL.
38. Alembic migrations MUST use sequential numbered prefixes: Always pass --rev-id flag.
39. Platform settings for feature toggles: Use SettingsManager.get("key", db, default=True).
40. Survey public routes: Add at top level in router.tsx alongside /login.