kpubdata 0.1.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 (134) hide show
  1. kpubdata-0.1.0/.github/ISSUE_TEMPLATE/new-provider-adapter.yml +105 -0
  2. kpubdata-0.1.0/.github/workflows/ci.yml +98 -0
  3. kpubdata-0.1.0/.github/workflows/integration.yml +50 -0
  4. kpubdata-0.1.0/.github/workflows/publish-pypi.yml +60 -0
  5. kpubdata-0.1.0/.gitignore +37 -0
  6. kpubdata-0.1.0/AGENTS.md +247 -0
  7. kpubdata-0.1.0/API_SPEC.md +160 -0
  8. kpubdata-0.1.0/ARCHITECTURE.md +464 -0
  9. kpubdata-0.1.0/CANONICAL_MODEL.md +355 -0
  10. kpubdata-0.1.0/CHANGELOG.md +40 -0
  11. kpubdata-0.1.0/CONTRIBUTING.md +193 -0
  12. kpubdata-0.1.0/LICENSE +21 -0
  13. kpubdata-0.1.0/PACKAGING.md +114 -0
  14. kpubdata-0.1.0/PKG-INFO +380 -0
  15. kpubdata-0.1.0/PRD.md +306 -0
  16. kpubdata-0.1.0/PROVIDER_ADAPTER_CONTRACT.md +251 -0
  17. kpubdata-0.1.0/README.md +343 -0
  18. kpubdata-0.1.0/ROADMAP.md +55 -0
  19. kpubdata-0.1.0/SUPPORTED_DATA.md +50 -0
  20. kpubdata-0.1.0/VALIDATION.md +106 -0
  21. kpubdata-0.1.0/docs/adrs/0001-dialect-inspired-architecture.md +22 -0
  22. kpubdata-0.1.0/docs/adrs/0002-standardize-ux-not-native-shape.md +21 -0
  23. kpubdata-0.1.0/docs/architecture-diagrams.md +496 -0
  24. kpubdata-0.1.0/docs/datago-api-reference.md +220 -0
  25. kpubdata-0.1.0/docs/product-family-architecture.md +369 -0
  26. kpubdata-0.1.0/docs/providers/bok.md +207 -0
  27. kpubdata-0.1.0/docs/providers/datago.md +393 -0
  28. kpubdata-0.1.0/docs/providers/kosis.md +216 -0
  29. kpubdata-0.1.0/docs/quickstart.md +152 -0
  30. kpubdata-0.1.0/docs/tutorial-ai-agent-workflow.md +490 -0
  31. kpubdata-0.1.0/pyproject.toml +80 -0
  32. kpubdata-0.1.0/src/kpubdata/__init__.py +52 -0
  33. kpubdata-0.1.0/src/kpubdata/catalog.py +101 -0
  34. kpubdata-0.1.0/src/kpubdata/client.py +179 -0
  35. kpubdata-0.1.0/src/kpubdata/config.py +119 -0
  36. kpubdata-0.1.0/src/kpubdata/core/__init__.py +25 -0
  37. kpubdata-0.1.0/src/kpubdata/core/capability.py +56 -0
  38. kpubdata-0.1.0/src/kpubdata/core/dataset.py +153 -0
  39. kpubdata-0.1.0/src/kpubdata/core/models.py +156 -0
  40. kpubdata-0.1.0/src/kpubdata/core/protocol.py +60 -0
  41. kpubdata-0.1.0/src/kpubdata/core/representation.py +19 -0
  42. kpubdata-0.1.0/src/kpubdata/exceptions.py +116 -0
  43. kpubdata-0.1.0/src/kpubdata/providers/__init__.py +5 -0
  44. kpubdata-0.1.0/src/kpubdata/providers/_common.py +204 -0
  45. kpubdata-0.1.0/src/kpubdata/providers/bok/__init__.py +7 -0
  46. kpubdata-0.1.0/src/kpubdata/providers/bok/adapter.py +333 -0
  47. kpubdata-0.1.0/src/kpubdata/providers/bok/catalogue.json +25 -0
  48. kpubdata-0.1.0/src/kpubdata/providers/datago/__init__.py +7 -0
  49. kpubdata-0.1.0/src/kpubdata/providers/datago/adapter.py +313 -0
  50. kpubdata-0.1.0/src/kpubdata/providers/datago/catalogue.json +92 -0
  51. kpubdata-0.1.0/src/kpubdata/providers/kosis/__init__.py +7 -0
  52. kpubdata-0.1.0/src/kpubdata/providers/kosis/adapter.py +254 -0
  53. kpubdata-0.1.0/src/kpubdata/providers/kosis/catalogue.json +26 -0
  54. kpubdata-0.1.0/src/kpubdata/providers/lofin/__init__.py +7 -0
  55. kpubdata-0.1.0/src/kpubdata/providers/lofin/adapter.py +329 -0
  56. kpubdata-0.1.0/src/kpubdata/providers/lofin/catalogue.json +127 -0
  57. kpubdata-0.1.0/src/kpubdata/py.typed +0 -0
  58. kpubdata-0.1.0/src/kpubdata/registry.py +135 -0
  59. kpubdata-0.1.0/src/kpubdata/transport/__init__.py +16 -0
  60. kpubdata-0.1.0/src/kpubdata/transport/decode.py +74 -0
  61. kpubdata-0.1.0/src/kpubdata/transport/http.py +380 -0
  62. kpubdata-0.1.0/src/kpubdata/transport/retry.py +68 -0
  63. kpubdata-0.1.0/tests/__init__.py +0 -0
  64. kpubdata-0.1.0/tests/contract/__init__.py +0 -0
  65. kpubdata-0.1.0/tests/contract/provider_adapter.py +81 -0
  66. kpubdata-0.1.0/tests/contract/test_bok.py +100 -0
  67. kpubdata-0.1.0/tests/contract/test_datago.py +81 -0
  68. kpubdata-0.1.0/tests/contract/test_kosis.py +102 -0
  69. kpubdata-0.1.0/tests/contract/test_lofin.py +137 -0
  70. kpubdata-0.1.0/tests/fixtures/bok/error_auth.json +6 -0
  71. kpubdata-0.1.0/tests/fixtures/bok/success_empty.json +6 -0
  72. kpubdata-0.1.0/tests/fixtures/bok/success_single_page.json +34 -0
  73. kpubdata-0.1.0/tests/fixtures/datago/error_auth_30.json +9 -0
  74. kpubdata-0.1.0/tests/fixtures/datago/error_invalid_request_10.json +9 -0
  75. kpubdata-0.1.0/tests/fixtures/datago/error_rate_limit_22.json +9 -0
  76. kpubdata-0.1.0/tests/fixtures/datago/error_service_unavailable_01.json +9 -0
  77. kpubdata-0.1.0/tests/fixtures/datago/error_xml_auth_30.xml +8 -0
  78. kpubdata-0.1.0/tests/fixtures/datago/success_apt_trade.json +43 -0
  79. kpubdata-0.1.0/tests/fixtures/datago/success_empty.json +14 -0
  80. kpubdata-0.1.0/tests/fixtures/datago/success_multi_page_1.json +25 -0
  81. kpubdata-0.1.0/tests/fixtures/datago/success_multi_page_2.json +21 -0
  82. kpubdata-0.1.0/tests/fixtures/datago/success_single_item.json +19 -0
  83. kpubdata-0.1.0/tests/fixtures/datago/success_single_page.json +35 -0
  84. kpubdata-0.1.0/tests/fixtures/datago/success_string_numerics.json +21 -0
  85. kpubdata-0.1.0/tests/fixtures/datago/success_xml.xml +22 -0
  86. kpubdata-0.1.0/tests/fixtures/datago/success_xml_single_item.xml +18 -0
  87. kpubdata-0.1.0/tests/fixtures/kosis/error_auth.json +4 -0
  88. kpubdata-0.1.0/tests/fixtures/kosis/success_empty.json +1 -0
  89. kpubdata-0.1.0/tests/fixtures/kosis/success_single_page.json +5 -0
  90. kpubdata-0.1.0/tests/fixtures/lofin/error_auth.json +8 -0
  91. kpubdata-0.1.0/tests/fixtures/lofin/success_single_page.json +50 -0
  92. kpubdata-0.1.0/tests/integration/__init__.py +0 -0
  93. kpubdata-0.1.0/tests/integration/conftest.py +54 -0
  94. kpubdata-0.1.0/tests/integration/test_bok_live.py +219 -0
  95. kpubdata-0.1.0/tests/integration/test_client_flow.py +198 -0
  96. kpubdata-0.1.0/tests/integration/test_datago_live.py +74 -0
  97. kpubdata-0.1.0/tests/integration/test_exception_propagation.py +229 -0
  98. kpubdata-0.1.0/tests/integration/test_kosis_live.py +236 -0
  99. kpubdata-0.1.0/tests/integration/test_lofin_live.py +199 -0
  100. kpubdata-0.1.0/tests/integration/test_transport_http.py +265 -0
  101. kpubdata-0.1.0/tests/unit/__init__.py +0 -0
  102. kpubdata-0.1.0/tests/unit/core/__init__.py +0 -0
  103. kpubdata-0.1.0/tests/unit/core/test_dataset.py +139 -0
  104. kpubdata-0.1.0/tests/unit/core/test_dataset_coverage.py +47 -0
  105. kpubdata-0.1.0/tests/unit/core/test_exceptions.py +88 -0
  106. kpubdata-0.1.0/tests/unit/core/test_exceptions_coverage.py +9 -0
  107. kpubdata-0.1.0/tests/unit/core/test_models.py +135 -0
  108. kpubdata-0.1.0/tests/unit/core/test_models_fixtures.py +236 -0
  109. kpubdata-0.1.0/tests/unit/providers/__init__.py +0 -0
  110. kpubdata-0.1.0/tests/unit/providers/datago/__init__.py +0 -0
  111. kpubdata-0.1.0/tests/unit/providers/datago/conftest.py +70 -0
  112. kpubdata-0.1.0/tests/unit/providers/datago/test_adapter.py +480 -0
  113. kpubdata-0.1.0/tests/unit/providers/datago/test_adapter_coverage.py +333 -0
  114. kpubdata-0.1.0/tests/unit/providers/datago/test_fixtures.py +137 -0
  115. kpubdata-0.1.0/tests/unit/test_catalog.py +137 -0
  116. kpubdata-0.1.0/tests/unit/test_catalog_coverage.py +49 -0
  117. kpubdata-0.1.0/tests/unit/test_catalogue_validation.py +113 -0
  118. kpubdata-0.1.0/tests/unit/test_client_coverage.py +121 -0
  119. kpubdata-0.1.0/tests/unit/test_client_transport_requirements.py +134 -0
  120. kpubdata-0.1.0/tests/unit/test_config.py +56 -0
  121. kpubdata-0.1.0/tests/unit/test_config_coverage.py +41 -0
  122. kpubdata-0.1.0/tests/unit/test_registry.py +83 -0
  123. kpubdata-0.1.0/tests/unit/test_registry_coverage.py +109 -0
  124. kpubdata-0.1.0/tests/unit/transport/__init__.py +0 -0
  125. kpubdata-0.1.0/tests/unit/transport/test_decode.py +90 -0
  126. kpubdata-0.1.0/tests/unit/transport/test_decode_coverage.py +22 -0
  127. kpubdata-0.1.0/tests/unit/transport/test_http_coverage.py +92 -0
  128. kpubdata-0.1.0/tests/unit/transport/test_http_coverage_extra.py +50 -0
  129. kpubdata-0.1.0/tests/unit/transport/test_logging.py +122 -0
  130. kpubdata-0.1.0/tests/unit/transport/test_retry.py +54 -0
  131. kpubdata-0.1.0/tests/unit/transport/test_retry_after.py +126 -0
  132. kpubdata-0.1.0/tests/unit/transport/test_retry_coverage.py +21 -0
  133. kpubdata-0.1.0/tests/unit/transport/test_transport_requirements.py +73 -0
  134. kpubdata-0.1.0/uv.lock +1518 -0
