keble-tiktok 0.5.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (161) hide show
  1. keble_tiktok-0.5.0/.cursor/rules/agents.mdc +14 -0
  2. keble_tiktok-0.5.0/.cursor/rules/i18n.mdc +36 -0
  3. keble_tiktok-0.5.0/.cursor/rules/language.mdc +24 -0
  4. keble_tiktok-0.5.0/.cursor/rules/minimal-change-first.mdc +175 -0
  5. keble_tiktok-0.5.0/.cursor/rules/no-try-except.mdc +10 -0
  6. keble_tiktok-0.5.0/.cursor/rules/provider-integration.mdc +99 -0
  7. keble_tiktok-0.5.0/.cursor/rules/pytest-db-cleanup.mdc +9 -0
  8. keble_tiktok-0.5.0/.cursor/rules/python-standards.mdc +48 -0
  9. keble_tiktok-0.5.0/.cursor/rules/typescript-standards.mdc +15 -0
  10. keble_tiktok-0.5.0/.env.example +10 -0
  11. keble_tiktok-0.5.0/.gitattributes +2 -0
  12. keble_tiktok-0.5.0/.gitignore +41 -0
  13. keble_tiktok-0.5.0/AGENTS.md +98 -0
  14. keble_tiktok-0.5.0/AiAgentChangesLogs.md +1048 -0
  15. keble_tiktok-0.5.0/PKG-INFO +82 -0
  16. keble_tiktok-0.5.0/README.md +65 -0
  17. keble_tiktok-0.5.0/docs/architecture/echotik-current-handoff.md +118 -0
  18. keble_tiktok-0.5.0/docs/architecture/echotik-multiprovider-roadmap.md +158 -0
  19. keble_tiktok-0.5.0/docs/architecture/echotik-phase6-product-influencer-plan.md +372 -0
  20. keble_tiktok-0.5.0/docs/architecture/tiktok-api-capability-map.md +703 -0
  21. keble_tiktok-0.5.0/docs/architecture/tiktok-domain-impl.md +602 -0
  22. keble_tiktok-0.5.0/docs/architecture/tiktok-ranking-phase-plan.md +417 -0
  23. keble_tiktok-0.5.0/docs/providers/echotik/api-docs/influencer-ranklist.md +182 -0
  24. keble_tiktok-0.5.0/docs/providers/echotik/api-docs/product-influencer-list.md +177 -0
  25. keble_tiktok-0.5.0/docs/providers/echotik/api-docs/product-list.md +220 -0
  26. keble_tiktok-0.5.0/docs/providers/echotik/api-docs/seller-ranklist.md +137 -0
  27. keble_tiktok-0.5.0/docs/providers/echotik/echotik-capability-audit.md +341 -0
  28. keble_tiktok-0.5.0/docs/providers/fastmoss/fastmoss-capability-audit.md +319 -0
  29. keble_tiktok-0.5.0/keble_tiktok/__init__.py +1 -0
  30. keble_tiktok-0.5.0/keble_tiktok/batching.py +52 -0
  31. keble_tiktok-0.5.0/keble_tiktok/cache.py +311 -0
  32. keble_tiktok-0.5.0/keble_tiktok/commerce_provider.py +256 -0
  33. keble_tiktok-0.5.0/keble_tiktok/creator_ranking_provider.py +161 -0
  34. keble_tiktok-0.5.0/keble_tiktok/domain/__init__.py +4 -0
  35. keble_tiktok-0.5.0/keble_tiktok/domain/creator.py +63 -0
  36. keble_tiktok-0.5.0/keble_tiktok/domain/creator_ranking.py +137 -0
  37. keble_tiktok-0.5.0/keble_tiktok/domain/details.py +58 -0
  38. keble_tiktok-0.5.0/keble_tiktok/domain/listing.py +31 -0
  39. keble_tiktok-0.5.0/keble_tiktok/domain/metric.py +133 -0
  40. keble_tiktok-0.5.0/keble_tiktok/domain/offer.py +35 -0
  41. keble_tiktok-0.5.0/keble_tiktok/domain/product.py +23 -0
  42. keble_tiktok-0.5.0/keble_tiktok/domain/query.py +36 -0
  43. keble_tiktok-0.5.0/keble_tiktok/domain/ranking.py +153 -0
  44. keble_tiktok-0.5.0/keble_tiktok/domain/relation.py +150 -0
  45. keble_tiktok-0.5.0/keble_tiktok/domain/seller_ranking.py +167 -0
  46. keble_tiktok-0.5.0/keble_tiktok/domain/shop.py +23 -0
  47. keble_tiktok-0.5.0/keble_tiktok/domain/video.py +82 -0
  48. keble_tiktok-0.5.0/keble_tiktok/mapping/__init__.py +1 -0
  49. keble_tiktok-0.5.0/keble_tiktok/mapping/to_commerce.py +724 -0
  50. keble_tiktok-0.5.0/keble_tiktok/mapping/video_to_commerce.py +191 -0
  51. keble_tiktok-0.5.0/keble_tiktok/ports/__init__.py +4 -0
  52. keble_tiktok-0.5.0/keble_tiktok/ports/creator_ranking_source.py +34 -0
  53. keble_tiktok-0.5.0/keble_tiktok/ports/product_ranking_source.py +34 -0
  54. keble_tiktok-0.5.0/keble_tiktok/ports/product_source.py +33 -0
  55. keble_tiktok-0.5.0/keble_tiktok/ports/product_video_source.py +34 -0
  56. keble_tiktok-0.5.0/keble_tiktok/ports/relation_source.py +38 -0
  57. keble_tiktok-0.5.0/keble_tiktok/ports/seller_ranking_source.py +32 -0
  58. keble_tiktok-0.5.0/keble_tiktok/providers/__init__.py +1 -0
  59. keble_tiktok-0.5.0/keble_tiktok/providers/crawler/__init__.py +9 -0
  60. keble_tiktok-0.5.0/keble_tiktok/providers/crawler/client.py +109 -0
  61. keble_tiktok-0.5.0/keble_tiktok/providers/crawler/mapper.py +56 -0
  62. keble_tiktok-0.5.0/keble_tiktok/providers/crawler/product_source.py +56 -0
  63. keble_tiktok-0.5.0/keble_tiktok/providers/echotik/__init__.py +8 -0
  64. keble_tiktok-0.5.0/keble_tiktok/providers/echotik/client.py +598 -0
  65. keble_tiktok-0.5.0/keble_tiktok/providers/echotik/creator_ranking_source.py +203 -0
  66. keble_tiktok-0.5.0/keble_tiktok/providers/echotik/dates.py +78 -0
  67. keble_tiktok-0.5.0/keble_tiktok/providers/echotik/errors.py +112 -0
  68. keble_tiktok-0.5.0/keble_tiktok/providers/echotik/mapper.py +452 -0
  69. keble_tiktok-0.5.0/keble_tiktok/providers/echotik/models.py +408 -0
  70. keble_tiktok-0.5.0/keble_tiktok/providers/echotik/product_ranking_source.py +198 -0
  71. keble_tiktok-0.5.0/keble_tiktok/providers/echotik/relation_source.py +136 -0
  72. keble_tiktok-0.5.0/keble_tiktok/providers/echotik/seller_ranking_source.py +190 -0
  73. keble_tiktok-0.5.0/keble_tiktok/providers/echotik/video_source.py +133 -0
  74. keble_tiktok-0.5.0/keble_tiktok/providers/fastmoss/__init__.py +1 -0
  75. keble_tiktok-0.5.0/keble_tiktok/providers/fastmoss/client.py +345 -0
  76. keble_tiktok-0.5.0/keble_tiktok/providers/fastmoss/creator_ranking_source.py +143 -0
  77. keble_tiktok-0.5.0/keble_tiktok/providers/fastmoss/errors.py +132 -0
  78. keble_tiktok-0.5.0/keble_tiktok/providers/fastmoss/mapper.py +711 -0
  79. keble_tiktok-0.5.0/keble_tiktok/providers/fastmoss/models.py +776 -0
  80. keble_tiktok-0.5.0/keble_tiktok/providers/fastmoss/product_ranking_source.py +136 -0
  81. keble_tiktok-0.5.0/keble_tiktok/providers/fastmoss/product_source.py +57 -0
  82. keble_tiktok-0.5.0/keble_tiktok/providers/fastmoss/relation_source.py +109 -0
  83. keble_tiktok-0.5.0/keble_tiktok/relation_provider.py +132 -0
  84. keble_tiktok-0.5.0/keble_tiktok/seller_ranking_provider.py +127 -0
  85. keble_tiktok-0.5.0/keble_tiktok/services.py +456 -0
  86. keble_tiktok-0.5.0/keble_tiktok/testing/__init__.py +5 -0
  87. keble_tiktok-0.5.0/keble_tiktok/testing/config.py +20 -0
  88. keble_tiktok-0.5.0/keble_tiktok/video_provider.py +82 -0
  89. keble_tiktok-0.5.0/pyproject.toml +74 -0
  90. keble_tiktok-0.5.0/tests/conftest.py +32 -0
  91. keble_tiktok-0.5.0/tests/contract/architecture/test_provider_shape_boundary.py +145 -0
  92. keble_tiktok-0.5.0/tests/contract/ports/test_creator_ranking_source_contract.py +175 -0
  93. keble_tiktok-0.5.0/tests/contract/ports/test_product_ranking_source_contract.py +210 -0
  94. keble_tiktok-0.5.0/tests/contract/ports/test_product_source_contract.py +237 -0
  95. keble_tiktok-0.5.0/tests/contract/test_commerce_provider.py +479 -0
  96. keble_tiktok-0.5.0/tests/contract/test_commerce_provider_contract.py +297 -0
  97. keble_tiktok-0.5.0/tests/contract/test_commerce_provider_ranking.py +309 -0
  98. keble_tiktok-0.5.0/tests/contract/test_creator_ranking_provider.py +232 -0
  99. keble_tiktok-0.5.0/tests/contract/test_echotik_relation_wiring.py +229 -0
  100. keble_tiktok-0.5.0/tests/contract/test_relation_provider.py +264 -0
  101. keble_tiktok-0.5.0/tests/contract/test_services_manifest.py +64 -0
  102. keble_tiktok-0.5.0/tests/fixtures/echotik/influencer_ranklist_success_sanitized.json +135 -0
  103. keble_tiktok-0.5.0/tests/fixtures/echotik/product_influencer_list_success_sanitized.json +108 -0
  104. keble_tiktok-0.5.0/tests/fixtures/echotik/product_list_success_sanitized.json +235 -0
  105. keble_tiktok-0.5.0/tests/fixtures/echotik/product_ranklist_success_sanitized.json +121 -0
  106. keble_tiktok-0.5.0/tests/fixtures/echotik/product_video_list_success_sanitized.json +51 -0
  107. keble_tiktok-0.5.0/tests/fixtures/echotik/seller_ranklist_success_sanitized.json +114 -0
  108. keble_tiktok-0.5.0/tests/fixtures/fastmoss/creator_product_list_success_sanitized.json +101 -0
  109. keble_tiktok-0.5.0/tests/fixtures/fastmoss/creator_rank_topecommerce_success_sanitized.json +185 -0
  110. keble_tiktok-0.5.0/tests/fixtures/fastmoss/creator_rank_topgrowth_success_sanitized.json +171 -0
  111. keble_tiktok-0.5.0/tests/fixtures/fastmoss/product_creator_list_success_sanitized.json +109 -0
  112. keble_tiktok-0.5.0/tests/fixtures/fastmoss/product_rank_topselling_success_sanitized.json +219 -0
  113. keble_tiktok-0.5.0/tests/fixtures/fastmoss/product_search_success_sanitized.json +140 -0
  114. keble_tiktok-0.5.0/tests/fixtures/fastmoss/product_video_list_success_sanitized.json +7 -0
  115. keble_tiktok-0.5.0/tests/integration/test_provider_cache.py +231 -0
  116. keble_tiktok-0.5.0/tests/live/providers/echotik/test_echotik_ranklist_smoke.py +1315 -0
  117. keble_tiktok-0.5.0/tests/live/providers/echotik/test_echotik_video_smoke.py +253 -0
  118. keble_tiktok-0.5.0/tests/live/providers/fastmoss/test_creator_rank_smoke.py +505 -0
  119. keble_tiktok-0.5.0/tests/live/providers/fastmoss/test_fastmoss_video_smoke.py +225 -0
  120. keble_tiktok-0.5.0/tests/live/providers/fastmoss/test_relations_smoke.py +600 -0
  121. keble_tiktok-0.5.0/tests/live/providers/fastmoss/test_smoke.py +68 -0
  122. keble_tiktok-0.5.0/tests/live/providers/fastmoss/test_top_selling_smoke.py +678 -0
  123. keble_tiktok-0.5.0/tests/unit/domain/test_creator.py +103 -0
  124. keble_tiktok-0.5.0/tests/unit/domain/test_creator_ranking.py +207 -0
  125. keble_tiktok-0.5.0/tests/unit/domain/test_listing.py +69 -0
  126. keble_tiktok-0.5.0/tests/unit/domain/test_mapping.py +361 -0
  127. keble_tiktok-0.5.0/tests/unit/domain/test_mapping_to_commerce.py +182 -0
  128. keble_tiktok-0.5.0/tests/unit/domain/test_metric.py +108 -0
  129. keble_tiktok-0.5.0/tests/unit/domain/test_offer.py +60 -0
  130. keble_tiktok-0.5.0/tests/unit/domain/test_ranking.py +244 -0
  131. keble_tiktok-0.5.0/tests/unit/domain/test_seller_ranking.py +148 -0
  132. keble_tiktok-0.5.0/tests/unit/providers/echotik/__init__.py +0 -0
  133. keble_tiktok-0.5.0/tests/unit/providers/echotik/test_client.py +455 -0
  134. keble_tiktok-0.5.0/tests/unit/providers/echotik/test_creator_ranking_source.py +390 -0
  135. keble_tiktok-0.5.0/tests/unit/providers/echotik/test_dates.py +91 -0
  136. keble_tiktok-0.5.0/tests/unit/providers/echotik/test_echotik_provider.py +202 -0
  137. keble_tiktok-0.5.0/tests/unit/providers/echotik/test_errors.py +90 -0
  138. keble_tiktok-0.5.0/tests/unit/providers/echotik/test_mapper.py +410 -0
  139. keble_tiktok-0.5.0/tests/unit/providers/echotik/test_models.py +289 -0
  140. keble_tiktok-0.5.0/tests/unit/providers/echotik/test_product_ranking_source.py +274 -0
  141. keble_tiktok-0.5.0/tests/unit/providers/echotik/test_relation_mapper.py +244 -0
  142. keble_tiktok-0.5.0/tests/unit/providers/echotik/test_relation_models.py +201 -0
  143. keble_tiktok-0.5.0/tests/unit/providers/echotik/test_relation_source.py +273 -0
  144. keble_tiktok-0.5.0/tests/unit/providers/echotik/test_seller_ranking_mapper.py +175 -0
  145. keble_tiktok-0.5.0/tests/unit/providers/echotik/test_seller_ranking_source.py +257 -0
  146. keble_tiktok-0.5.0/tests/unit/providers/echotik/test_video_fixture_b4.py +150 -0
  147. keble_tiktok-0.5.0/tests/unit/providers/echotik/test_video_source.py +261 -0
  148. keble_tiktok-0.5.0/tests/unit/providers/fastmoss/test_client.py +309 -0
  149. keble_tiktok-0.5.0/tests/unit/providers/fastmoss/test_creator_mapper.py +151 -0
  150. keble_tiktok-0.5.0/tests/unit/providers/fastmoss/test_creator_models.py +144 -0
  151. keble_tiktok-0.5.0/tests/unit/providers/fastmoss/test_creator_ranking_source.py +242 -0
  152. keble_tiktok-0.5.0/tests/unit/providers/fastmoss/test_errors.py +168 -0
  153. keble_tiktok-0.5.0/tests/unit/providers/fastmoss/test_models.py +396 -0
  154. keble_tiktok-0.5.0/tests/unit/providers/fastmoss/test_product_ranking_source.py +236 -0
  155. keble_tiktok-0.5.0/tests/unit/providers/fastmoss/test_product_source.py +201 -0
  156. keble_tiktok-0.5.0/tests/unit/providers/fastmoss/test_relations_mapper.py +382 -0
  157. keble_tiktok-0.5.0/tests/unit/providers/fastmoss/test_topselling_mapper.py +104 -0
  158. keble_tiktok-0.5.0/tests/unit/test_batching.py +92 -0
  159. keble_tiktok-0.5.0/tests/unit/test_proxy_runtime.py +25 -0
  160. keble_tiktok-0.5.0/tests/unit/test_video_mapping.py +225 -0
  161. keble_tiktok-0.5.0/uv.lock +1490 -0
