chore: scaffold payroll extension
Repo tooling and LNbits extension metadata only — no runtime code yet, so this lands separately from the feature work per the workspace commit rules (cross-cutting concerns commit first). - MIT licence, .gitignore, README - Makefile + pyproject wired for the standard aio fork lint pipeline (black + ruff + mypy) and pytest - config.json declaring id/version/tile so the extension is installable from the aiolabs catalog once there is something to install Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018jy52j9GRZ6XKa1Zt21LLj
This commit is contained in:
commit
a211a8ab8b
7 changed files with 191 additions and 0 deletions
10
.gitignore
vendored
Normal file
10
.gitignore
vendored
Normal file
|
|
@ -0,0 +1,10 @@
|
||||||
|
__pycache__/
|
||||||
|
*.py[cod]
|
||||||
|
*.egg-info/
|
||||||
|
.venv/
|
||||||
|
node_modules/
|
||||||
|
*.sqlite3
|
||||||
|
.DS_Store
|
||||||
|
.pytest_cache/
|
||||||
|
.ruff_cache/
|
||||||
|
.mypy_cache/
|
||||||
21
LICENSE
Normal file
21
LICENSE
Normal file
|
|
@ -0,0 +1,21 @@
|
||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2026 aiolabs
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
32
Makefile
Normal file
32
Makefile
Normal file
|
|
@ -0,0 +1,32 @@
|
||||||
|
all: format check
|
||||||
|
|
||||||
|
format: black ruff
|
||||||
|
|
||||||
|
check: mypy checkblack checkruff
|
||||||
|
|
||||||
|
mypy:
|
||||||
|
uv run mypy .
|
||||||
|
|
||||||
|
black:
|
||||||
|
uv run black .
|
||||||
|
|
||||||
|
ruff:
|
||||||
|
uv run ruff check . --fix
|
||||||
|
|
||||||
|
checkruff:
|
||||||
|
uv run ruff check .
|
||||||
|
|
||||||
|
checkblack:
|
||||||
|
uv run black --check .
|
||||||
|
|
||||||
|
test:
|
||||||
|
PYTHONUNBUFFERED=1 \
|
||||||
|
DEBUG=true \
|
||||||
|
uv run pytest
|
||||||
|
|
||||||
|
install-pre-commit-hook:
|
||||||
|
@echo "Installing pre-commit hook to git"
|
||||||
|
uv run pre-commit install
|
||||||
|
|
||||||
|
pre-commit:
|
||||||
|
uv run pre-commit run --all-files
|
||||||
42
README.md
Normal file
42
README.md
Normal file
|
|
@ -0,0 +1,42 @@
|
||||||
|
# Payroll
|
||||||
|
|
||||||
|
Scheduled recurring payouts between LNbits wallets, driven by the instance
|
||||||
|
**super user**.
|
||||||
|
|
||||||
|
Pick a user from the account directory, point the payout at one of their
|
||||||
|
wallets, set an amount + currency, a start date, how often it pays and how
|
||||||
|
many times — Payroll then moves the money on schedule, from a source wallet
|
||||||
|
you control, and keeps a ledger of every attempt.
|
||||||
|
|
||||||
|
## Status
|
||||||
|
|
||||||
|
Early. Built for `aiolabs` LNbits instances; see `docs/` for the data model
|
||||||
|
and operational notes.
|
||||||
|
|
||||||
|
## Who can use it
|
||||||
|
|
||||||
|
Everything under `/payroll/api/v1/` that reads the account directory or
|
||||||
|
touches a contract is gated on `check_super_user` — payroll moves money
|
||||||
|
between accounts the operator does not own, so wallet-level admin keys are
|
||||||
|
deliberately *not* enough. (`require_admin_key` authorises writes to your
|
||||||
|
own wallet only; it is not instance-admin. See the auth table in the
|
||||||
|
workspace `CLAUDE.md`.)
|
||||||
|
|
||||||
|
Add `payroll` to `LNBITS_ADMIN_EXTENSIONS` so the extension is hidden from
|
||||||
|
ordinary users in the UI as well.
|
||||||
|
|
||||||
|
## Development
|
||||||
|
|
||||||
|
```
|
||||||
|
make # black + ruff + mypy
|
||||||
|
make test # pytest
|
||||||
|
```
|
||||||
|
|
||||||
|
The dev LNbits compose mounts `~/dev/shared/extensions/` at `/shared` with
|
||||||
|
`LNBITS_EXTENSIONS_PATH=/shared`, so this checkout *is* the installed
|
||||||
|
extension. FakeWallet is enough — no regtest needed for anything except
|
||||||
|
end-to-end Lightning behaviour.
|
||||||
|
|
||||||
|
## Licence
|
||||||
|
|
||||||
|
MIT
|
||||||
23
config.json
Normal file
23
config.json
Normal file
|
|
@ -0,0 +1,23 @@
|
||||||
|
{
|
||||||
|
"id": "payroll",
|
||||||
|
"version": "0.1.0",
|
||||||
|
"name": "Payroll",
|
||||||
|
"repo": "https://git.atitlan.io/aiolabs/payroll",
|
||||||
|
"short_description": "Scheduled recurring salary payouts between LNbits wallets",
|
||||||
|
"description": "",
|
||||||
|
"tile": "/payroll/static/image/payroll.png",
|
||||||
|
"min_lnbits_version": "1.4.1",
|
||||||
|
"contributors": [
|
||||||
|
{
|
||||||
|
"name": "padreug",
|
||||||
|
"uri": "https://git.atitlan.io/padreug",
|
||||||
|
"role": "Author"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"images": [],
|
||||||
|
"license": "MIT",
|
||||||
|
"paid_features": "",
|
||||||
|
"tags": ["Finance"],
|
||||||
|
"donate": "",
|
||||||
|
"hidden": false
|
||||||
|
}
|
||||||
63
pyproject.toml
Normal file
63
pyproject.toml
Normal file
|
|
@ -0,0 +1,63 @@
|
||||||
|
[project]
|
||||||
|
name = "lnbits-payroll"
|
||||||
|
version = "0.0.0"
|
||||||
|
requires-python = ">=3.10,<3.13"
|
||||||
|
description = "Recurring salary payouts between LNbits wallets, scheduled by the instance super user."
|
||||||
|
authors = [{ name = "aiolabs", email = "dev@aiolabs.dev" }]
|
||||||
|
urls = { Homepage = "https://git.atitlan.io/aiolabs/payroll", Repository = "https://git.atitlan.io/aiolabs/payroll" }
|
||||||
|
dependencies = [ "lnbits>1" ]
|
||||||
|
|
||||||
|
[dependency-groups]
|
||||||
|
dev = [
|
||||||
|
"black",
|
||||||
|
"pytest-asyncio",
|
||||||
|
"pytest",
|
||||||
|
"mypy",
|
||||||
|
"pre-commit",
|
||||||
|
"ruff",
|
||||||
|
]
|
||||||
|
|
||||||
|
[tool.poetry]
|
||||||
|
package-mode = false
|
||||||
|
|
||||||
|
[tool.mypy]
|
||||||
|
plugins = ["pydantic.mypy"]
|
||||||
|
|
||||||
|
[tool.pydantic-mypy]
|
||||||
|
init_forbid_extra = true
|
||||||
|
init_typed = true
|
||||||
|
warn_required_dynamic_aliases = true
|
||||||
|
warn_untyped_fields = true
|
||||||
|
|
||||||
|
[tool.pytest.ini_options]
|
||||||
|
log_cli = false
|
||||||
|
testpaths = [
|
||||||
|
"tests"
|
||||||
|
]
|
||||||
|
|
||||||
|
[tool.black]
|
||||||
|
line-length = 88
|
||||||
|
|
||||||
|
[tool.ruff]
|
||||||
|
line-length = 88
|
||||||
|
|
||||||
|
[tool.ruff.lint]
|
||||||
|
select = ["F", "E", "W", "I", "A", "C", "N", "UP", "RUF", "B"]
|
||||||
|
ignore = ["C901"]
|
||||||
|
|
||||||
|
fixable = ["ALL"]
|
||||||
|
unfixable = []
|
||||||
|
|
||||||
|
dummy-variable-rgx = "^(_+|(_+[a-zA-Z0-9_]*[a-zA-Z0-9]+?))$"
|
||||||
|
|
||||||
|
[tool.ruff.lint.pep8-naming]
|
||||||
|
classmethod-decorators = [
|
||||||
|
"validator",
|
||||||
|
"root_validator",
|
||||||
|
]
|
||||||
|
|
||||||
|
[tool.ruff.lint.flake8-bugbear]
|
||||||
|
extend-immutable-calls = [
|
||||||
|
"fastapi.Depends",
|
||||||
|
"fastapi.Query",
|
||||||
|
]
|
||||||
BIN
static/image/payroll.png
Normal file
BIN
static/image/payroll.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 481 B |
Loading…
Add table
Add a link
Reference in a new issue