@@ -0,0 +1,105 @@
1
+ name: New Provider Adapter
2
+ description: Propose or track a new Korean public data provider adapter
3
+ title: "[Provider] "
4
+ labels: ["type:feature"]
5
+ body:
6
+ - type: markdown
7
+ attributes:
8
+ value: |
9
+ ## New Provider Adapter Request
10
+
11
+ Use this template to propose adding a new Korean public data provider.
12
+
13
+ - type: input
14
+ id: provider-name
15
+ attributes:
16
+ label: Provider Name
17
+ description: The official name of the data provider (Korean and English)
18
+ placeholder: "e.g., 서울열린데이터광장 (Seoul Open Data)"
19
+ validations:
20
+ required: true
21
+
22
+ - type: input
23
+ id: base-url
24
+ attributes:
25
+ label: API Base URL
26
+ description: The base URL for the provider's API
27
+ placeholder: "e.g., http://openapi.seoul.go.kr:8088"
28
+ validations:
29
+ required: true
30
+
31
+ - type: dropdown
32
+ id: auth-type
33
+ attributes:
34
+ label: Authentication Type
35
+ options:
36
+ - API Key (query parameter)
37
+ - API Key (header)
38
+ - OAuth 2.0
39
+ - No auth
40
+ - Other (describe below)
41
+ validations:
42
+ required: true
43
+
44
+ - type: dropdown
45
+ id: response-format
46
+ attributes:
47
+ label: Response Format
48
+ multiple: true
49
+ options:
50
+ - JSON
51
+ - XML
52
+ - CSV
53
+ - Excel
54
+ - Other
55
+ validations:
56
+ required: true
57
+
58
+ - type: textarea
59
+ id: datasets
60
+ attributes:
61
+ label: Key Datasets
62
+ description: List the most important datasets this provider offers
63
+ placeholder: |
64
+ - 서울시 실시간 대기환경 (Real-time air quality)
65
+ - 서울시 공공자전거 대여소 (Public bike stations)
66
+ validations:
67
+ required: true
68
+
69
+ - type: textarea
70
+ id: api-docs
71
+ attributes:
72
+ label: API Documentation Links
73
+ description: Links to official API documentation
74
+ placeholder: "https://..."
75
+ validations:
76
+ required: true
77
+
78
+ - type: textarea
79
+ id: notes
80
+ attributes:
81
+ label: Additional Notes
82
+ description: Any quirks, rate limits, or special considerations
83
+ placeholder: |
84
+ - Rate limit: 1000 calls/day
85
+ - Requires registration at data.go.kr
86
+ - Some endpoints return EUC-KR encoding
87
+ validations:
88
+ required: false
89
+
90
+ - type: checkboxes
91
+ id: checklist
92
+ attributes:
93
+ label: Implementation Checklist
94
+ description: Track progress (maintainer use)
95
+ options:
96
+ - label: "API research and documentation"
97
+ - label: "Adapter class with `name` property"
98
+ - label: "`list_datasets()` implementation"
99
+ - label: "`query_records()` with pagination"
100
+ - label: "`get_schema()` implementation"
101
+ - label: "`call_raw()` escape hatch"
102
+ - label: "Fixture responses captured"
103
+ - label: "Unit tests with fixtures"
104
+ - label: "Contract tests passing"
105
+ - label: "Capabilities documented honestly"
@@ -0,0 +1,98 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ pull_request:
7
+ branches: [main]
8
+
9
+ permissions:
10
+ contents: read
11
+
12
+ concurrency:
13
+ group: ci-${{ github.ref }}
14
+ cancel-in-progress: true
15
+
16
+ jobs:
17
+ quality:
18
+ name: Lint & Type Check
19
+ runs-on: ubuntu-latest
20
+ timeout-minutes: 10
21
+ steps:
22
+ - uses: actions/checkout@v4
23
+
24
+ - uses: astral-sh/setup-uv@v4
25
+ with:
26
+ enable-cache: true
27
+ cache-dependency-glob: "uv.lock"
28
+
29
+ - uses: actions/setup-python@v5
30
+ with:
31
+ python-version: "3.12"
32
+
33
+ - name: Install dependencies
34
+ run: uv sync --frozen --extra dev
35
+
36
+ - name: Ruff check
37
+ run: uv run ruff check .
38
+
39
+ - name: Ruff format check
40
+ run: uv run ruff format --check .
41
+
42
+ - name: Mypy
43
+ run: uv run mypy src
44
+
45
+ test:
46
+ name: Test (Python ${{ matrix.python-version }})
47
+ runs-on: ubuntu-latest
48
+ timeout-minutes: 15
49
+ strategy:
50
+ fail-fast: false
51
+ matrix:
52
+ python-version: ["3.10", "3.11", "3.12", "3.13"]
53
+ steps:
54
+ - uses: actions/checkout@v4
55
+
56
+ - uses: astral-sh/setup-uv@v4
57
+ with:
58
+ enable-cache: true
59
+ cache-dependency-glob: "uv.lock"
60
+
61
+ - uses: actions/setup-python@v5
62
+ with:
63
+ python-version: ${{ matrix.python-version }}
64
+
65
+ - name: Install dependencies
66
+ run: uv sync --frozen --extra dev
67
+
68
+ - name: Run tests
69
+ run: uv run pytest -ra
70
+
71
+ build:
72
+ name: Build Package
73
+ runs-on: ubuntu-latest
74
+ timeout-minutes: 10
75
+ needs: [quality, test]
76
+ steps:
77
+ - uses: actions/checkout@v4
78
+
79
+ - uses: astral-sh/setup-uv@v4
80
+ with:
81
+ enable-cache: true
82
+ cache-dependency-glob: "uv.lock"
83
+
84
+ - uses: actions/setup-python@v5
85
+ with:
86
+ python-version: "3.12"
87
+
88
+ - name: Install dependencies
89
+ run: uv sync --frozen --extra dev
90
+
91
+ - name: Build sdist and wheel
92
+ run: uv run python -m build
93
+
94
+ - name: Upload artifacts
95
+ uses: actions/upload-artifact@v4
96
+ with:
97
+ name: dist
98
+ path: dist/
@@ -0,0 +1,50 @@
1
+ name: Integration Tests
2
+
3
+ on:
4
+ workflow_dispatch:
5
+ inputs:
6
+ provider:
7
+ description: 'Provider to test'
8
+ required: true
9
+ default: 'all'
10
+ type: choice
11
+ options:
12
+ - all
13
+ - datago
14
+ - bok
15
+ - kosis
16
+
17
+ permissions:
18
+ contents: read
19
+
20
+ jobs:
21
+ integration:
22
+ name: Integration Tests (${{ github.event.inputs.provider }})
23
+ runs-on: ubuntu-latest
24
+ timeout-minutes: 15
25
+ steps:
26
+ - uses: actions/checkout@v4
27
+
28
+ - uses: astral-sh/setup-uv@v4
29
+ with:
30
+ enable-cache: true
31
+ cache-dependency-glob: "uv.lock"
32
+
33
+ - uses: actions/setup-python@v5
34
+ with:
35
+ python-version: "3.12"
36
+
37
+ - name: Install dependencies
38
+ run: uv sync --frozen --extra dev
39
+
40
+ - name: Run integration tests
41
+ env:
42
+ KPUBDATA_DATAGO_API_KEY: ${{ secrets.KPUBDATA_DATAGO_API_KEY }}
43
+ KPUBDATA_BOK_API_KEY: ${{ secrets.KPUBDATA_BOK_API_KEY }}
44
+ KPUBDATA_KOSIS_API_KEY: ${{ secrets.KPUBDATA_KOSIS_API_KEY }}
45
+ run: |
46
+ if [ "${{ github.event.inputs.provider }}" = "all" ]; then
47
+ uv run pytest -m integration -ra -v
48
+ else
49
+ uv run pytest -m integration -ra -v -k "${{ github.event.inputs.provider }}"
50
+ fi
@@ -0,0 +1,60 @@
1
+ name: Publish to PyPI
2
+
3
+ on:
4
+ release:
5
+ types: [published]
6
+
7
+ permissions:
8
+ contents: read
9
+ id-token: write
10
+
11
+ jobs:
12
+ build:
13
+ name: Build Package
14
+ runs-on: ubuntu-latest
15
+ timeout-minutes: 10
16
+ steps:
17
+ - uses: actions/checkout@v4
18
+
19
+ - uses: astral-sh/setup-uv@v4
20
+ with:
21
+ enable-cache: true
22
+ cache-dependency-glob: "uv.lock"
23
+
24
+ - uses: actions/setup-python@v5
25
+ with:
26
+ python-version: "3.12"
27
+
28
+ - name: Install dependencies
29
+ run: uv sync --frozen --extra dev
30
+
31
+ - name: Run quality gates
32
+ run: |
33
+ uv run ruff check .
34
+ uv run ruff format --check .
35
+ uv run mypy src
36
+ uv run pytest -ra
37
+
38
+ - name: Build sdist and wheel
39
+ run: uv run python -m build
40
+
41
+ - name: Upload artifacts
42
+ uses: actions/upload-artifact@v4
43
+ with:
44
+ name: dist
45
+ path: dist/
46
+
47
+ publish:
48
+ name: Publish to PyPI
49
+ runs-on: ubuntu-latest
50
+ needs: build
51
+ environment: pypi
52
+ steps:
53
+ - name: Download artifacts
54
+ uses: actions/download-artifact@v4
55
+ with:
56
+ name: dist
57
+ path: dist/
58
+
59
+ - name: Publish to PyPI
60
+ uses: pypa/gh-action-pypi-publish@release/v1
@@ -0,0 +1,37 @@
1
+ # Python
2
+ __pycache__/
3
+ *.py[cod]
4
+ *$py.class
5
+ *.so
6
+ *.egg-info/
7
+ *.egg
8
+ dist/
9
+ build/
10
+ .eggs/
11
+
12
+ # Virtual environments
13
+ .venv/
14
+ venv/
15
+ env/
16
+
17
+ # IDE
18
+ .idea/
19
+ .vscode/
20
+ *.swp
21
+ *.swo
22
+ *~
23
+
24
+ # Testing / Coverage
25
+ .pytest_cache/
26
+ .coverage
27
+ htmlcov/
28
+ .mypy_cache/
29
+ .ruff_cache/
30
+
31
+ # OS
32
+ .DS_Store
33
+ Thumbs.db
34
+
35
+ # Environment
36
+ .env
37
+ .env.local
@@ -0,0 +1,247 @@
1
+ # AGENTS.md
2
+
3
+ ## Purpose
4
+
5
+ This repository is built for agentic coding and Codex-heavy development.
6
+
7
+ The project is a Python 3.10+ framework with a small stable public API and provider-specific adapters.
8
+
9
+ ## Read these first
10
+
11
+ 1. `VALIDATION.md`
12
+ 2. `PRD.md`
13
+ 3. `ARCHITECTURE.md`
14
+ 4. `CANONICAL_MODEL.md`
15
+ 5. `PROVIDER_ADAPTER_CONTRACT.md`
16
+ 6. `API_SPEC.md`
17
+ 7. `PACKAGING.md`
18
+
19
+ ## Rules of engagement
20
+
21
+ - Keep the public API small.
22
+ - Do not turn provider quirks into fake universal semantics.
23
+ - Do not remove raw escape hatches.
24
+ - Do not mark a capability as supported unless tests prove it.
25
+ - Keep provider complexity in provider adapters.
26
+ - Update tests and docs with every behavior change.
27
+ - `SUPPORTED_DATA.md`는 지원 Provider/Dataset 현황의 단일 기준 문서(single source of truth)다.
28
+ - Provider/Dataset의 지원 상태 또는 검증 수준이 바뀌면, 같은 PR에서 `SUPPORTED_DATA.md`를 반드시 업데이트한다.
29
+ - `지원`은 fixture/unit/contract 테스트가 통과했을 때만 표시한다.
30
+ - `실API 검증`은 실 API integration 테스트가 존재하고 통과했을 때만 표시한다. 그 전에는 `테스트 검증`으로 유지한다.
31
+
32
+ ## Language policy
33
+
34
+ - **Documentation**: Write in Korean by default. English expansion is planned for future releases.
35
+ - **Code**: All code (variable names, function names, comments, docstrings) must be in English.
36
+ - **Commit messages**: Always in English.
37
+ - **Issue / PR titles and descriptions**: Korean is acceptable; English is also fine.
38
+
39
+ ## Branch rules
40
+
41
+ - Default branch is `main`. **Never push directly to `main`.**
42
+ - Always work on a feature branch and open a PR.
43
+ - Branch naming: `feat/issue-<number>-<short-description>`, `fix/issue-<number>-<short-description>`, `docs/<short-description>`
44
+ - Never force-push to `main`. Never delete `main`.
45
+ - Never rename or delete branches you did not create.
46
+ - If unsure about any git operation, **ask first — do not guess.**
47
+
48
+ ## When to write a plan
49
+
50
+ Before multi-file or architecture-affecting work, create or update a task plan in a local plan file.
51
+
52
+ The plan should include:
53
+
54
+ - scope
55
+ - touched modules
56
+ - risks
57
+ - validation steps
58
+
59
+ ## Quality gates
60
+
61
+ Run before marking work complete:
62
+
63
+ ```bash
64
+ uv sync --extra dev
65
+ uv run ruff check .
66
+ uv run ruff format --check .
67
+ uv run mypy src
68
+ uv run pytest
69
+ uv run python -m build
70
+ ```
71
+
72
+ ## Adapter work rules
73
+
74
+ When adding a provider adapter:
75
+
76
+ - add fixture responses
77
+ - add unit tests
78
+ - add contract tests
79
+ - document capabilities honestly
80
+ - keep `call_raw` working
81
+
82
+ ## Public API change rule
83
+
84
+ If a public method, public model, or canonical exception changes:
85
+
86
+ - update `API_SPEC.md`
87
+ - update `PRD.md` if requirements changed
88
+ - add release note/changelog entry
89
+
90
+ ---
91
+
92
+ ## 이 프로젝트 이해하기
93
+
94
+ KPubData는 한국 공공데이터(data.go.kr 등)라는 거대한 도서관에서 책을 찾아주는 **똑똑한 사서**와 같습니다. 도서관마다 책을 분류하는 방식이 제각각이지만, 사서는 여러분에게 항상 동일한 방식으로 책을 찾아다 줍니다.
95
+
96
+ ### 핵심 개념 용어 사전
97
+
98
+ | 용어 | 설명 |
99
+ | :--- | :--- |
100
+ | **Provider** | 데이터를 제공하는 기관 (예: 공공데이터포털, 기상청 등) |
101
+ | **Adapter** | 각 기관의 서로 다른 API 규칙을 KPubData 표준에 맞게 변환해주는 통역사 |
102
+ | **Dataset** | 실제 데이터의 집합 (예: 동네예보, 대기오염정보 등) |
103
+ | **Query** | 데이터를 찾기 위해 던지는 질문 (검색 조건) |
104
+ | **RecordBatch** | 검색 결과로 돌아온 데이터 뭉치 |
105
+ | **Canonical Model** | 기관마다 다른 데이터 형식을 하나로 통일한 표준 모델 |
106
+ | **Raw Escape Hatch** | 표준화된 방식 대신 원본 API를 그대로 쓰고 싶을 때 사용하는 비상구 (`call_raw`) |
107
+
108
+ ### 이 프로젝트의 코드가 실행되는 흐름
109
+
110
+ ```text
111
+ [User] -> [Client] -> [Dataset] -> [Adapter] -> [Transport] -> [Public Data API]
112
+ ^ |
113
+ | v
114
+ [User] <- [RecordBatch] <----------- [Parser] <--- [Raw Response]
115
+ ```
116
+
117
+ ```mermaid
118
+ sequenceDiagram
119
+ participant U as 사용자 (User)
120
+ participant C as 클라이언트 (Client)
121
+ participant Cat as 카탈로그 (Catalog)
122
+ participant A as 어댑터 (Adapter)
123
+ participant T as 전송 계층 (Transport)
124
+ participant P as 공공 API (Public API)
125
+
126
+ U->>C: 데이터셋 요청
127
+ C->>Cat: 데이터셋 검색/확인
128
+ Cat-->>C: 데이터셋 객체 반환
129
+ U->>C: 데이터 조회 (list/get)
130
+ C->>A: 요청 위임
131
+ A->>T: HTTP 요청
132
+ T->>P: 실제 데이터 요청
133
+ P-->>T: 원본 데이터 응답
134
+ T-->>A: 파싱된 데이터 전달
135
+ A-->>U: RecordBatch 반환
136
+ ```
137
+
138
+ ## AI 에이전트 코딩 가이드
139
+
140
+ 에이전트(Copilot, Cursor 등)를 사용하여 개발할 때 다음 규칙을 준수하세요.
141
+
142
+ ### 좋은 프롬프트 예시
143
+ - "`datago` 어댑터에 새로운 `Dataset`인 `air_quality`를 추가해줘. `PROVIDER_ADAPTER_CONTRACT.md`를 참고해서 구현하고, `tests/fixtures`에 응답 샘플도 추가해."
144
+ - "`RecordBatch` 모델에 `to_pandas()` 메서드를 추가하고 관련 유닛 테스트를 작성해줘."
145
+
146
+ ### 에이전트 금지 사항
147
+ - **Any 타입 남발 금지**: `typing.Any`를 사용하지 말고 명확한 타입을 정의하세요.
148
+ - **type: ignore 금지**: 타입 오류를 해결하지 않고 무시하지 마세요.
149
+ - **테스트 코드 삭제 금지**: 기존 테스트를 지우지 마세요.
150
+ - **Fake universal semantics 금지**: 특정 기관에만 있는 기능을 모든 기관이 지원하는 것처럼 속이지 마세요.
151
+
152
+ ### 에이전트 결과물 검증 체크리스트
153
+ - [ ] `mypy` 검사를 통과했는가?
154
+ - [ ] `pytest`가 모두 성공하는가?
155
+ - [ ] `src/` 외부의 파일을 수정하지 않았는가?
156
+ - [ ] `API_SPEC.md`에 정의되지 않은 public 메서드를 추가하지 않았는가?
157
+
158
+ ## 파일 구조 가이드
159
+
160
+ ```text
161
+ src/kpubdata/
162
+ ├── core/ # 핵심 비즈니스 로직 및 추상 클래스
163
+ ├── transport/ # HTTP 통신 처리
164
+ ├── providers/ # 데이터 제공 기관 정의
165
+ ├── adapters/ # 기관별 데이터 변환 로직 (가장 자주 수정하게 될 곳)
166
+ ├── client.py # 사용자가 처음 만나는 입구
167
+ ├── catalog.py # 사용 가능한 데이터셋 목록 관리
168
+ └── exceptions.py # 공통 에러 정의
169
+ ```
170
+
171
+ ```mermaid
172
+ graph TD
173
+ root[src/kpubdata/] --> core[core/]
174
+ root --> transport[transport/]
175
+ root --> providers[providers/]
176
+ root --> adapters[adapters/]
177
+ root --> client[client.py]
178
+ root --> catalog[catalog.py]
179
+ root --> exceptions[exceptions.py]
180
+
181
+ core --> core_desc[핵심 비즈니스 로직]
182
+ transport --> transport_desc[HTTP 통신 처리]
183
+ providers --> providers_desc[기관 정의]
184
+ adapters --> adapters_desc[데이터 변환 로직]
185
+ ```
186
+
187
+ ### 이 파일을 수정해야 할 때
188
+ - **새로운 데이터 기관을 추가하고 싶을 때**: `adapters/`에 새 디렉토리를 만들고 `core/`의 추상 클래스를 구현합니다.
189
+ - **데이터 조회 방식을 개선하고 싶을 때**: `core/query.py`나 `core/record.py`를 수정합니다.
190
+
191
+ ## 어댑터 개발 가이드
192
+
193
+ ### 개발 시작부터 완료까지 체크리스트
194
+ 1. [ ] 원본 API의 응답 예시(XML/JSON)를 `tests/fixtures/<provider>/<dataset>.json`에 저장
195
+ 2. [ ] `ProviderAdapter` 추상 클래스를 상속받아 클래스 생성
196
+ 3. [ ] `list()`, `get()` 등 필요한 동작 구현
197
+ 4. [ ] `capabilities` 속성에 지원하는 기능 명시
198
+ 5. [ ] `call_raw`가 항상 원본 데이터를 반환하도록 보장
199
+ 6. [ ] `tests/unit/adapters/`에 유닛 테스트 추가
200
+ 7. [ ] `tests/contract/`에 계약 테스트(Contract Test) 추가
201
+ 8. [ ] `SUPPORTED_DATA.md` 업데이트 (`상태`, `검증`, `인증`, `공식 문서`, `비고`)
202
+
203
+ ```mermaid
204
+ flowchart TD
205
+ Start[시작] --> F1[1. 원본 API 응답 Fixture 저장]
206
+ F1 --> F2[2. ProviderAdapter 상속 클래스 생성]
207
+ F2 --> F3[3. list/get 등 핵심 동작 구현]
208
+ F3 --> F4[4. capabilities 기능 명시]
209
+ F4 --> F5[5. call_raw 보장]
210
+ F5 --> F6[6. 유닛 테스트 추가]
211
+ F6 --> F7[7. 계약 테스트 통과 확인]
212
+ F7 --> F8[8. SUPPORTED_DATA.md 업데이트]
213
+ F8 --> End[완료]
214
+ ```
215
+
216
+ ### 핵심 추상 클래스 설명
217
+ - **ProviderAdapter**: 모든 어댑터의 부모입니다. 인증, 요청 생성, 응답 파싱을 담당합니다.
218
+ - **DatasetRef**: 특정 데이터셋을 가리키는 주소 정보입니다.
219
+ - **Query**: 데이터 필터링 조건을 담는 객체입니다.
220
+ - **RecordBatch**: 표준화된 데이터 레코드들의 묶음입니다.
221
+
222
+ ### 테스트 작성 가이드
223
+ - **Fixture 기반 테스트**: 가짜 서버를 띄우는 대신, 미리 저장해둔 응답 파일(`fixture`)을 사용하여 어댑터가 올바르게 파싱하는지 확인합니다.
224
+ - **Contract 테스트**: 어댑터가 KPubData의 표준 규약(Contract)을 잘 지키고 있는지 확인하는 테스트입니다. 모든 어댑터는 동일한 인터페이스를 통과해야 합니다.
225
+
226
+ ---
227
+
228
+ ## 관련 문서
229
+
230
+ ### 이 저장소 내 문서
231
+ | 문서 | 설명 |
232
+ | :--- | :--- |
233
+ | [CONTRIBUTING.md](./CONTRIBUTING.md) | 프로젝트 기여 가이드 |
234
+ | [ARCHITECTURE.md](./ARCHITECTURE.md) | 시스템 아키텍처 설계 |
235
+ | [PROVIDER_ADAPTER_CONTRACT.md](./PROVIDER_ADAPTER_CONTRACT.md) | 어댑터 구현 규약 |
236
+ | [CANONICAL_MODEL.md](./CANONICAL_MODEL.md) | 표준 데이터 모델 정의 |
237
+ | [VALIDATION.md](./VALIDATION.md) | 아키텍처 타당성 검증 |
238
+ | [API_SPEC.md](./API_SPEC.md) | 파이썬 API 명세 |
239
+ | [PRD.md](./PRD.md) | 제품 요구사항 정의 |
240
+ | [PACKAGING.md](./PACKAGING.md) | 패키징 및 배포 전략 |
241
+ | [SUPPORTED_DATA.md](./SUPPORTED_DATA.md) | 지원 공공데이터 현황 및 진행 상태 |
242
+
243
+ ### KPubData Product Family
244
+ | 저장소 | 문서 | 설명 |
245
+ | :--- | :--- | :--- |
246
+ | [kpubdata-builder](https://github.com/yeongseon/kpubdata-builder) | [AGENTS.md](https://github.com/yeongseon/kpubdata-builder/blob/main/AGENTS.md) | Builder 에이전트 가이드 |
247
+ | [kpubdata-studio](https://github.com/yeongseon/kpubdata-studio) | [AGENTS.md](https://github.com/yeongseon/kpubdata-studio/blob/main/AGENTS.md) | Studio 에이전트 가이드 |