@@ -0,0 +1,14 @@
1
+ ---
2
+ description: Always load AGENTS.md project context and enforce AiAgentChangesLogs.md update on every completion
3
+ alwaysApply: true
4
+ ---
5
+
6
+ # Agent Instructions
7
+
8
+ Read and follow all instructions in `AGENTS.md` at the project root before starting any task.
9
+
10
+ **Mandatory on every completion**: update `AiAgentChangesLogs.md` in the project root with:
11
+ - Timestamp
12
+ - Current git branch / project state
13
+ - User's github username (check via `git config user.name` or `git log`) + summary of their prompt
14
+ - Summary of what you changed (mechanism, dependencies, schemas, etc.)
@@ -0,0 +1,36 @@
1
+ ---
2
+ description: i18n locale resolution dependency — 4-level priority
3
+ globs: backend/**/*.py
4
+ alwaysApply: false
5
+ ---
6
+
7
+ # i18n — Locale Resolution
8
+
9
+ Supported: `zh-CN` (default), `en-US`
10
+
11
+ ## Resolution Order (strict)
12
+ 1. `X-Local-Language` request header
13
+ 2. Authenticated user's `preferred_locale` from DB
14
+ 3. `Accept-Language` header (browser)
15
+ 4. Fallback → `zh-CN`
16
+
17
+ ## FastAPI Dependency
18
+ ```python
19
+ async def get_current_locale(
20
+ request: Request,
21
+ x_local_language: str | None = Header(default=None),
22
+ session: AsyncSession = Depends(get_session),
23
+ ) -> str:
24
+ if x_local_language in SUPPORTED_LOCALES:
25
+ return x_local_language
26
+ user_id = getattr(request.state, "user_id", None)
27
+ if user_id:
28
+ pref = await get_user_locale_from_db(session, user_id)
29
+ if pref in SUPPORTED_LOCALES:
30
+ return pref
31
+ browser = parse_accept_language(request.headers.get("Accept-Language", ""))
32
+ return browser or "zh-CN"
33
+
34
+ # Type alias for injection
35
+ CurrentLocale = Annotated[str, Depends(get_current_locale)]
36
+ ```
@@ -0,0 +1,24 @@
1
+ ---
2
+ description: Language standards for rule files and code artifacts
3
+ alwaysApply: true
4
+ ---
5
+
6
+ # Language Standards
7
+
8
+ ## Rule Files Must Be Written in English
9
+ All `.cursor/rules/*.mdc` files must be written entirely in English.
10
+ No Chinese or other non-English content is allowed in rule files.
11
+
12
+ This applies to:
13
+ - Section headings
14
+ - Explanatory prose
15
+ - Code comments within examples
16
+ - Frontmatter `description` fields
17
+
18
+ ## Code Comments and Identifiers
19
+ All code comments, variable names, function names, and docstrings in the codebase
20
+ must be written in English.
21
+
22
+ ## Conversation Language
23
+ The AI may respond to the user in whatever language the user writes in.
24
+ This rule applies only to persisted artifacts (rule files, code, documentation).
@@ -0,0 +1,175 @@
1
+ ---
2
+ description: Require minimal, requirement-traceable changes and prevent overengineering, premature abstraction, and scope expansion
3
+ alwaysApply: true
4
+ ---
5
+
6
+ # Minimal Change First
7
+
8
+ You are a senior engineer maintaining an existing codebase. Your primary responsibility is not to design the most complete, generic, or future-proof system. Your responsibility is to satisfy the current confirmed requirements with the smallest change and lowest reasonable complexity while preserving existing business semantics.
9
+
10
+ ## 1. Solve only the confirmed problem
11
+
12
+ - Implement only explicitly confirmed requirements and acceptance criteria.
13
+ - Do not automatically expand the scope because unrelated issues were discovered during code investigation.
14
+ - A risk may be documented without being solved in the current task.
15
+ - Do not design for unconfirmed future requirements.
16
+ - Do not add advanced functionality that the user did not request.
17
+
18
+ When the business behavior has already been confirmed, do not redesign it.
19
+
20
+ ## 2. Prefer the simplest viable solution
21
+
22
+ When multiple solutions satisfy the current requirements, prefer the one with:
23
+
24
+ 1. The smallest change surface;
25
+ 2. The highest reuse of existing code;
26
+ 3. The fewest new files;
27
+ 4. The fewest new concepts and states;
28
+ 5. The easiest verification and rollback.
29
+
30
+ Do not introduce complex state management, state machines, strategy patterns, or generic frameworks when ordinary conditions and local state are sufficient.
31
+
32
+ ## 3. Do not convert uncertainty into abstraction
33
+
34
+ Unless the current requirements contain real behavioral differences, do not introduce:
35
+
36
+ - Permission models or role matrices;
37
+ - Preventive `canXxx` or `enableXxx` configuration;
38
+ - Managers, strategies, registries, or providers;
39
+ - Generic hooks or intermediate abstraction layers;
40
+ - Plugin systems;
41
+ - Complex lifecycle management;
42
+ - Generic capabilities created for one current use case.
43
+
44
+ Do not build something merely because it may be useful in the future.
45
+
46
+ Abstraction must be driven by current, demonstrated duplication, not imagined future requirements.
47
+
48
+ ## 4. Entry criteria for new abstractions
49
+
50
+ Only consider adding a component, hook, utility layer, or abstraction when at least one of the following is true:
51
+
52
+ - There are already two or more real call sites;
53
+ - Not extracting it would create clear duplication or inconsistent behavior;
54
+ - The existing component has become too large to understand;
55
+ - The abstraction directly reduces current implementation complexity;
56
+ - The abstraction directly supports current testing or acceptance criteria.
57
+
58
+ Every proposed abstraction must answer:
59
+
60
+ 1. Which explicit requirement does it satisfy?
61
+ 2. Which acceptance criterion would fail without it?
62
+ 3. Why can the existing code not be reused or changed locally?
63
+ 4. Is there a simpler implementation?
64
+
65
+ If these questions cannot be answered, do not add the abstraction.
66
+
67
+ ## 5. Preserve existing business semantics by default
68
+
69
+ Unless explicitly requested, do not change:
70
+
71
+ - Permission rules;
72
+ - Data models;
73
+ - Deletion semantics;
74
+ - Storage behavior;
75
+ - Workflow states;
76
+ - API contracts;
77
+ - Audit behavior;
78
+ - Error-handling semantics.
79
+
80
+ Do not turn a page interaction improvement into a backend redesign, data-lifecycle project, or permission-system redesign.
81
+
82
+ ## 6. Do not expand the technical scope by default
83
+
84
+ Unless the core requirement cannot otherwise be completed, do not:
85
+
86
+ - Add backend endpoints;
87
+ - Change database models;
88
+ - Introduce third-party dependencies or external services;
89
+ - Create scheduled cleanup jobs;
90
+ - Implement unrequested compatibility features;
91
+ - Refactor modules unrelated to the acceptance criteria;
92
+ - Solve all historical issues discovered in the repository.
93
+
94
+ If the requirement can be completed with the existing frontend architecture, do not expand it into backend work.
95
+
96
+ ## 7. Classify investigation findings
97
+
98
+ All issues found during investigation must be classified into three groups:
99
+
100
+ ### A. Required for the current task
101
+
102
+ The requirement or acceptance criteria cannot be satisfied without addressing it.
103
+
104
+ ### B. Safe incidental improvement
105
+
106
+ It is directly related to the current change, inexpensive, and does not expand the scope.
107
+
108
+ ### C. Discovered but out of scope
109
+
110
+ The issue is real but is not directly required by the current goal.
111
+
112
+ Category C issues may be documented but must not automatically enter the implementation plan.
113
+
114
+ Only an issue that would create an immediate security vulnerability, data corruption, or release blocker may be raised as a blocker. Even then, explain the risk first rather than silently expanding the implementation.
115
+
116
+ ## 8. Maintain requirement traceability
117
+
118
+ Every proposed change must trace back to an explicit requirement or acceptance criterion.
119
+
120
+ For each change, state:
121
+
122
+ - Which requirement it satisfies;
123
+ - What concrete failure occurs without it;
124
+ - Why it is the minimum necessary change.
125
+
126
+ A design with no direct connection to the current requirements should be removed from the current plan.
127
+
128
+ ## 9. Present the minimal plan before optional enhancements
129
+
130
+ Before coding, first provide:
131
+
132
+ 1. The direct root cause;
133
+ 2. A minimal implementation path in no more than five sentences;
134
+ 3. Existing files expected to change;
135
+ 4. New files that are genuinely necessary;
136
+ 5. Items explicitly excluded from the current scope;
137
+ 6. A mapping from changes to acceptance criteria;
138
+ 7. Issues discovered but intentionally left out of scope.
139
+
140
+ Do not begin with a complete target architecture, ideal end state, or long-term evolution plan.
141
+
142
+ Optional enhancements must be listed separately. They must not be mixed into the baseline solution or implemented by default.
143
+
144
+ ## 10. Overengineering warning signs
145
+
146
+ Pause and simplify the proposal when any of the following appears:
147
+
148
+ - A simple UI feature introduces a permission matrix;
149
+ - Two or three states introduce a custom state machine or complex hook;
150
+ - Basic previous/next navigation introduces a carousel framework;
151
+ - Unrequested file types, platforms, or advanced capabilities are added;
152
+ - A frontend interaction issue becomes a backend lifecycle project;
153
+ - The number of new files clearly exceeds the number of existing files being changed;
154
+ - The proposal repeatedly relies on "future extensibility," "possible future needs," or "generic capability";
155
+ - Removing a proposed design still leaves every acceptance criterion satisfied;
156
+ - The core implementation cannot be explained in five sentences.
157
+
158
+ When these signals appear, return to the current acceptance criteria and remove every design element without a direct requirement source.
159
+
160
+ ## 11. Implementation discipline
161
+
162
+ After the plan is approved:
163
+
164
+ - Implement in the smallest independently verifiable steps;
165
+ - Run relevant tests after each step;
166
+ - Do not expand the scope during coding;
167
+ - Classify and report newly discovered issues before acting on them;
168
+ - Do not silently include Category C issues;
169
+ - Keep changes local, reversible, and easy to review.
170
+
171
+ ## Final decision rule
172
+
173
+ When both a more complete solution and a simpler solution satisfy the current requirements, choose the simpler solution.
174
+
175
+ Architecture creates value by removing unnecessary complexity, not by adding abstractions.
@@ -0,0 +1,10 @@
1
+ ---
2
+ description: Do not introduce try/catch or try/except in generated code
3
+ alwaysApply: true
4
+ ---
5
+
6
+ # Prevent try/catch / except Pattern
7
+
8
+ 1. When generating code, do NOT use any `try/catch` or `try/except` block — including in pytest. Use pytest utilities (e.g. `pytest.raises`) to test expected error cases.
9
+ 2. If the existing codebase already has `try/catch/except`, keep it unless the user explicitly asks to update it.
10
+ 3. `getattr`, `setattr`, and `try/catch/except` are not patterns of a robust codebase. Prefer explicit types, schemas, and direct attribute access instead.
@@ -0,0 +1,99 @@
1
+ ---
2
+ description: Provider Integration Rule — Docs First, Smoke Second, Implementation Last. Applies to any new third-party provider or new provider endpoint (FastMoss, EchoTik, Keepa, Amazon, Shopify, ...).
3
+ alwaysApply: true
4
+ ---
5
+
6
+ # Provider Integration Rule: Docs First, Smoke Second, Implementation Last
7
+
8
+ This rule exists because two capability-reasoning mistakes were made when integrating providers:
9
+
10
+ 1. **EchoTik**: `page_size` max 10 was misread as "can only return Top 10"; the `page_num`
11
+ pagination parameter was missed; "returns a GMV field" (`total_sale_gmv_amt`) was conflated
12
+ with "does not have GMV", and separately with "supports GMV-sorted ranking".
13
+ 2. **FastMoss**: a verified host (`openapi.fastmoss.com`) was documented but the client default
14
+ was never corrected; `total` was treated as a full board count when only the depth cap was
15
+ observed.
16
+
17
+ The root cause was never the smoke test itself. It was **inferring full API capability from a
18
+ few observations without first reading the docs and producing a capability audit.**
19
+
20
+ ## 1. Mandatory sequence (do not reorder)
21
+
22
+ Any new provider or new provider endpoint MUST proceed in this order:
23
+
24
+ 1. Read the first-party API documentation.
25
+ 2. Save the key endpoint pages verbatim to `docs/providers/<provider>/api-docs/` (a synthesis is
26
+ not a substitute for the primary source).
27
+ 3. Produce a capability matrix at `docs/providers/<provider>/<provider>-capability-audit.md`.
28
+ 4. Label every capability `SUPPORTED` / `UNSUPPORTED` / `UNKNOWN` (§3).
29
+ 5. Design smoke tests that verify the specific assumptions you intend to code against.
30
+ 6. Design the mapper / provider / source implementation.
31
+ 7. Write the code.
32
+ 8. Add default-safe tests (no real API calls, no credentials, no Docker).
33
+ 9. Run the live smoke gate (`RUN_LIVE_<PROVIDER>=1` + `live` marker) and capture a **sanitized**
34
+ fixture.
35
+ 10. Update the capability audit before merging; move each claim from UNKNOWN to SUPPORTED/
36
+ UNSUPPORTED only with cited evidence.
37
+
38
+ If the first-party API doc URL cannot be located, STOP and report "missing first-party API doc
39
+ source" — do not make strong capability claims from responses alone.
40
+
41
+ ## 2. Prohibited
42
+
43
+ - Coding against an endpoint before reading its docs.
44
+ - Inferring full API capability from a single smoke/fixture observation.
45
+ - Writing `UNKNOWN` as `UNSUPPORTED` (or as `SUPPORTED`).
46
+ - Generalizing one observed result into a global conclusion (one region → all regions; one
47
+ `orderby` field → all sort fields; one sample unit → confirmed unit).
48
+ - Treating **field presence** as **sort capability** (a GMV field ≠ a GMV-sorted ranking).
49
+ - Treating a **`page_size` cap** as a **total board-depth limit**.
50
+ - Treating a `total` value as the true full count when only a fixed cap or a page count was
51
+ observed.
52
+ - Guessing a field's unit from its name (basis points vs decimal vs percent; major vs minor
53
+ currency units; ISO week vs Monday-date).
54
+ - Putting provider-specific details into the `keble-data-infra` universal layer.
55
+ - Committing real credentials anywhere, including `.env.example` (use placeholders only).
56
+
57
+ ## 3. Three-state vocabulary (strict)
58
+
59
+ - **SUPPORTED** — documented AND verified by at least one of smoke / fixture / test.
60
+ - **UNSUPPORTED** — documented as absent, OR smoke-confirmed failing, AND the failing condition
61
+ is stated.
62
+ - **UNKNOWN** — docs unclear, or not yet verified. UNKNOWN blocks coding against the capability.
63
+
64
+ ## 4. Every key conclusion must separate four layers
65
+
66
+ For each key capability, the audit must state:
67
+
68
+ - **Docs** — what the official documentation actually says.
69
+ - **Observed** — what smoke / fixture / test actually returned.
70
+ - **Inferred** — the reasoning built on docs + observation, with its uncertainty called out.
71
+ - **Decision** — the engineering choice this phase (opened / withheld / approximated), and why.
72
+
73
+ Do not write bare claims like "provider supports GMV" / "provider does not support GMV" /
74
+ "provider only returns N rows" without doc + test evidence behind each layer.
75
+
76
+ ## 5. Capability matrix columns (minimum)
77
+
78
+ `endpoint · business use · implemented? · request params · pagination params · page_size limit ·
79
+ returns total? · next_cursor/has_more? · sort fields · sales field · GMV field · GMV-sort
80
+ capability · price field · currency field · commission field · window/time format · region/market
81
+ param · doc evidence · smoke evidence · test coverage · conclusion (SUPPORTED/UNSUPPORTED/UNKNOWN)
82
+ · risk note`
83
+
84
+ Keep `page_size` cap, `total` semantics, and board depth in **separate** columns — never merge
85
+ them.
86
+
87
+ ## 6. Field retention
88
+
89
+ Fields that are valuable downstream but not yet universalizable MUST be preserved on
90
+ `channel_details` (or the domain's channel-specific detail object), not dropped just because the
91
+ universal domain has no field for them yet. Never fabricate a value to fill a universal field;
92
+ emit the metric as absent instead.
93
+
94
+ ## 7. Layering (unchanged, restated for providers)
95
+
96
+ - Provider raw adapters, domain, and ports must NOT import `keble-data-infra` contracts.
97
+ - Only bridge modules (`commerce_provider.py`, `creator_ranking_provider.py`,
98
+ `mapping/to_commerce.py`, `app.py`) adapt domain objects into the universal contract.
99
+ - Provider selection (`if provider_id == "..."`) lives only in the composition root (`app.py`).
@@ -0,0 +1,9 @@
1
+ ---
2
+ description: Prevent database leaks during pytest runs
3
+ globs: "tests/**"
4
+ alwaysApply: false
5
+ ---
6
+
7
+ # Prevent Pytest DB Leaks
8
+
9
+ Prevent database leaks across MongoDB, Redis, Neo4j, and Qdrant during pytest. Clean up databases after each test run or test function.
@@ -0,0 +1,48 @@
1
+ ---
2
+ description: Python coding standards — pydantic, typing, backend schemas, and protocols
3
+ globs: "**/*.py"
4
+ alwaysApply: false
5
+ ---
6
+
7
+ # Python
8
+
9
+ 0. Use MCP to check latest library docs when needed.
10
+ 1. Prefer pydantic models to restrict schemas rather than `hasattr` + `getattr`.
11
+ 2. When updating any library or Python package, run/update pytest and update `README.md` if necessary.
12
+ 3. Do not use in-function imports.
13
+ 4. Use `uv` to manage the environment (older docs may reference `conda`).
14
+ 5. After Python changes, run `npx --yes pyright .` at the repo root and fix all reported errors.
15
+
16
+ ## Pydantic AI Prompting — Use Strong Types
17
+
18
+ Do not inject URLs (or any doc references) as plain strings into prompts. Pass typed prompt parts in a list:
19
+
20
+ ```python
21
+ from pydantic_ai import Agent, ImageUrl
22
+
23
+ agent = Agent(model='gateway/openai:gpt-5.2')
24
+ result = await agent.run(
25
+ [
26
+ 'What company is this logo from?',
27
+ ImageUrl(url='https://iili.io/3Hs4FMg.png'),
28
+ ]
29
+ )
30
+ ```
31
+
32
+ ## Backend — Structural and Type Conversion
33
+
34
+ Limit schema count: not over-reduced, not over-complicated.
35
+
36
+ **CRUD** schemas (per entity): `*Base`, `*Update`, `*Create`, `*MongoObject` (or `*SqlObject`, etc.).
37
+
38
+ **Logic** schemas: e.g. `MyLogic`, `MyLogics`, `MyLogicItem`, `MyLogicItemType(str, Enum)` — names reflect hierarchy. Every schema, especially `*Base`, needs a docstring stating its intention.
39
+
40
+ **Client APIs**: `get_*`, `list_*`, etc. Each API needs a docstring stating intention and which types it converts (e.g. `client.get_* -> crud.list_* -> MyLogic.to_other_logic_type(crud_response) -> return`).
41
+
42
+ Typing conversion + APIs is the core backend design pattern.
43
+
44
+ ## Libs and Submodules — Schemas and Protocol First
45
+
46
+ Split complex backend logic across packages. To avoid mutual explicit dependencies while allowing implicit coordination, define `Protocol` types so dependent libs follow the contract without circular imports.
47
+
48
+ Keep protocols in standalone files such as `schemas.py` and `protocols.py`. Wire implementations in the backend layer.
@@ -0,0 +1,15 @@
1
+ ---
2
+ description: TypeScript and React/Next.js coding standards
3
+ globs: "**/*.{ts,tsx}"
4
+ alwaysApply: false
5
+ ---
6
+
7
+ # TypeScript
8
+
9
+ 0. Always run `nvm use 21` before TypeScript work to prevent wrong Node versioning.
10
+ 1. After updating any TypeScript files, run `tsc` to check for type errors.
11
+ 2. For React / Next.js projects, export components in this format — no `React.FC`, no `export default`:
12
+
13
+ ```ts
14
+ export function MyComponent(props: MyComponentProps) {}
15
+ ```
@@ -0,0 +1,10 @@
1
+ FASTMOSS_CLIENT_SECRET=jdkzdjjtckcapoopnpotrewvcjknommg
2
+ FASTMOSS_BASE_URL=https://openapi.fastmoss.com
3
+ FASTMOSS_PROVIDER_ID=fastmoss
4
+ RUN_FASTMOSS_SMOKE=1
5
+
6
+ # EchoTik credentials
7
+ ECHOTIK_USERNAME=260625095277577533
8
+ ECHOTIK_PASSWORD=d7f0dbfc243348aabb4953efc26bbcbe
9
+ ECHOTIK_BASE_URL=https://open.echotik.live
10
+ RUN_LIVE_ECHOTIK=1
@@ -0,0 +1,2 @@
1
+ # Auto detect text files and perform LF normalization
2
+ * text=auto
@@ -0,0 +1,41 @@
1
+ # Generated by Cargo
2
+ # will have compiled files and executables
3
+ debug/
4
+ target/
5
+ cert/
6
+
7
+ # Remove Cargo.lock from gitignore if creating an executable, leave it for libraries
8
+ # More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html
9
+ Cargo.lock
10
+
11
+ # These are backup files generated by rustfmt
12
+ **/*.rs.bk
13
+
14
+ # MSVC Windows builds of rustc generate these, which store debugging information
15
+ *.pdb
16
+ *__ignored__*
17
+
18
+ *.env
19
+ *.DS_Store
20
+ **/.DS_Store
21
+
22
+ .vscode
23
+ .idea
24
+
25
+ *.crt
26
+
27
+ uploads/
28
+ !strapi-v5/public/uploads/
29
+ !strapi-v5/public/uploads/.gitkeep
30
+ test/
31
+ resources/
32
+ Brewfile
33
+ qdrant/
34
+ *.pyc
35
+ **.pyc.*
36
+ */traefik/certs
37
+ */traefik/certs/*
38
+ gcp.json
39
+ .history
40
+
41
+ prod.env.*
@@ -0,0 +1,98 @@
1
+
2
+ 1. Update `AiAgentChangesLogs.md` in project root directory on each completion. Include timestamp, project state, my prompt and your changes. Be simple when you are simply fixing a small bug. Be concise and conclusive when you are updating large portion of the codebase. Sample format:
3
+ ```markdown
4
+ ## 2026-01-01 14:00
5
+ State: <the state of the project linked to this section>
6
+
7
+ <!-- you may want to use git to check my git username, since there are multiple people working in the same branch -->
8
+ <My github username>: <a summary of my prompt, shorten it if too long, it need to contained details bulletpoints of my requests>
9
+
10
+ Ai: <a summary on what have you changed? Especially the mechanism, dependencies, schemas, etc...>
11
+ ```
12
+ If `AiAgentChangesLogs.md` is NOT presented in the project root directory, create one, and copy paste my prompt
13
+ ```markdown
14
+ Update `AiAgentChangesLogs.md` in project root directory on each completion. Include timestamp, project state, my prompt and your changes. Be simple when you are simply fixing a small bug. Be concise and conclusive when you are updating large portion of the codebase. Sample format:
15
+ ```
16
+ ... as above
17
+
18
+ ## Project Context
19
+
20
+ `keble-tiktok` is the **TikTok Channel Domain** layer of the Keble unified e-commerce data platform. It sits in the middle of the three-layer architecture:
21
+
22
+ ```text
23
+ Provider Raw (e.g. FastMoss, EchoTik, Crawler)
24
+
25
+ Channel Domain ← this repo (keble-tiktok: TikTok Domain + TikTokProductSource interface)
26
+
27
+ Universal Commerce (keble-data-infra-contract)
28
+
29
+ Application Service / SDK / Agent
30
+ ```
31
+
32
+ **Key architectural decisions**:
33
+ - Source of truth: `keble-data-infra/docs/architecture/keble-data-platform-design.md`
34
+ - Local implementation reference (extracted subset for this repo): `docs/architecture/tiktok-domain-impl.md`
35
+
36
+ **Summary of decisions**:
37
+
38
+ 1. **Interface ownership**: provider-neutral schemas, protocols, operation keys, and manifests are defined in `keble-data-infra-contract`; this repo implements them.
39
+ 2. **Dependency direction**: TikTok domain, ports, and provider raw adapters do not import the API package. Bridge modules and `services.py` may import the contract to normalize provider results.
40
+ 3. **HTTP ownership**: this package exports `FastMossServices` and `EchoTikServices`; it must not import FastAPI or build routers/apps. `keble-data-infra-api` constructs every raw HTTP route.
41
+ 4. **Provider-native fields**: typed TikTok detail models remain internal and are not embedded into normalized public contracts.
42
+ 5. **No DI framework**: dependency injection via plain constructors; prefer `typing.Protocol` over abstract base classes.
43
+ 6. **Primary responsibility**: expose stable provider services that wrap FastMoss / EchoTik raw data into normalized contract models.
44
+ 7. **Minimal increment**: implement one capability at a time; test and commit before the next step.
45
+ 8. **No speculative implementations**: do not pre-build multi-source merge, MCP, or Agent layers until there is a concrete requirement.
46
+ 9. **Python >= 3.13**, pydantic v2 only.
47
+
48
+ ## Testing Rules
49
+
50
+ - Follow the umbrella root `TESTING_GUIDELINE.md` for every test change.
51
+ - Use the canonical layer-first structure: `tests/unit`, `tests/contract`, `tests/integration`, `tests/live`, `tests/evals`, and `tests/db_stack` only when those layers have real executable tests. Do not create empty placeholder test modules or folders just to mirror source files.
52
+ - Default-safe tests must run without real FastMoss calls, Docker, shared dev/prod databases, or credentials:
53
+ `uv run pytest -m "not live and not slow and not eval and not local_stack and not db_stack and not container"`.
54
+ - Local deterministic DB-heavy tests should be part of the local-full lane when the repo has them; opt-in gates are for real provider calls, eval datasets, cross-store `db_stack`, `local_stack`, and container/service orchestration.
55
+ - Keep the canonical marker vocabulary aligned with the root guideline. `asyncio` is a pytest framework marker, not a semantic layer marker; use it only when pytest-asyncio needs it.
56
+ - Real FastMoss canaries belong under `tests/live` and require `RUN_LIVE_FASTMOSS=1` plus credentials. Once the gate is enabled, provider request/schema failures should fail the test instead of being downgraded to skips.
57
+ - Production clients that honor environment proxy settings require the
58
+ `httpx[socks]` runtime extra; do not remove it while `trust_env=True` remains
59
+ an API-owned production option.
60
+ - Use `keble_db.testing` and `keble_keepa.testing` when DB or Keepa fixtures are needed in downstream repos. If a reusable fixture is missing, enrich the shared toolkit before adding ad hoc fakes here.
61
+ - Provider response caching must use `ProviderOperationCache` with complete
62
+ request identity, the API-startup Mongo indexes, and shared
63
+ `keble_db.RedisLeaseManager`; never add provider-local locks or a second cache.
64
+ - Service-only batches must deduplicate exact requests, preserve caller order,
65
+ and bound concurrency. Do not expose HTTP batch routes without a new contract.
66
+ - Keep Sentry spans structural: cache outcome, lease ownership, stable
67
+ operation, and batch counts only. Never attach request bodies or credentials.
68
+ - Run `uv lock --check`, the relevant pytest layer selectors, and `npx --yes pyright .` from this repo after Python test or typing changes.
69
+
70
+ **Related repos**:
71
+ - `keble-data-infra-contract` — provider-neutral caller-owned contracts
72
+ - `keble-data-infra-api` — sole raw FastAPI composition root
73
+ - `keble-products` — product data services (FastMoss integration live)
74
+ - `keble-helpers` (installed as `keble_helpers==1.12.17`)
75
+ - `keble-exceptions`, `keble-graphrag`, `keble-keepa`
76
+
77
+ ## Git Branching, Versioning, and Merge Policy
78
+
79
+ 1. Branch names normally must NOT include version numbers.
80
+ 2. Use topic-based branch names:
81
+ - `feature/<topic>`
82
+ - `fix/<topic>`
83
+ - `rewrite/<topic>`
84
+ - `refactor/<topic>`
85
+ - `hotfix/<topic>`
86
+ 3. Create a new branch when starting a meaningful line of work.
87
+ 4. If you are still in planning phase, ask whether this work needs:
88
+ - a new branch
89
+ - a new version bump
90
+ - a new release label
91
+ 5. Do not assume branch creation implies a version bump.
92
+ 6. Versions belong in annotated tags, normally pure semantic versioning such as `v0.1.0`.
93
+ 7. Only use extra tag labels if explicitly requested.
94
+ 8. When bumping a repo version, create and push the corresponding annotated tag after verification.
95
+ 9. After the work is verified, merge to `main`.
96
+ 10. For non-production repos, merging to `main` is allowed after verification.
97
+ 11. Do not delete branches, rewrite shared history, or force-push unless explicitly approved.
98
+ 12. Do not claim branch, tag, merge, or push success unless `git branch -vv`, `git tag`, and remote refs confirm it.