kubera-core 0.1.1__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 (61) hide show
  1. kubera_core-0.1.1/.env.example +2 -0
  2. kubera_core-0.1.1/.github/ISSUE_TEMPLATE/api_request.yml +46 -0
  3. kubera_core-0.1.1/.github/ISSUE_TEMPLATE/bug_report.yml +36 -0
  4. kubera_core-0.1.1/.github/ISSUE_TEMPLATE/config.yml +1 -0
  5. kubera_core-0.1.1/.github/ISSUE_TEMPLATE/enhancement.yml +18 -0
  6. kubera_core-0.1.1/.github/workflows/publish.yml +21 -0
  7. kubera_core-0.1.1/.github/workflows/sync-spec.yml +54 -0
  8. kubera_core-0.1.1/.gitignore +41 -0
  9. kubera_core-0.1.1/CLAUDE.md +24 -0
  10. kubera_core-0.1.1/LICENSE +21 -0
  11. kubera_core-0.1.1/PKG-INFO +74 -0
  12. kubera_core-0.1.1/README.md +45 -0
  13. kubera_core-0.1.1/alembic/env.py +44 -0
  14. kubera_core-0.1.1/alembic.ini +36 -0
  15. kubera_core-0.1.1/config/settings.yaml +6 -0
  16. kubera_core-0.1.1/openapi.json +1340 -0
  17. kubera_core-0.1.1/pyproject.toml +52 -0
  18. kubera_core-0.1.1/scripts/export_openapi.py +19 -0
  19. kubera_core-0.1.1/src/kubera/CONTEXT.md +16 -0
  20. kubera_core-0.1.1/src/kubera/__init__.py +3 -0
  21. kubera_core-0.1.1/src/kubera/api/CONTEXT.md +34 -0
  22. kubera_core-0.1.1/src/kubera/api/__init__.py +0 -0
  23. kubera_core-0.1.1/src/kubera/api/auth.py +30 -0
  24. kubera_core-0.1.1/src/kubera/api/deps.py +21 -0
  25. kubera_core-0.1.1/src/kubera/api/errors.py +20 -0
  26. kubera_core-0.1.1/src/kubera/api/main.py +53 -0
  27. kubera_core-0.1.1/src/kubera/api/routers/__init__.py +0 -0
  28. kubera_core-0.1.1/src/kubera/api/routers/snapshots.py +133 -0
  29. kubera_core-0.1.1/src/kubera/api/schemas/__init__.py +0 -0
  30. kubera_core-0.1.1/src/kubera/api/schemas/common.py +37 -0
  31. kubera_core-0.1.1/src/kubera/api/schemas/snapshot.py +118 -0
  32. kubera_core-0.1.1/src/kubera/cli/CONTEXT.md +19 -0
  33. kubera_core-0.1.1/src/kubera/cli/__init__.py +65 -0
  34. kubera_core-0.1.1/src/kubera/cli/commands.py +310 -0
  35. kubera_core-0.1.1/src/kubera/core/CONTEXT.md +36 -0
  36. kubera_core-0.1.1/src/kubera/core/__init__.py +0 -0
  37. kubera_core-0.1.1/src/kubera/core/config.py +110 -0
  38. kubera_core-0.1.1/src/kubera/core/models/__init__.py +24 -0
  39. kubera_core-0.1.1/src/kubera/core/models/base.py +43 -0
  40. kubera_core-0.1.1/src/kubera/core/snapshot/CONTEXT.md +37 -0
  41. kubera_core-0.1.1/src/kubera/core/snapshot/__init__.py +0 -0
  42. kubera_core-0.1.1/src/kubera/core/snapshot/mail_watcher.py +180 -0
  43. kubera_core-0.1.1/src/kubera/core/snapshot/models.py +120 -0
  44. kubera_core-0.1.1/src/kubera/core/snapshot/parser.py +520 -0
  45. kubera_core-0.1.1/src/kubera/core/snapshot/service.py +250 -0
  46. kubera_core-0.1.1/tests/__init__.py +0 -0
  47. kubera_core-0.1.1/tests/conftest.py +73 -0
  48. kubera_core-0.1.1/tests/test_auth.py +53 -0
  49. kubera_core-0.1.1/tests/test_cli.py +59 -0
  50. kubera_core-0.1.1/tests/test_config.py +61 -0
  51. kubera_core-0.1.1/tests/test_cors.py +70 -0
  52. kubera_core-0.1.1/tests/test_credential_cli.py +134 -0
  53. kubera_core-0.1.1/tests/test_health.py +26 -0
  54. kubera_core-0.1.1/tests/test_import.py +13 -0
  55. kubera_core-0.1.1/tests/test_mail_watch_cli.py +190 -0
  56. kubera_core-0.1.1/tests/test_mail_watcher.py +338 -0
  57. kubera_core-0.1.1/tests/test_snapshot_api.py +353 -0
  58. kubera_core-0.1.1/tests/test_snapshot_cli.py +111 -0
  59. kubera_core-0.1.1/tests/test_snapshot_models.py +261 -0
  60. kubera_core-0.1.1/tests/test_snapshot_parser.py +333 -0
  61. kubera_core-0.1.1/uv.lock +1053 -0
