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.
Files changed (86) hide show
  1. essl_f22_sdk-0.1.0/.dockerignore +17 -0
  2. essl_f22_sdk-0.1.0/.github/workflows/branch-flow.yml +44 -0
  3. essl_f22_sdk-0.1.0/.github/workflows/ci.yml +70 -0
  4. essl_f22_sdk-0.1.0/.github/workflows/release.yml +31 -0
  5. essl_f22_sdk-0.1.0/.gitignore +29 -0
  6. essl_f22_sdk-0.1.0/.pre-commit-config.yaml +12 -0
  7. essl_f22_sdk-0.1.0/AGENTS.md +214 -0
  8. essl_f22_sdk-0.1.0/CHANGELOG.md +35 -0
  9. essl_f22_sdk-0.1.0/CODE_OF_CONDUCT.md +26 -0
  10. essl_f22_sdk-0.1.0/CONTRIBUTING.md +37 -0
  11. essl_f22_sdk-0.1.0/Dockerfile +17 -0
  12. essl_f22_sdk-0.1.0/LICENSE +178 -0
  13. essl_f22_sdk-0.1.0/PKG-INFO +546 -0
  14. essl_f22_sdk-0.1.0/README.md +510 -0
  15. essl_f22_sdk-0.1.0/SECURITY.md +14 -0
  16. essl_f22_sdk-0.1.0/docs/concepts/access-control.md +299 -0
  17. essl_f22_sdk-0.1.0/docs/concepts/attendance.md +248 -0
  18. essl_f22_sdk-0.1.0/docs/concepts/fingerprints.md +189 -0
  19. essl_f22_sdk-0.1.0/docs/concepts/how-it-works.md +232 -0
  20. essl_f22_sdk-0.1.0/docs/concepts/mirror-and-storage.md +338 -0
  21. essl_f22_sdk-0.1.0/docs/concepts/users.md +260 -0
  22. essl_f22_sdk-0.1.0/docs/contributing/development.md +237 -0
  23. essl_f22_sdk-0.1.0/docs/contributing/release.md +230 -0
  24. essl_f22_sdk-0.1.0/docs/getting-started/first-connection.md +233 -0
  25. essl_f22_sdk-0.1.0/docs/getting-started/installation.md +188 -0
  26. essl_f22_sdk-0.1.0/docs/getting-started/quickstart.md +269 -0
  27. essl_f22_sdk-0.1.0/docs/getting-started/what-is-this.md +167 -0
  28. essl_f22_sdk-0.1.0/docs/guides/back-up-and-sync.md +290 -0
  29. essl_f22_sdk-0.1.0/docs/guides/block-and-unblock.md +313 -0
  30. essl_f22_sdk-0.1.0/docs/guides/choose-storage.md +312 -0
  31. essl_f22_sdk-0.1.0/docs/guides/handle-errors.md +293 -0
  32. essl_f22_sdk-0.1.0/docs/guides/manage-users.md +270 -0
  33. essl_f22_sdk-0.1.0/docs/guides/production-checklist.md +191 -0
  34. essl_f22_sdk-0.1.0/docs/help/compatibility.md +188 -0
  35. essl_f22_sdk-0.1.0/docs/help/faq.md +206 -0
  36. essl_f22_sdk-0.1.0/docs/help/glossary.md +237 -0
  37. essl_f22_sdk-0.1.0/docs/help/troubleshooting.md +333 -0
  38. essl_f22_sdk-0.1.0/docs/index.md +167 -0
  39. essl_f22_sdk-0.1.0/docs/reference/device-api.md +481 -0
  40. essl_f22_sdk-0.1.0/docs/reference/errors.md +273 -0
  41. essl_f22_sdk-0.1.0/docs/reference/models.md +375 -0
  42. essl_f22_sdk-0.1.0/docs/reference/protocol.md +285 -0
  43. essl_f22_sdk-0.1.0/docs/reference/storage.md +286 -0
  44. essl_f22_sdk-0.1.0/mkdocs.yml +100 -0
  45. essl_f22_sdk-0.1.0/pyproject.toml +87 -0
  46. essl_f22_sdk-0.1.0/src/essl_f22/__init__.py +113 -0
  47. essl_f22_sdk-0.1.0/src/essl_f22/access.py +199 -0
  48. essl_f22_sdk-0.1.0/src/essl_f22/device.py +325 -0
  49. essl_f22_sdk-0.1.0/src/essl_f22/errors.py +61 -0
  50. essl_f22_sdk-0.1.0/src/essl_f22/mirror.py +237 -0
  51. essl_f22_sdk-0.1.0/src/essl_f22/models.py +360 -0
  52. essl_f22_sdk-0.1.0/src/essl_f22/protocol.py +177 -0
  53. essl_f22_sdk-0.1.0/src/essl_f22/py.typed +0 -0
  54. essl_f22_sdk-0.1.0/src/essl_f22/session.py +250 -0
  55. essl_f22_sdk-0.1.0/src/essl_f22/state.py +15 -0
  56. essl_f22_sdk-0.1.0/src/essl_f22/storage/__init__.py +47 -0
  57. essl_f22_sdk-0.1.0/src/essl_f22/storage/base.py +110 -0
  58. essl_f22_sdk-0.1.0/src/essl_f22/storage/codec.py +287 -0
  59. essl_f22_sdk-0.1.0/src/essl_f22/storage/document.py +285 -0
  60. essl_f22_sdk-0.1.0/src/essl_f22/storage/factory.py +60 -0
  61. essl_f22_sdk-0.1.0/src/essl_f22/storage/jsonfile.py +147 -0
  62. essl_f22_sdk-0.1.0/src/essl_f22/storage/memory.py +61 -0
  63. essl_f22_sdk-0.1.0/src/essl_f22/storage/models.py +56 -0
  64. essl_f22_sdk-0.1.0/src/essl_f22/storage/mongo.py +157 -0
  65. essl_f22_sdk-0.1.0/src/essl_f22/storage/mysql.py +198 -0
  66. essl_f22_sdk-0.1.0/src/essl_f22/storage/paths.py +41 -0
  67. essl_f22_sdk-0.1.0/src/essl_f22/storage/postgres.py +182 -0
  68. essl_f22_sdk-0.1.0/src/essl_f22/storage/redis.py +126 -0
  69. essl_f22_sdk-0.1.0/src/essl_f22/storage/sqlite.py +178 -0
  70. essl_f22_sdk-0.1.0/src/essl_f22/transport.py +59 -0
  71. essl_f22_sdk-0.1.0/tests/__init__.py +0 -0
  72. essl_f22_sdk-0.1.0/tests/fakes.py +52 -0
  73. essl_f22_sdk-0.1.0/tests/test_access.py +349 -0
  74. essl_f22_sdk-0.1.0/tests/test_device.py +351 -0
  75. essl_f22_sdk-0.1.0/tests/test_hardware.py +88 -0
  76. essl_f22_sdk-0.1.0/tests/test_mirror.py +261 -0
  77. essl_f22_sdk-0.1.0/tests/test_models.py +168 -0
  78. essl_f22_sdk-0.1.0/tests/test_protocol.py +33 -0
  79. essl_f22_sdk-0.1.0/tests/test_public_api.py +278 -0
  80. essl_f22_sdk-0.1.0/tests/test_session.py +85 -0
  81. essl_f22_sdk-0.1.0/tests/test_storage_codec.py +111 -0
  82. essl_f22_sdk-0.1.0/tests/test_storage_contract.py +310 -0
  83. essl_f22_sdk-0.1.0/tests/test_storage_factory.py +128 -0
  84. essl_f22_sdk-0.1.0/tests/test_storage_nosql_adapters.py +73 -0
  85. essl_f22_sdk-0.1.0/tests/test_storage_sql_adapters.py +210 -0
  86. essl_f22_sdk-0.1.0/uv.lock +1342 -0
@@ -0,0 +1,17 @@
1
+ .git
2
+ .github
3
+ .venv
4
+ venv/
5
+ __pycache__/
6
+ *.py[cod]
7
+ .mypy_cache/
8
+ .pytest_cache/
9
+ .ruff_cache/
10
+ .coverage
11
+ htmlcov/
12
+ tests/
13
+ docs/
14
+ mkdocs.yml
15
+ Dockerfile
16
+ .dockerignore
17
+ LICENSE
@@ -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))"]