Essl-F22-SDK 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.
- essl_f22_sdk-0.1.0/.dockerignore +17 -0
- essl_f22_sdk-0.1.0/.github/workflows/branch-flow.yml +44 -0
- essl_f22_sdk-0.1.0/.github/workflows/ci.yml +70 -0
- essl_f22_sdk-0.1.0/.github/workflows/release.yml +31 -0
- essl_f22_sdk-0.1.0/.gitignore +29 -0
- essl_f22_sdk-0.1.0/.pre-commit-config.yaml +12 -0
- essl_f22_sdk-0.1.0/AGENTS.md +214 -0
- essl_f22_sdk-0.1.0/CHANGELOG.md +35 -0
- essl_f22_sdk-0.1.0/CODE_OF_CONDUCT.md +26 -0
- essl_f22_sdk-0.1.0/CONTRIBUTING.md +37 -0
- essl_f22_sdk-0.1.0/Dockerfile +17 -0
- essl_f22_sdk-0.1.0/LICENSE +178 -0
- essl_f22_sdk-0.1.0/PKG-INFO +546 -0
- essl_f22_sdk-0.1.0/README.md +510 -0
- essl_f22_sdk-0.1.0/SECURITY.md +14 -0
- essl_f22_sdk-0.1.0/docs/concepts/access-control.md +299 -0
- essl_f22_sdk-0.1.0/docs/concepts/attendance.md +248 -0
- essl_f22_sdk-0.1.0/docs/concepts/fingerprints.md +189 -0
- essl_f22_sdk-0.1.0/docs/concepts/how-it-works.md +232 -0
- essl_f22_sdk-0.1.0/docs/concepts/mirror-and-storage.md +338 -0
- essl_f22_sdk-0.1.0/docs/concepts/users.md +260 -0
- essl_f22_sdk-0.1.0/docs/contributing/development.md +237 -0
- essl_f22_sdk-0.1.0/docs/contributing/release.md +230 -0
- essl_f22_sdk-0.1.0/docs/getting-started/first-connection.md +233 -0
- essl_f22_sdk-0.1.0/docs/getting-started/installation.md +188 -0
- essl_f22_sdk-0.1.0/docs/getting-started/quickstart.md +269 -0
- essl_f22_sdk-0.1.0/docs/getting-started/what-is-this.md +167 -0
- essl_f22_sdk-0.1.0/docs/guides/back-up-and-sync.md +290 -0
- essl_f22_sdk-0.1.0/docs/guides/block-and-unblock.md +313 -0
- essl_f22_sdk-0.1.0/docs/guides/choose-storage.md +312 -0
- essl_f22_sdk-0.1.0/docs/guides/handle-errors.md +293 -0
- essl_f22_sdk-0.1.0/docs/guides/manage-users.md +270 -0
- essl_f22_sdk-0.1.0/docs/guides/production-checklist.md +191 -0
- essl_f22_sdk-0.1.0/docs/help/compatibility.md +188 -0
- essl_f22_sdk-0.1.0/docs/help/faq.md +206 -0
- essl_f22_sdk-0.1.0/docs/help/glossary.md +237 -0
- essl_f22_sdk-0.1.0/docs/help/troubleshooting.md +333 -0
- essl_f22_sdk-0.1.0/docs/index.md +167 -0
- essl_f22_sdk-0.1.0/docs/reference/device-api.md +481 -0
- essl_f22_sdk-0.1.0/docs/reference/errors.md +273 -0
- essl_f22_sdk-0.1.0/docs/reference/models.md +375 -0
- essl_f22_sdk-0.1.0/docs/reference/protocol.md +285 -0
- essl_f22_sdk-0.1.0/docs/reference/storage.md +286 -0
- essl_f22_sdk-0.1.0/mkdocs.yml +100 -0
- essl_f22_sdk-0.1.0/pyproject.toml +87 -0
- essl_f22_sdk-0.1.0/src/essl_f22/__init__.py +113 -0
- essl_f22_sdk-0.1.0/src/essl_f22/access.py +199 -0
- essl_f22_sdk-0.1.0/src/essl_f22/device.py +325 -0
- essl_f22_sdk-0.1.0/src/essl_f22/errors.py +61 -0
- essl_f22_sdk-0.1.0/src/essl_f22/mirror.py +237 -0
- essl_f22_sdk-0.1.0/src/essl_f22/models.py +360 -0
- essl_f22_sdk-0.1.0/src/essl_f22/protocol.py +177 -0
- essl_f22_sdk-0.1.0/src/essl_f22/py.typed +0 -0
- essl_f22_sdk-0.1.0/src/essl_f22/session.py +250 -0
- essl_f22_sdk-0.1.0/src/essl_f22/state.py +15 -0
- essl_f22_sdk-0.1.0/src/essl_f22/storage/__init__.py +47 -0
- essl_f22_sdk-0.1.0/src/essl_f22/storage/base.py +110 -0
- essl_f22_sdk-0.1.0/src/essl_f22/storage/codec.py +287 -0
- essl_f22_sdk-0.1.0/src/essl_f22/storage/document.py +285 -0
- essl_f22_sdk-0.1.0/src/essl_f22/storage/factory.py +60 -0
- essl_f22_sdk-0.1.0/src/essl_f22/storage/jsonfile.py +147 -0
- essl_f22_sdk-0.1.0/src/essl_f22/storage/memory.py +61 -0
- essl_f22_sdk-0.1.0/src/essl_f22/storage/models.py +56 -0
- essl_f22_sdk-0.1.0/src/essl_f22/storage/mongo.py +157 -0
- essl_f22_sdk-0.1.0/src/essl_f22/storage/mysql.py +198 -0
- essl_f22_sdk-0.1.0/src/essl_f22/storage/paths.py +41 -0
- essl_f22_sdk-0.1.0/src/essl_f22/storage/postgres.py +182 -0
- essl_f22_sdk-0.1.0/src/essl_f22/storage/redis.py +126 -0
- essl_f22_sdk-0.1.0/src/essl_f22/storage/sqlite.py +178 -0
- essl_f22_sdk-0.1.0/src/essl_f22/transport.py +59 -0
- essl_f22_sdk-0.1.0/tests/__init__.py +0 -0
- essl_f22_sdk-0.1.0/tests/fakes.py +52 -0
- essl_f22_sdk-0.1.0/tests/test_access.py +349 -0
- essl_f22_sdk-0.1.0/tests/test_device.py +351 -0
- essl_f22_sdk-0.1.0/tests/test_hardware.py +88 -0
- essl_f22_sdk-0.1.0/tests/test_mirror.py +261 -0
- essl_f22_sdk-0.1.0/tests/test_models.py +168 -0
- essl_f22_sdk-0.1.0/tests/test_protocol.py +33 -0
- essl_f22_sdk-0.1.0/tests/test_public_api.py +278 -0
- essl_f22_sdk-0.1.0/tests/test_session.py +85 -0
- essl_f22_sdk-0.1.0/tests/test_storage_codec.py +111 -0
- essl_f22_sdk-0.1.0/tests/test_storage_contract.py +310 -0
- essl_f22_sdk-0.1.0/tests/test_storage_factory.py +128 -0
- essl_f22_sdk-0.1.0/tests/test_storage_nosql_adapters.py +73 -0
- essl_f22_sdk-0.1.0/tests/test_storage_sql_adapters.py +210 -0
- essl_f22_sdk-0.1.0/uv.lock +1342 -0
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
name: Branch flow
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
pull_request:
|
|
5
|
+
types: [opened, synchronize, reopened, edited]
|
|
6
|
+
|
|
7
|
+
permissions:
|
|
8
|
+
contents: read
|
|
9
|
+
|
|
10
|
+
jobs:
|
|
11
|
+
validate:
|
|
12
|
+
runs-on: ubuntu-latest
|
|
13
|
+
steps:
|
|
14
|
+
- name: Validate pull request branch flow
|
|
15
|
+
env:
|
|
16
|
+
BASE_REF: ${{ github.base_ref }}
|
|
17
|
+
HEAD_REF: ${{ github.head_ref }}
|
|
18
|
+
run: |
|
|
19
|
+
echo "base=${BASE_REF} head=${HEAD_REF}"
|
|
20
|
+
case "${BASE_REF}" in
|
|
21
|
+
prod)
|
|
22
|
+
if [[ "${HEAD_REF}" != "stag" ]]; then
|
|
23
|
+
echo "prod accepts pull requests only from stag"
|
|
24
|
+
exit 1
|
|
25
|
+
fi
|
|
26
|
+
;;
|
|
27
|
+
stag)
|
|
28
|
+
if [[ "${HEAD_REF}" != "dev" ]]; then
|
|
29
|
+
echo "stag accepts pull requests only from dev"
|
|
30
|
+
exit 1
|
|
31
|
+
fi
|
|
32
|
+
;;
|
|
33
|
+
dev)
|
|
34
|
+
if [[ ! "${HEAD_REF}" =~ ^(feat|fix|chore|docs|test)/[0-9]+-[a-z0-9-]+$ ]]; then
|
|
35
|
+
echo "dev accepts pull requests only from <type>/<issue#>-<slug>"
|
|
36
|
+
exit 1
|
|
37
|
+
fi
|
|
38
|
+
;;
|
|
39
|
+
*)
|
|
40
|
+
echo "unsupported base branch: ${BASE_REF}"
|
|
41
|
+
exit 1
|
|
42
|
+
;;
|
|
43
|
+
esac
|
|
44
|
+
echo "branch flow is valid"
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [prod, stag, dev]
|
|
6
|
+
pull_request:
|
|
7
|
+
|
|
8
|
+
permissions:
|
|
9
|
+
contents: read
|
|
10
|
+
|
|
11
|
+
concurrency:
|
|
12
|
+
group: ci-${{ github.ref }}
|
|
13
|
+
cancel-in-progress: true
|
|
14
|
+
|
|
15
|
+
jobs:
|
|
16
|
+
checks:
|
|
17
|
+
runs-on: ubuntu-latest
|
|
18
|
+
steps:
|
|
19
|
+
- uses: actions/checkout@v7
|
|
20
|
+
- name: Install uv
|
|
21
|
+
uses: astral-sh/setup-uv@v7
|
|
22
|
+
with:
|
|
23
|
+
enable-cache: true
|
|
24
|
+
- name: Set up Python
|
|
25
|
+
run: uv python install 3.14
|
|
26
|
+
- name: Install dependencies
|
|
27
|
+
run: uv sync
|
|
28
|
+
- name: ruff check
|
|
29
|
+
run: uv run ruff check .
|
|
30
|
+
- name: ruff format check
|
|
31
|
+
run: uv run ruff format --check .
|
|
32
|
+
- name: mypy
|
|
33
|
+
run: uv run mypy src/
|
|
34
|
+
- name: pytest
|
|
35
|
+
run: uv run pytest
|
|
36
|
+
|
|
37
|
+
docs:
|
|
38
|
+
runs-on: ubuntu-latest
|
|
39
|
+
steps:
|
|
40
|
+
- uses: actions/checkout@v7
|
|
41
|
+
- name: Install uv
|
|
42
|
+
uses: astral-sh/setup-uv@v7
|
|
43
|
+
with:
|
|
44
|
+
enable-cache: true
|
|
45
|
+
- name: Set up Python
|
|
46
|
+
run: uv python install 3.14
|
|
47
|
+
- name: Install docs dependencies
|
|
48
|
+
run: uv sync --extra docs
|
|
49
|
+
- name: Build documentation
|
|
50
|
+
run: uv run mkdocs build --strict
|
|
51
|
+
|
|
52
|
+
package:
|
|
53
|
+
runs-on: ubuntu-latest
|
|
54
|
+
steps:
|
|
55
|
+
- uses: actions/checkout@v7
|
|
56
|
+
- name: Install uv
|
|
57
|
+
uses: astral-sh/setup-uv@v7
|
|
58
|
+
with:
|
|
59
|
+
enable-cache: true
|
|
60
|
+
- name: Set up Python
|
|
61
|
+
run: uv python install 3.14
|
|
62
|
+
- name: Build sdist and wheel
|
|
63
|
+
run: uv build
|
|
64
|
+
- name: Check package metadata
|
|
65
|
+
run: uvx twine check dist/*
|
|
66
|
+
- name: Install wheel in clean environment
|
|
67
|
+
run: |
|
|
68
|
+
uv venv --python 3.14 /tmp/essl_f22-wheel
|
|
69
|
+
uv pip install --python /tmp/essl_f22-wheel/bin/python dist/*.whl
|
|
70
|
+
/tmp/essl_f22-wheel/bin/python -c "from importlib.metadata import version; import essl_f22; from essl_f22 import Device; assert essl_f22.__version__ == version('Essl_F22_SDK'); print(Device, essl_f22.__version__)"
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
name: Release
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
tags:
|
|
6
|
+
- "v*"
|
|
7
|
+
|
|
8
|
+
permissions:
|
|
9
|
+
contents: read
|
|
10
|
+
id-token: write
|
|
11
|
+
|
|
12
|
+
jobs:
|
|
13
|
+
publish:
|
|
14
|
+
runs-on: ubuntu-latest
|
|
15
|
+
environment:
|
|
16
|
+
name: pypi
|
|
17
|
+
url: https://pypi.org/project/Essl_F22_SDK/
|
|
18
|
+
steps:
|
|
19
|
+
- uses: actions/checkout@v7
|
|
20
|
+
- name: Install uv
|
|
21
|
+
uses: astral-sh/setup-uv@v7
|
|
22
|
+
with:
|
|
23
|
+
enable-cache: true
|
|
24
|
+
- name: Set up Python
|
|
25
|
+
run: uv python install 3.14
|
|
26
|
+
- name: Build sdist and wheel
|
|
27
|
+
run: uv build
|
|
28
|
+
- name: Check package metadata
|
|
29
|
+
run: uvx twine check dist/*
|
|
30
|
+
- name: Publish to PyPI
|
|
31
|
+
uses: pypa/gh-action-pypi-publish@release/v1
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# Byte-compiled / optimized
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[cod]
|
|
4
|
+
|
|
5
|
+
# Environments
|
|
6
|
+
.venv/
|
|
7
|
+
venv/
|
|
8
|
+
|
|
9
|
+
# Test / coverage
|
|
10
|
+
.pytest_cache/
|
|
11
|
+
.coverage
|
|
12
|
+
htmlcov/
|
|
13
|
+
|
|
14
|
+
# Type checkers / linters
|
|
15
|
+
.mypy_cache/
|
|
16
|
+
.ruff_cache/
|
|
17
|
+
|
|
18
|
+
# Packaging
|
|
19
|
+
build/
|
|
20
|
+
dist/
|
|
21
|
+
*.egg-info/
|
|
22
|
+
|
|
23
|
+
# Documentation build
|
|
24
|
+
site/
|
|
25
|
+
|
|
26
|
+
# OS / editor
|
|
27
|
+
.DS_Store
|
|
28
|
+
.idea/
|
|
29
|
+
.vscode/
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
repos:
|
|
2
|
+
- repo: https://github.com/astral-sh/ruff-pre-commit
|
|
3
|
+
rev: v0.17.2
|
|
4
|
+
hooks:
|
|
5
|
+
- id: ruff
|
|
6
|
+
args: [--fix]
|
|
7
|
+
- id: ruff-format
|
|
8
|
+
- repo: https://github.com/pre-commit/mirrors-mypy
|
|
9
|
+
rev: v2.4.0
|
|
10
|
+
hooks:
|
|
11
|
+
- id: mypy
|
|
12
|
+
additional_dependencies: [pytest]
|
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
# AGENTS.md
|
|
2
|
+
|
|
3
|
+
Rules every AI agent (and human contributor) must follow when working in this
|
|
4
|
+
repository. Sections `Technical Stack`, `Commands`, and `Architecture & Code
|
|
5
|
+
Style` are project-specific. `Guardrails & Boundaries` is generic — it must be
|
|
6
|
+
carried over unchanged when this file is reused in another project, and only
|
|
7
|
+
the first three sections are rewritten.
|
|
8
|
+
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
## Technical Stack
|
|
12
|
+
|
|
13
|
+
<!-- PROJECT SPECIFIC — regenerate when reusing this file in another project -->
|
|
14
|
+
|
|
15
|
+
- **Language/Runtime:** Python 3.12+; `pyproject.toml` requires `>=3.12`.
|
|
16
|
+
- **Web framework:** None. This repository is a library, not a web service.
|
|
17
|
+
- **Database:** SQLite via stdlib `sqlite3` by default, with JSON and in-memory
|
|
18
|
+
backends for block state and the offline mirror. PostgreSQL, MySQL, MongoDB,
|
|
19
|
+
and Redis are optional adapters using their direct drivers.
|
|
20
|
+
- **Validation/config:** Dataclasses and explicit constructor arguments; no
|
|
21
|
+
Pydantic dependency.
|
|
22
|
+
- **Telegram:** None.
|
|
23
|
+
- **Outbound HTTP:** None. Device communication is TCP via stdlib `socket`.
|
|
24
|
+
- **Logging:** No logging framework selected yet; avoid adding runtime
|
|
25
|
+
dependencies without an accepted requirement.
|
|
26
|
+
- **Testing:** pytest + pytest-cov. External storage tests are opt-in through
|
|
27
|
+
environment values; hardware tests use the `hardware` marker and are opt-in
|
|
28
|
+
through `ESSL_F22_HOST`.
|
|
29
|
+
- **Quality gates:** ruff (lint + format), mypy (strict), pytest, pre-commit.
|
|
30
|
+
- **Packaging/deploy:** hatchling, uv; optional extras are `docs`, `mongo`,
|
|
31
|
+
`mysql`, `postgres`, and `redis`.
|
|
32
|
+
- **License:** Apache 2.0.
|
|
33
|
+
|
|
34
|
+
### Branch layout
|
|
35
|
+
|
|
36
|
+
- `prod` — default/protected branch. **Can be merged only from `stag`.**
|
|
37
|
+
- `stag` — staging. **Can be merged only from `dev`.**
|
|
38
|
+
- `dev` — integration branch. **Can be merged only from feature/issue
|
|
39
|
+
branches** (`<type>/<issue#>-<slug>`).
|
|
40
|
+
- Feature/issue branches target `dev`. Promotion through the chain happens
|
|
41
|
+
via PRs only, one hop at a time.
|
|
42
|
+
- Remote `origin` is `https://github.com/mramitdas/Essl_F22_SDK`; all
|
|
43
|
+
changes land through PRs and no direct pushes to integration branches are
|
|
44
|
+
permitted.
|
|
45
|
+
- Server-side branch protection is unavailable on the private free-plan
|
|
46
|
+
repository. The branch-flow workflow and PR discipline are the enforcement
|
|
47
|
+
mechanism.
|
|
48
|
+
|
|
49
|
+
---
|
|
50
|
+
|
|
51
|
+
## Commands
|
|
52
|
+
|
|
53
|
+
<!-- PROJECT SPECIFIC — regenerate when reusing this file in another project -->
|
|
54
|
+
|
|
55
|
+
Run all commands from the repository root unless stated otherwise.
|
|
56
|
+
|
|
57
|
+
```bash
|
|
58
|
+
# Setup
|
|
59
|
+
uv sync
|
|
60
|
+
|
|
61
|
+
# Test
|
|
62
|
+
uv run pytest # all tests with coverage
|
|
63
|
+
uv run pytest -k name # single test
|
|
64
|
+
uv run pytest -m hardware # opt-in read-only hardware test
|
|
65
|
+
uv run pytest tests/test_storage_contract.py # opt-in external storage tests
|
|
66
|
+
|
|
67
|
+
# Quality gates (must be clean before every PR)
|
|
68
|
+
uv run ruff check .
|
|
69
|
+
uv run ruff format --check .
|
|
70
|
+
uv run mypy src/
|
|
71
|
+
uv run pytest
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
**Rule:** never invent commands. Use these verbatim. If a required command is
|
|
75
|
+
missing, check `.github/workflows/ci.yml`; if not defined anywhere, stop and
|
|
76
|
+
ask instead of guessing.
|
|
77
|
+
|
|
78
|
+
---
|
|
79
|
+
|
|
80
|
+
## Architecture & Code Style
|
|
81
|
+
|
|
82
|
+
<!-- PROJECT SPECIFIC — regenerate when reusing this file in another project -->
|
|
83
|
+
|
|
84
|
+
### Architecture (v0.1 target)
|
|
85
|
+
|
|
86
|
+
- `src/essl_f22/` — importable package using a src layout. No web, API, bot, or
|
|
87
|
+
database-server layers.
|
|
88
|
+
- `errors.py` — SDK exception hierarchy.
|
|
89
|
+
- `protocol.py` — command constants, checksums, packet framing, and binary
|
|
90
|
+
codecs.
|
|
91
|
+
- `transport.py` — TCP socket transport.
|
|
92
|
+
- `session.py` — connect/auth, command request/response, buffered reads.
|
|
93
|
+
- `models.py` — dataclasses for users, attendance, fingerprints, timezones,
|
|
94
|
+
groups, and device info.
|
|
95
|
+
- `device.py` — high-level device read/write, blocking, mirror, and sync APIs.
|
|
96
|
+
- `mirror.py` — read-only offline mirror and full/incremental sync.
|
|
97
|
+
- `access.py` — non-destructive block/unblock manager.
|
|
98
|
+
- `storage/` — document storage protocols, codecs, built-in backends,
|
|
99
|
+
external adapters, and the storage factory.
|
|
100
|
+
- `state.py` — `SqliteBlockStateStore` compatibility shim.
|
|
101
|
+
- `__init__.py` — public exports.
|
|
102
|
+
- Unit tests must not require a physical device; use fake transports/sessions.
|
|
103
|
+
Hardware tests are separate, read-only by default, and skipped unless
|
|
104
|
+
`ESSL_F22_HOST` is set.
|
|
105
|
+
|
|
106
|
+
### Code style
|
|
107
|
+
|
|
108
|
+
- Follow the existing pattern of the file/module you touch. Read neighboring
|
|
109
|
+
code before writing anything new.
|
|
110
|
+
- Formatted by ruff; type-hinted for mypy strictness over `src/`.
|
|
111
|
+
- Every behavior change ships with tests in the same PR; test names describe
|
|
112
|
+
the behavior, not the implementation.
|
|
113
|
+
- Documentation (`README.md`, `docs/`) is updated in the same PR whenever
|
|
114
|
+
setup, behavior, or the API contract changes.
|
|
115
|
+
- No TODO markers, commented-out code, or dead files left behind.
|
|
116
|
+
|
|
117
|
+
---
|
|
118
|
+
|
|
119
|
+
## Guardrails & Boundaries
|
|
120
|
+
|
|
121
|
+
<!-- GENERIC — do not modify when reusing this file in another project -->
|
|
122
|
+
|
|
123
|
+
### 1. Anti-hallucination
|
|
124
|
+
|
|
125
|
+
- **Cite, never guess.** Every file, function, command, or config an agent
|
|
126
|
+
references must exist in the repo right now — verify by reading before
|
|
127
|
+
acting. No "it should probably be in…" reasoning.
|
|
128
|
+
- **No invented APIs.** Never use a library method from memory; read the
|
|
129
|
+
installed package for the pinned version in use. Versions come from the
|
|
130
|
+
manifests, not from recollection.
|
|
131
|
+
- **Read before edit.** A file must be fully read (not just grepped) before it
|
|
132
|
+
is edited.
|
|
133
|
+
- **Verify before claiming.** Never say "done", "passing", or "fixed" without
|
|
134
|
+
having run the actual command and seen real output.
|
|
135
|
+
- **Acknowledge unknowns.** Unsure about an env value, expected behavior, or
|
|
136
|
+
secret? Stop and ask. Never invent credentials, URLs, or DB values.
|
|
137
|
+
- **No silent fallbacks.** If a step fails, report the real error verbatim.
|
|
138
|
+
Do not work around it by editing unrelated files.
|
|
139
|
+
- **Diff-check after edits.** After every edit, review `git diff` to confirm
|
|
140
|
+
only intended changes.
|
|
141
|
+
|
|
142
|
+
### 2. Scope discipline (no overreach)
|
|
143
|
+
|
|
144
|
+
- One issue = one PR = one logical change. Strictly implement only what the
|
|
145
|
+
accepted issue defines (its AC).
|
|
146
|
+
- No drive-by refactors, renames, or formatting-only edits; no "while I'm in
|
|
147
|
+
here" changes. Spotted problems → create a new issue, do not fix inline.
|
|
148
|
+
- No unrequested suggestions at the end of a task. Finish, report, stop.
|
|
149
|
+
Ideas belong in GitHub issues.
|
|
150
|
+
- One-way decisions (schema changes, API contracts, migrations) are proposed
|
|
151
|
+
in 1–3 lines and approved before applying.
|
|
152
|
+
- Never create `v2`, `copy`, `.new`, `backup`, or `-final` variants of files;
|
|
153
|
+
edit in place.
|
|
154
|
+
|
|
155
|
+
### 3. Issue → branch → PR workflow
|
|
156
|
+
|
|
157
|
+
- Every task/feature starts as a GitHub issue before any code.
|
|
158
|
+
- Branch naming: `<type>/<issue#>-<slug>` (e.g., `feat/12-rate-limiting`).
|
|
159
|
+
- One task = one commit: conventional commits (`feat:`, `fix:`, `chore:`,
|
|
160
|
+
`docs:`, `test:`), subject ≤ 50 chars, commit body ends with `refs #N`.
|
|
161
|
+
- Work happens on the issue branch; the PR targets `dev`. Promotion is
|
|
162
|
+
sequential and PR-only: `dev` → `stag` → `prod`. Never skip or reorder
|
|
163
|
+
a hop; PRs into `prod` must come from `stag` only, PRs into `stag` from
|
|
164
|
+
`dev` only.
|
|
165
|
+
- **PR checklist gates (all required before merge):**
|
|
166
|
+
- tests pass (real command output),
|
|
167
|
+
- black/isort/mypy/flake8 clean,
|
|
168
|
+
- no secrets and no `.env` in the diff,
|
|
169
|
+
- acceptance criteria demonstrably met,
|
|
170
|
+
- docs updated if behavior/setup changed,
|
|
171
|
+
- PR targets the correct branch in the chain (`dev` ← branch,
|
|
172
|
+
`stag` ← `dev`, `prod` ← `stag`).
|
|
173
|
+
- Issue is closed **only** after its PR is merged. Never close otherwise.
|
|
174
|
+
- Never commit or PR directly to protected branches (`prod`, `stag`, `main`),
|
|
175
|
+
even for docs. No skip-hooks (`--no-verify`), no force-pushing.
|
|
176
|
+
- **Never head-delete integration branches.** Merging a PR with
|
|
177
|
+
`gh pr merge --delete-branch` deletes the PR's head branch, so use it
|
|
178
|
+
only for feature/issue branches. PRs whose head is `dev`, `stag`, or
|
|
179
|
+
`prod` (promotion hops) must be merged without `--delete-branch`.
|
|
180
|
+
Feature-branch cleanup is manual or guarded by GitHub branch protection.
|
|
181
|
+
|
|
182
|
+
### 4. Task granularity & tracking
|
|
183
|
+
|
|
184
|
+
- One task = ≤ 30 minutes of work = one commit = one checkbox in its issue.
|
|
185
|
+
- A task exceeding 30 minutes is split into subtasks within the issue.
|
|
186
|
+
- Every task has executable acceptance criteria (a test, a command, or a
|
|
187
|
+
demonstrable behavior). Done = AC passes — nothing more, nothing less.
|
|
188
|
+
- Feature issues are parents with a task checklist; each item is its own
|
|
189
|
+
branch/PR and ≤ 30 minutes.
|
|
190
|
+
- Status is communicated through issue/PR comments, not memory or chat-only.
|
|
191
|
+
|
|
192
|
+
### 5. Security
|
|
193
|
+
|
|
194
|
+
- Never commit secrets, tokens, API keys, or `.env`; `.env` is git-ignored.
|
|
195
|
+
Real secrets live only in the local `.env` / deployment secret store.
|
|
196
|
+
- Dependencies are added/changed only through the requirement manifests
|
|
197
|
+
(`requirements/*.txt`); lockfile or pin updates are separate commits.
|
|
198
|
+
- Never disable lint, typecheck, or test gates to make something pass.
|
|
199
|
+
|
|
200
|
+
### 6. Destructive & irreversible operations
|
|
201
|
+
|
|
202
|
+
- The following require explicit, current-session user approval before
|
|
203
|
+
running: `git push --force`, branch deletion (including of integration
|
|
204
|
+
branches `dev`, `stag`, `prod`), dropping/updating-down DB
|
|
205
|
+
migrations, deleting files beyond the current task's scope, publishing or
|
|
206
|
+
releasing, and anything modifying `main`/`prod` history.
|
|
207
|
+
- Never touch files outside the workspace directory.
|
|
208
|
+
|
|
209
|
+
### 7. On session start
|
|
210
|
+
|
|
211
|
+
- Read this file first.
|
|
212
|
+
- Check open issues and PRs to resume context; rely on issue/PR comments, not
|
|
213
|
+
memory of a previous session.
|
|
214
|
+
- Confirm the target branch and issue number before the first action.
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project will be documented in this file.
|
|
4
|
+
|
|
5
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
6
|
+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
|
+
|
|
8
|
+
## [Unreleased]
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
|
|
12
|
+
- Complete layperson-friendly handbook with concepts, guides, reference, help,
|
|
13
|
+
and contributing pages, plus a strict MkDocs build in CI.
|
|
14
|
+
- Expanded README with requirements, installation, quickstart, common tasks,
|
|
15
|
+
storage, safety, compatibility, error handling, and development guidance.
|
|
16
|
+
|
|
17
|
+
### Changed
|
|
18
|
+
|
|
19
|
+
- Renamed the PyPI distribution from `essl_f22` to `Essl_F22_SDK`; the Python
|
|
20
|
+
import remains `essl_f22`.
|
|
21
|
+
|
|
22
|
+
## [0.1.0] - 2026-10-24
|
|
23
|
+
|
|
24
|
+
### Added
|
|
25
|
+
|
|
26
|
+
- Synchronous TCP SDK for eSSL/ZKTeco F22 terminals.
|
|
27
|
+
- Device information, user, fingerprint metadata, attendance, group, and
|
|
28
|
+
timezone reads.
|
|
29
|
+
- User create, update, and delete APIs.
|
|
30
|
+
- Non-destructive user blocking and unblocking.
|
|
31
|
+
- Read-only offline mirror with full and incremental sync.
|
|
32
|
+
- SQLite, JSON, memory, PostgreSQL, MySQL, MongoDB, and Redis storage backends.
|
|
33
|
+
- Optional dependency extras for external storage drivers.
|
|
34
|
+
- Hardware, storage-contract, and unit test suites.
|
|
35
|
+
- PyPI packaging with Trusted Publishing.
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# Code of Conduct
|
|
2
|
+
|
|
3
|
+
## Our pledge
|
|
4
|
+
|
|
5
|
+
We as members, contributors, and maintainers of the Essl F22 SDK
|
|
6
|
+
pledge to make participation in this project a harassment-free experience for
|
|
7
|
+
everyone, regardless of age, body size, visible or invisible disability, ethnicity,
|
|
8
|
+
sex characteristics, gender identity and expression, level of experience,
|
|
9
|
+
education, socio-economic status, nationality, personal appearance, race,
|
|
10
|
+
religion, or sexual identity and orientation.
|
|
11
|
+
|
|
12
|
+
## Expected behavior
|
|
13
|
+
|
|
14
|
+
- Being respectful of differing opinions, viewpoints, and experiences
|
|
15
|
+
- Giving and gracefully accepting constructive feedback
|
|
16
|
+
- Focusing on what is best for the community and the project
|
|
17
|
+
|
|
18
|
+
Unacceptable behavior includes harassment, personal attacks, trolling, and
|
|
19
|
+
publishing others' private information without permission.
|
|
20
|
+
|
|
21
|
+
## Enforcement
|
|
22
|
+
|
|
23
|
+
Report unacceptable behavior to the project maintainer at
|
|
24
|
+
[mramitdas99@gmail.com](mailto:mramitdas99@gmail.com). All complaints
|
|
25
|
+
will be reviewed and investigated promptly and fairly. Maintainers are
|
|
26
|
+
obligated to respect the privacy of the reporter.
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# Contributing
|
|
2
|
+
|
|
3
|
+
Thanks for your interest in contributing to the Essl F22 SDK.
|
|
4
|
+
|
|
5
|
+
## Workflow
|
|
6
|
+
|
|
7
|
+
1. Fork and create a feature branch from `dev`.
|
|
8
|
+
2. Install dev dependencies: `uv sync`.
|
|
9
|
+
3. Make your change with tests.
|
|
10
|
+
4. Run the quality gates:
|
|
11
|
+
|
|
12
|
+
```bash
|
|
13
|
+
uv run ruff check .
|
|
14
|
+
uv run ruff format --check .
|
|
15
|
+
uv run mypy src/
|
|
16
|
+
uv run pytest
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
5. Open a pull request targeting `dev`.
|
|
20
|
+
|
|
21
|
+
## Release
|
|
22
|
+
|
|
23
|
+
Releases are published to PyPI from `prod` with Trusted Publishing.
|
|
24
|
+
|
|
25
|
+
One-time setup: add a PyPI pending trusted publisher for this repository,
|
|
26
|
+
workflow `release.yml`, and environment `pypi`, then create the matching
|
|
27
|
+
GitHub environment.
|
|
28
|
+
|
|
29
|
+
1. Update `CHANGELOG.md` and `__version__` in `src/essl_f22/__init__.py`.
|
|
30
|
+
2. Merge the release change through `dev` → `stag` → `prod`.
|
|
31
|
+
3. Tag `prod` with `vX.Y.Z` and push the tag.
|
|
32
|
+
4. The `release.yml` workflow builds and publishes the sdist and wheel.
|
|
33
|
+
5. Verify `pip install Essl_F22_SDK==X.Y.Z` in a clean environment.
|
|
34
|
+
|
|
35
|
+
## Code of Conduct
|
|
36
|
+
|
|
37
|
+
Please read and follow the [Code of Conduct](CODE_OF_CONDUCT.md).
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
FROM python:3.14-slim
|
|
2
|
+
|
|
3
|
+
COPY --from=ghcr.io/astral-sh/uv:latest /uv /usr/local/bin/uv
|
|
4
|
+
|
|
5
|
+
WORKDIR /app
|
|
6
|
+
|
|
7
|
+
ENV UV_COMPILE_BYTECODE=1 \
|
|
8
|
+
UV_LINK_MODE=copy
|
|
9
|
+
|
|
10
|
+
COPY pyproject.toml uv.lock ./
|
|
11
|
+
RUN uv sync --no-dev --frozen
|
|
12
|
+
|
|
13
|
+
COPY src/ src/
|
|
14
|
+
|
|
15
|
+
USER 1000:1000
|
|
16
|
+
|
|
17
|
+
CMD ["uv", "run", "--no-sync", "python", "-c", "from essl_f22.core import add; print(add(1, 2))"]
|