@@ -0,0 +1,2 @@
1
+ KUBERA_SECRET_TOKEN=
2
+ KUBERA_DATABASE_URL=sqlite:///kubera.db
@@ -0,0 +1,46 @@
1
+ name: API Request
2
+ description: Request a new or modified API endpoint
3
+ labels: ["api-request"]
4
+ body:
5
+ - type: input
6
+ id: endpoint
7
+ attributes:
8
+ label: Requested endpoint
9
+ description: The endpoint being requested
10
+ placeholder: "GET /api/v1/..."
11
+ validations:
12
+ required: true
13
+ - type: textarea
14
+ id: description
15
+ attributes:
16
+ label: Description
17
+ description: What this endpoint should do
18
+ validations:
19
+ required: true
20
+ - type: textarea
21
+ id: schema
22
+ attributes:
23
+ label: Request / Response schema
24
+ description: Expected request and response format
25
+ placeholder: |
26
+ Request:
27
+ POST /api/v1/users { "name": "string", "email": "string" }
28
+ Response:
29
+ 201 { "id": "number", "name": "string", "email": "string" }
30
+ validations:
31
+ required: true
32
+ - type: textarea
33
+ id: use-case
34
+ attributes:
35
+ label: Use case
36
+ description: Why is this endpoint needed?
37
+ validations:
38
+ required: true
39
+ - type: input
40
+ id: origin-issue
41
+ attributes:
42
+ label: Origin issue
43
+ description: The issue that triggered this request
44
+ placeholder: "oh-my-kubera/kubera-web#123"
45
+ validations:
46
+ required: false
@@ -0,0 +1,36 @@
1
+ name: Bug Report
2
+ description: Report a bug or unexpected behavior
3
+ labels: ["bug"]
4
+ body:
5
+ - type: textarea
6
+ id: description
7
+ attributes:
8
+ label: Description
9
+ description: What happened? Include error messages if any.
10
+ validations:
11
+ required: true
12
+ - type: textarea
13
+ id: steps
14
+ attributes:
15
+ label: Steps to reproduce
16
+ description: Steps to reproduce the behavior
17
+ placeholder: |
18
+ 1. Go to '...'
19
+ 2. Click on '...'
20
+ 3. See error
21
+ validations:
22
+ required: true
23
+ - type: textarea
24
+ id: expected
25
+ attributes:
26
+ label: Expected behavior
27
+ description: What you expected to happen
28
+ validations:
29
+ required: true
30
+ - type: textarea
31
+ id: actual
32
+ attributes:
33
+ label: Actual behavior
34
+ description: What actually happened
35
+ validations:
36
+ required: true
@@ -0,0 +1 @@
1
+ blank_issues_enabled: false
@@ -0,0 +1,18 @@
1
+ name: Enhancement
2
+ description: Suggest an improvement or new feature
3
+ labels: ["enhancement"]
4
+ body:
5
+ - type: textarea
6
+ id: description
7
+ attributes:
8
+ label: Description
9
+ description: A clear description of the enhancement
10
+ validations:
11
+ required: true
12
+ - type: textarea
13
+ id: motivation
14
+ attributes:
15
+ label: Motivation / use case
16
+ description: Why is this enhancement needed? What problem does it solve?
17
+ validations:
18
+ required: true
@@ -0,0 +1,21 @@
1
+ name: Publish to PyPI
2
+
3
+ on:
4
+ release:
5
+ types: [published]
6
+
7
+ jobs:
8
+ publish:
9
+ runs-on: ubuntu-latest
10
+ environment: pypi
11
+ permissions:
12
+ contents: read
13
+ id-token: write
14
+ steps:
15
+ - uses: actions/checkout@v4
16
+
17
+ - uses: astral-sh/setup-uv@v4
18
+
19
+ - run: uv build
20
+
21
+ - uses: pypa/gh-action-pypi-publish@release/v1
@@ -0,0 +1,54 @@
1
+ name: Sync OpenAPI spec to kubera-web
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ paths:
7
+ - "src/kubera/api/**"
8
+ - "scripts/export_openapi.py"
9
+
10
+ jobs:
11
+ sync-spec:
12
+ runs-on: ubuntu-latest
13
+ steps:
14
+ - uses: actions/checkout@v4
15
+
16
+ - uses: actions/setup-python@v5
17
+ with:
18
+ python-version: "3.12"
19
+
20
+ - name: Install dependencies
21
+ run: pip install -e .
22
+
23
+ - name: Export openapi.json
24
+ run: python scripts/export_openapi.py
25
+
26
+ - name: Checkout kubera-web
27
+ uses: actions/checkout@v4
28
+ with:
29
+ repository: oh-my-kubera/kubera-web
30
+ token: ${{ secrets.KUBERA_ORG_PAT }}
31
+ ref: develop
32
+ path: kubera-web
33
+
34
+ - name: Check for changes
35
+ id: diff
36
+ run: |
37
+ mkdir -p kubera-web/specs
38
+ diff -q openapi.json kubera-web/specs/core-openapi.json && echo "changed=false" >> $GITHUB_OUTPUT || echo "changed=true" >> $GITHUB_OUTPUT
39
+
40
+ - name: Update spec
41
+ if: steps.diff.outputs.changed == 'true'
42
+ run: cp openapi.json kubera-web/specs/core-openapi.json
43
+
44
+ - name: Create PR
45
+ if: steps.diff.outputs.changed == 'true'
46
+ uses: peter-evans/create-pull-request@v7
47
+ with:
48
+ token: ${{ secrets.KUBERA_ORG_PAT }}
49
+ path: kubera-web
50
+ base: develop
51
+ branch: chore/update-core-spec
52
+ title: "chore: update core openapi.json"
53
+ body: "Auto-generated from kubera-core ${{ github.sha }}"
54
+ commit-message: "chore: update core openapi.json"
@@ -0,0 +1,41 @@
1
+ # Python
2
+ __pycache__/
3
+ *.py[cod]
4
+ *$py.class
5
+ *.egg-info/
6
+ *.egg
7
+ dist/
8
+ build/
9
+
10
+ # Virtual environment
11
+ .venv/
12
+
13
+ # Database
14
+ *.db
15
+ *.db-journal
16
+ *.db-wal
17
+ *.db-shm
18
+
19
+ # Environment
20
+ .env
21
+
22
+ # IDE
23
+ .idea/
24
+ .vscode/
25
+ *.swp
26
+ *.swo
27
+
28
+ # OS
29
+ .DS_Store
30
+ Thumbs.db
31
+
32
+ # OMC
33
+ .omc/
34
+
35
+ # Claude Code
36
+ .claude/
37
+
38
+ # Coverage
39
+ htmlcov/
40
+ .coverage
41
+ .coverage.*
@@ -0,0 +1,24 @@
1
+ # kubera-core
2
+
3
+ ## API Contract First
4
+ - When adding or changing API endpoints, **define schemas first** before implementation
5
+ - Order: schema design → export openapi.json → create kubera-web issue → implement
6
+ - Finalize and share response schemas early so web can develop in parallel
7
+ - Schemas must clearly specify all fields, types, nullable, and nested structures
8
+
9
+ ## Security
10
+ - Credential keys: CLI only for input/viewing. API returns status only.
11
+
12
+ ## Deployment Constraints
13
+ - Runs on user's PC (self-hosted) — not a managed server
14
+ - Must work cross-platform: Windows, macOS, Linux
15
+ - Zero-config ideal: `pip install kubera-core && kubera-core start`
16
+ - SQLite default — no external services required
17
+ - Keep dependencies minimal and cross-platform compatible
18
+
19
+ ## Build & Test
20
+ - Package manager: `uv`
21
+ - Run tests: `uv run pytest`
22
+ - Run single test: `uv run pytest tests/test_xxx.py`
23
+ - Export OpenAPI: `uv run python scripts/export_openapi.py`
24
+ - Dev server: `uv run kubera-core start`
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 SanGyuk-Raccoon
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,74 @@
1
+ Metadata-Version: 2.4
2
+ Name: kubera-core
3
+ Version: 0.1.1
4
+ Summary: Personal asset management backend
5
+ Project-URL: Homepage, https://github.com/oh-my-kubera/kubera-core
6
+ Project-URL: Repository, https://github.com/oh-my-kubera/kubera-core
7
+ Project-URL: Issues, https://github.com/oh-my-kubera/kubera-core/issues
8
+ Author-email: SanGyuk-Raccoon <dmstjkim80@gmail.com>
9
+ License: MIT
10
+ License-File: LICENSE
11
+ Classifier: Development Status :: 3 - Alpha
12
+ Classifier: License :: OSI Approved :: MIT License
13
+ Classifier: Programming Language :: Python :: 3
14
+ Classifier: Programming Language :: Python :: 3.11
15
+ Classifier: Programming Language :: Python :: 3.12
16
+ Classifier: Programming Language :: Python :: 3.13
17
+ Requires-Python: >=3.11
18
+ Requires-Dist: alembic>=1.13.0
19
+ Requires-Dist: cryptography>=43.0
20
+ Requires-Dist: fastapi>=0.115.0
21
+ Requires-Dist: openpyxl>=3.1.5
22
+ Requires-Dist: pydantic-settings>=2.0
23
+ Requires-Dist: pydantic>=2.0
24
+ Requires-Dist: python-multipart>=0.0.9
25
+ Requires-Dist: pyyaml>=6.0
26
+ Requires-Dist: sqlalchemy>=2.0
27
+ Requires-Dist: uvicorn[standard]>=0.30.0
28
+ Description-Content-Type: text/markdown
29
+
30
+ # Kubera Core
31
+
32
+ Personal asset management backend. All financial data stays on your machine.
33
+
34
+ ## Install & Run
35
+
36
+ ```bash
37
+ pip install kubera-core
38
+ kubera-core start
39
+ ```
40
+
41
+ - API docs: http://localhost:8000/docs
42
+ - Auth token is auto-generated and printed on first start
43
+
44
+ ## Options
45
+
46
+ ```bash
47
+ kubera-core start --host 127.0.0.1 --port 3000
48
+ kubera-core token # show current token
49
+ kubera-core token --refresh # generate new token
50
+ ```
51
+
52
+ ## Credential Management
53
+
54
+ API keys for financial services are managed via CLI only (never through web).
55
+
56
+ ```bash
57
+ kubera-core credential add upbit # interactive masked input
58
+ kubera-core credential list # show status
59
+ kubera-core credential remove upbit
60
+ ```
61
+
62
+ Supported providers: upbit, kis, binance, codef
63
+
64
+ ## Tech Stack
65
+
66
+ FastAPI, SQLAlchemy (SQLite), Pydantic, cryptography (Fernet)
67
+
68
+ ## Related
69
+
70
+ - [kubera-web](https://github.com/oh-my-kubera/kubera-web) — Next.js dashboard (PWA)
71
+
72
+ ## License
73
+
74
+ MIT
@@ -0,0 +1,45 @@
1
+ # Kubera Core
2
+
3
+ Personal asset management backend. All financial data stays on your machine.
4
+
5
+ ## Install & Run
6
+
7
+ ```bash
8
+ pip install kubera-core
9
+ kubera-core start
10
+ ```
11
+
12
+ - API docs: http://localhost:8000/docs
13
+ - Auth token is auto-generated and printed on first start
14
+
15
+ ## Options
16
+
17
+ ```bash
18
+ kubera-core start --host 127.0.0.1 --port 3000
19
+ kubera-core token # show current token
20
+ kubera-core token --refresh # generate new token
21
+ ```
22
+
23
+ ## Credential Management
24
+
25
+ API keys for financial services are managed via CLI only (never through web).
26
+
27
+ ```bash
28
+ kubera-core credential add upbit # interactive masked input
29
+ kubera-core credential list # show status
30
+ kubera-core credential remove upbit
31
+ ```
32
+
33
+ Supported providers: upbit, kis, binance, codef
34
+
35
+ ## Tech Stack
36
+
37
+ FastAPI, SQLAlchemy (SQLite), Pydantic, cryptography (Fernet)
38
+
39
+ ## Related
40
+
41
+ - [kubera-web](https://github.com/oh-my-kubera/kubera-web) — Next.js dashboard (PWA)
42
+
43
+ ## License
44
+
45
+ MIT
@@ -0,0 +1,44 @@
1
+ """Alembic environment configuration."""
2
+
3
+ from logging.config import fileConfig
4
+
5
+ from alembic import context
6
+ from sqlalchemy import engine_from_config, pool
7
+
8
+ from kubera.core.models import Base
9
+
10
+ config = context.config
11
+ if config.config_file_name is not None:
12
+ fileConfig(config.config_file_name)
13
+
14
+ target_metadata = Base.metadata
15
+
16
+
17
+ def run_migrations_offline() -> None:
18
+ url = config.get_main_option("sqlalchemy.url")
19
+ context.configure(
20
+ url=url,
21
+ target_metadata=target_metadata,
22
+ literal_binds=True,
23
+ dialect_opts={"paramstyle": "named"},
24
+ )
25
+ with context.begin_transaction():
26
+ context.run_migrations()
27
+
28
+
29
+ def run_migrations_online() -> None:
30
+ connectable = engine_from_config(
31
+ config.get_section(config.config_ini_section, {}),
32
+ prefix="sqlalchemy.",
33
+ poolclass=pool.NullPool,
34
+ )
35
+ with connectable.connect() as connection:
36
+ context.configure(connection=connection, target_metadata=target_metadata)
37
+ with context.begin_transaction():
38
+ context.run_migrations()
39
+
40
+
41
+ if context.is_offline_mode():
42
+ run_migrations_offline()
43
+ else:
44
+ run_migrations_online()
@@ -0,0 +1,36 @@
1
+ [alembic]
2
+ script_location = alembic
3
+ sqlalchemy.url = sqlite:///kubera.db
4
+
5
+ [loggers]
6
+ keys = root,sqlalchemy,alembic
7
+
8
+ [handlers]
9
+ keys = console
10
+
11
+ [formatters]
12
+ keys = generic
13
+
14
+ [logger_root]
15
+ level = WARN
16
+ handlers = console
17
+
18
+ [logger_sqlalchemy]
19
+ level = WARN
20
+ handlers =
21
+ qualname = sqlalchemy.engine
22
+
23
+ [logger_alembic]
24
+ level = INFO
25
+ handlers =
26
+ qualname = alembic
27
+
28
+ [handler_console]
29
+ class = StreamHandler
30
+ args = (sys.stderr,)
31
+ level = NOTSET
32
+ formatter = generic
33
+
34
+ [formatter_generic]
35
+ format = %(levelname)-5.5s [%(name)s] %(message)s
36
+ datefmt = %H:%M:%S
@@ -0,0 +1,6 @@
1
+ database_url: "sqlite:///kubera.db"
2
+ host: "0.0.0.0"
3
+ port: 8000
4
+ debug: false
5
+ cors_origins:
6
+ - "*"