evlet 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 (122) hide show
  1. evlet-0.1.0/AGENTS.md +38 -0
  2. evlet-0.1.0/LICENSE +21 -0
  3. evlet-0.1.0/MANIFEST.in +8 -0
  4. evlet-0.1.0/PKG-INFO +290 -0
  5. evlet-0.1.0/README.md +270 -0
  6. evlet-0.1.0/docs/application-generation.md +141 -0
  7. evlet-0.1.0/docs/architecture.md +247 -0
  8. evlet-0.1.0/docs/benchmarks/2026-10-29-postgresql.json +72 -0
  9. evlet-0.1.0/docs/benchmarks/2026-10-29-sqlite.json +70 -0
  10. evlet-0.1.0/docs/business-capabilities.md +231 -0
  11. evlet-0.1.0/docs/connector.md +198 -0
  12. evlet-0.1.0/docs/handoff.md +83 -0
  13. evlet-0.1.0/docs/jobs-realtime.md +279 -0
  14. evlet-0.1.0/docs/model-engine.md +193 -0
  15. evlet-0.1.0/docs/performance.md +144 -0
  16. evlet-0.1.0/docs/postgresql.md +142 -0
  17. evlet-0.1.0/docs/production-operations.md +102 -0
  18. evlet-0.1.0/docs/specification.md +1121 -0
  19. evlet-0.1.0/docs/tenancy-deployment.md +254 -0
  20. evlet-0.1.0/evlet/__init__.py +48 -0
  21. evlet-0.1.0/evlet/__main__.py +4 -0
  22. evlet-0.1.0/evlet/app.py +221 -0
  23. evlet-0.1.0/evlet/auth.py +224 -0
  24. evlet-0.1.0/evlet/business.py +402 -0
  25. evlet-0.1.0/evlet/cli.py +147 -0
  26. evlet-0.1.0/evlet/connector.py +161 -0
  27. evlet-0.1.0/evlet/database.py +199 -0
  28. evlet-0.1.0/evlet/deployment.py +63 -0
  29. evlet-0.1.0/evlet/discovery.py +125 -0
  30. evlet-0.1.0/evlet/events.py +65 -0
  31. evlet-0.1.0/evlet/fields.py +331 -0
  32. evlet-0.1.0/evlet/jobs.py +245 -0
  33. evlet-0.1.0/evlet/mcp.py +198 -0
  34. evlet-0.1.0/evlet/metadata.py +64 -0
  35. evlet-0.1.0/evlet/migrations.py +326 -0
  36. evlet-0.1.0/evlet/models.py +121 -0
  37. evlet-0.1.0/evlet/object_storage.py +111 -0
  38. evlet-0.1.0/evlet/permissions.py +108 -0
  39. evlet-0.1.0/evlet/postgres.py +212 -0
  40. evlet-0.1.0/evlet/postgres_schema.py +202 -0
  41. evlet-0.1.0/evlet/query.py +132 -0
  42. evlet-0.1.0/evlet/serverless.py +141 -0
  43. evlet-0.1.0/evlet/storage.py +134 -0
  44. evlet-0.1.0/evlet/tenancy.py +284 -0
  45. evlet-0.1.0/evlet.egg-info/PKG-INFO +290 -0
  46. evlet-0.1.0/evlet.egg-info/SOURCES.txt +120 -0
  47. evlet-0.1.0/evlet.egg-info/dependency_links.txt +1 -0
  48. evlet-0.1.0/evlet.egg-info/entry_points.txt +2 -0
  49. evlet-0.1.0/evlet.egg-info/requires.txt +13 -0
  50. evlet-0.1.0/evlet.egg-info/top_level.txt +1 -0
  51. evlet-0.1.0/examples/playground/app.py +48 -0
  52. evlet-0.1.0/examples/playground/manage.py +131 -0
  53. evlet-0.1.0/examples/playground/migrate.py +97 -0
  54. evlet-0.1.0/examples/playground/models.py +67 -0
  55. evlet-0.1.0/examples/playground/tenants.py +36 -0
  56. evlet-0.1.0/examples/playground/worker.py +58 -0
  57. evlet-0.1.0/frontend/.node-version +1 -0
  58. evlet-0.1.0/frontend/.npmrc +1 -0
  59. evlet-0.1.0/frontend/index.html +13 -0
  60. evlet-0.1.0/frontend/package-lock.json +2136 -0
  61. evlet-0.1.0/frontend/package.json +25 -0
  62. evlet-0.1.0/frontend/src/Accounts.vue +39 -0
  63. evlet-0.1.0/frontend/src/App.test.js +514 -0
  64. evlet-0.1.0/frontend/src/App.vue +216 -0
  65. evlet-0.1.0/frontend/src/FieldInput.vue +23 -0
  66. evlet-0.1.0/frontend/src/LinkInput.vue +51 -0
  67. evlet-0.1.0/frontend/src/QueryControls.vue +51 -0
  68. evlet-0.1.0/frontend/src/RecordDetail.vue +13 -0
  69. evlet-0.1.0/frontend/src/RecordExtras.vue +94 -0
  70. evlet-0.1.0/frontend/src/RecordForm.vue +88 -0
  71. evlet-0.1.0/frontend/src/SessionApp.vue +59 -0
  72. evlet-0.1.0/frontend/src/api.js +64 -0
  73. evlet-0.1.0/frontend/src/api.test.js +30 -0
  74. evlet-0.1.0/frontend/src/business.test.js +181 -0
  75. evlet-0.1.0/frontend/src/child-permissions.test.js +103 -0
  76. evlet-0.1.0/frontend/src/events.js +43 -0
  77. evlet-0.1.0/frontend/src/events.test.js +157 -0
  78. evlet-0.1.0/frontend/src/main.js +21 -0
  79. evlet-0.1.0/frontend/src/recovery.test.js +194 -0
  80. evlet-0.1.0/frontend/src/schema.js +44 -0
  81. evlet-0.1.0/frontend/src/style.css +93 -0
  82. evlet-0.1.0/frontend/src/test-business-schema.json +604 -0
  83. evlet-0.1.0/frontend/src/test-schema.json +535 -0
  84. evlet-0.1.0/frontend/src/test-setup.js +15 -0
  85. evlet-0.1.0/frontend/vite.config.js +21 -0
  86. evlet-0.1.0/pyproject.toml +28 -0
  87. evlet-0.1.0/requirements-dev.lock +54 -0
  88. evlet-0.1.0/requirements-mcp.in +2 -0
  89. evlet-0.1.0/requirements-mcp.lock +593 -0
  90. evlet-0.1.0/requirements-postgres.lock +77 -0
  91. evlet-0.1.0/requirements-s3.lock +16 -0
  92. evlet-0.1.0/requirements-server.lock +13 -0
  93. evlet-0.1.0/scripts/benchmark.py +180 -0
  94. evlet-0.1.0/scripts/check_package.py +96 -0
  95. evlet-0.1.0/scripts/playground.sh +156 -0
  96. evlet-0.1.0/scripts/smoke.py +106 -0
  97. evlet-0.1.0/scripts/smoke_tenants.py +210 -0
  98. evlet-0.1.0/setup.cfg +4 -0
  99. evlet-0.1.0/tests/conftest.py +16 -0
  100. evlet-0.1.0/tests/test_api.py +121 -0
  101. evlet-0.1.0/tests/test_async_tenants.py +45 -0
  102. evlet-0.1.0/tests/test_business.py +329 -0
  103. evlet-0.1.0/tests/test_business_regressions.py +94 -0
  104. evlet-0.1.0/tests/test_cli.py +103 -0
  105. evlet-0.1.0/tests/test_connector.py +253 -0
  106. evlet-0.1.0/tests/test_database.py +88 -0
  107. evlet-0.1.0/tests/test_deployment.py +55 -0
  108. evlet-0.1.0/tests/test_discovery.py +86 -0
  109. evlet-0.1.0/tests/test_events.py +89 -0
  110. evlet-0.1.0/tests/test_generation.py +149 -0
  111. evlet-0.1.0/tests/test_hardening.py +71 -0
  112. evlet-0.1.0/tests/test_input_regressions.py +68 -0
  113. evlet-0.1.0/tests/test_jobs.py +152 -0
  114. evlet-0.1.0/tests/test_mcp_sdk.py +59 -0
  115. evlet-0.1.0/tests/test_migrations.py +264 -0
  116. evlet-0.1.0/tests/test_model_engine.py +187 -0
  117. evlet-0.1.0/tests/test_models.py +93 -0
  118. evlet-0.1.0/tests/test_object_storage.py +117 -0
  119. evlet-0.1.0/tests/test_postgres.py +365 -0
  120. evlet-0.1.0/tests/test_serverless.py +82 -0
  121. evlet-0.1.0/tests/test_storage.py +136 -0
  122. evlet-0.1.0/tests/test_tenancy.py +210 -0
evlet-0.1.0/AGENTS.md ADDED
@@ -0,0 +1,38 @@
1
+ # Working on Evlet
2
+
3
+ Read `docs/specification.md` and `docs/architecture.md` before changing the public API.
4
+ The current scope is Milestone 8: optional PostgreSQL persistence, performance
5
+ measurement, concurrency and tenant security tests, and deployment operations.
6
+ Milestones 1 through 7 are merged. Keep changes within this milestone. Read
7
+ `docs/business-capabilities.md`, `docs/tenancy-deployment.md`,
8
+ `docs/jobs-realtime.md`, and `docs/connector.md` for public APIs and permission
9
+ boundaries. Read `docs/postgresql.md`, `docs/performance.md`, and
10
+ `docs/production-operations.md` for adapter limits and validation. Connector writes must use the existing
11
+ authenticated HTTP routes;
12
+ never bypass account, tenant, row, field, or action checks.
13
+
14
+ - Use Python 3.12+ and Node 24. Python definitions are authoritative; frontend
15
+ components consume a neutral schema and never appear in Python model definitions.
16
+ - Prefer the standard library. Justify every dependency. No mandatory Redis,
17
+ Docker, external database, ORM, or background worker.
18
+ - Keep public APIs explicit, small, and readable. Use snake_case in Python,
19
+ PascalCase for model and Vue component names. Do not create unused modules.
20
+ - `evlet/` contains the framework; `examples/playground/` is a consumer using only
21
+ public exports; `frontend/` is the Vue/PrimeVue Playground; `tests/` covers the
22
+ core, SQLite integration, and ASGI interface.
23
+ - Parameterize SQL values and validate SQL identifiers. Validate on the backend.
24
+ Preserve transaction boundaries, exact currency values, and foreign keys.
25
+ - Keep the Playground authenticated and development servers on loopback. Backend
26
+ permission checks cover all HTTP surfaces. Python sessions and action handlers
27
+ are trusted code. Do not describe the application as production ready.
28
+ - Add meaningful tests for features and regressions. Run `.venv/bin/python -m
29
+ pytest`, then `npm test` and `npm run build` in `frontend/`. Verify package build
30
+ and installation when changing packaging. Never substitute mocks for SQLite.
31
+ - Update documentation and demonstrate applicable public APIs in the Playground.
32
+ A feature is done only when its tests and all existing tests pass.
33
+ - Work on feature branches and prepare PRs; never merge automatically or push
34
+ experimental implementation into `main`.
35
+ - Cloud tasks are already isolated. Use the existing checkout; create no Git
36
+ worktree unless explicitly requested by the user.
37
+
38
+ See the README for complete installation, startup, and smoke-check commands.
evlet-0.1.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Aslam
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,8 @@
1
+ include README.md AGENTS.md requirements-dev.lock requirements-server.lock requirements-s3.lock requirements-mcp.in requirements-mcp.lock requirements-postgres.lock
2
+ recursive-include docs *.md *.json
3
+ recursive-include examples *.py
4
+ recursive-include tests *.py
5
+ recursive-include scripts *.py *.sh
6
+ include frontend/package.json frontend/package-lock.json frontend/index.html frontend/vite.config.js
7
+ include frontend/.node-version frontend/.npmrc
8
+ recursive-include frontend/src *.js *.vue *.css *.json
evlet-0.1.0/PKG-INFO ADDED
@@ -0,0 +1,290 @@
1
+ Metadata-Version: 2.4
2
+ Name: evlet
3
+ Version: 0.1.0
4
+ Summary: A small Python application framework with SQLite and a neutral UI schema
5
+ License-Expression: MIT
6
+ Requires-Python: >=3.12
7
+ Description-Content-Type: text/markdown
8
+ License-File: LICENSE
9
+ Provides-Extra: postgres
10
+ Requires-Dist: psycopg[binary]<4,>=3.3.6; extra == "postgres"
11
+ Requires-Dist: psycopg-pool<4,>=3.3.3; extra == "postgres"
12
+ Provides-Extra: s3
13
+ Requires-Dist: boto3<2,>=1.43.119; extra == "s3"
14
+ Provides-Extra: dev
15
+ Requires-Dist: pytest<10,>=8; extra == "dev"
16
+ Requires-Dist: uvicorn<1,>=0.34; extra == "dev"
17
+ Requires-Dist: build<2,>=1; extra == "dev"
18
+ Requires-Dist: setuptools>=75; extra == "dev"
19
+ Dynamic: license-file
20
+
21
+ # Evlet
22
+
23
+ A small Python application framework for business applications. This repository
24
+ implements **Milestone 8**: optional PostgreSQL persistence, large-data and
25
+ concurrency measurements, tenant security regression tests, and deployment
26
+ operations documentation. SQLite remains the default; PostgreSQL is optional.
27
+
28
+ Python model definitions remain authoritative. The core has **zero third-party
29
+ runtime dependencies**. No database server, Redis, Docker, or worker is required.
30
+
31
+ ## Install the Python package
32
+
33
+ Requires Python 3.12 or newer:
34
+
35
+ ```bash
36
+ python -m pip install evlet
37
+ evlet --help
38
+ ```
39
+
40
+ Optional adapters are available with `python -m pip install 'evlet[postgres]'`
41
+ or `python -m pip install 'evlet[s3]'`. To serve an application, install an ASGI
42
+ server such as Uvicorn separately. The installed Python package contains the
43
+ framework and command-line tools. The Vue Playground requires the source
44
+ distribution or a repository checkout and the setup below.
45
+
46
+ ## License
47
+
48
+ Evlet is available under the [MIT License](https://github.com/dxb-aslam/evlet/blob/main/LICENSE).
49
+
50
+ ## Open the Playground on macOS
51
+
52
+ Install Git, Python 3.12+, and Node 24.15+ (24.x). If you use Homebrew:
53
+
54
+ ```bash
55
+ brew install git python@3.12 node@24
56
+ ```
57
+
58
+ Then, in Terminal:
59
+
60
+ ```bash
61
+ git clone https://github.com/dxb-aslam/evlet.git
62
+ cd evlet
63
+ bash scripts/playground.sh --setup
64
+ ```
65
+
66
+ This private repository requires your GitHub account to have access. You can also
67
+ download the feature branch as a ZIP while signed in to GitHub, extract it, open
68
+ Terminal in the extracted folder, and run the same launcher command.
69
+
70
+ The launcher installs the locked dependencies, starts both servers and an optional
71
+ job worker, checks the API, and opens the Playground in your default browser. Keep Terminal open while
72
+ using the app. Press **Control-C** to stop its processes; your SQLite data remains.
73
+ On later runs, use `bash scripts/playground.sh` from the same folder. The launcher
74
+ activates Homebrew's versioned Node and Python paths for its own process only.
75
+
76
+ Logs are in `examples/playground/.data/logs/5173/` by default. If ports 8000 or 5173 are already
77
+ occupied, the launcher exits without stopping any existing service. Linux can
78
+ use the same launcher with Python and Node already installed. Set
79
+ `EVLET_OPEN_BROWSER=0` for noninteractive validation.
80
+
81
+ For an existing Milestone 1, 2, or 3 database, stop the launcher and run
82
+ `.venv/bin/python -m examples.playground.migrate` before restarting it. SQLite upgrades create
83
+ a backup and preserve existing records. When `EVLET_POSTGRES_DSN` is set, the
84
+ command upgrades PostgreSQL instead; take an operator-managed PostgreSQL backup
85
+ first, as described in the [PostgreSQL guide](docs/postgresql.md). See the [model engine guide](docs/model-engine.md)
86
+ for the API, migration operations, and current limits.
87
+
88
+ ## Install for development
89
+
90
+ Requires Python 3.12+ with `venv`, Node **24.15+ in the 24.x line**, and npm.
91
+ The cloud environment was verified with Python 3.12.14 and Node 24.19.0.
92
+ Run from the repository root:
93
+
94
+ ```bash
95
+ python3 -m venv .venv
96
+ .venv/bin/python -m pip install --require-hashes -r requirements-dev.lock
97
+ .venv/bin/python -m pip install --no-build-isolation --no-deps -e .
98
+ npm --prefix frontend ci
99
+ ```
100
+
101
+ In a managed cloud checkout, use the existing checkout at `/workspace/evlet` and set writable
102
+ package caches if the default home directory is read-only:
103
+
104
+ ```bash
105
+ export PIP_CACHE_DIR=/workspace/.cache/pip
106
+ export npm_config_cache=/workspace/.cache/npm
107
+ ```
108
+
109
+ The lockfiles pin development dependencies and preserve package-integrity checks.
110
+ Do not regenerate them during routine setup. To intentionally update the Python
111
+ lock with `uv` installed, run `uv pip compile pyproject.toml --extra dev --universal
112
+ --generate-hashes --output-file requirements-dev.lock`, then rerun validation.
113
+ `uv` is only a lock-maintenance tool; ordinary setup uses pip.
114
+
115
+ ## Run the Playground
116
+
117
+ From the root, start the backend in one terminal:
118
+
119
+ ```bash
120
+ .venv/bin/python -m uvicorn examples.playground.app:create_app --factory --host 127.0.0.1 --port 8000
121
+ ```
122
+
123
+ In another terminal, start Vite:
124
+
125
+ ```bash
126
+ npm --prefix frontend run dev
127
+ ```
128
+
129
+ The backend listens on port 8000; Vite listens on port 5173 and proxies `/api` and
130
+ `/health` to it. Both bind to loopback. Use your development environment's normal
131
+ browser access where supported. The onboarding UI itself does not provide a web
132
+ preview; local HTTP requests still verify the running application.
133
+
134
+ Create the first administrator account when prompted. Use Accounts to add Editor
135
+ or Viewer accounts. Then create a customer, an invoice referencing it, and a payment
136
+ referencing that invoice. Refresh or restart the backend to verify persistence.
137
+ The default database is `examples/playground/.data/playground.sqlite3`, ignored
138
+ by Git. `EVLET_DATABASE` can select another SQLite file. Each database has its own accounts.
139
+ Projects demonstrate child tasks, Start/Complete actions, private attachments, and
140
+ a queued **Recalculate progress** action. The launcher starts its worker; with
141
+ manual startup, run `.venv/bin/python -m examples.playground.worker` separately.
142
+
143
+ Check the live workflow from the root:
144
+
145
+ ```bash
146
+ curl --fail http://127.0.0.1:8000/health
147
+ .venv/bin/python scripts/smoke.py --base-url http://127.0.0.1:5173
148
+ ```
149
+
150
+ The smoke check prompts for an existing Admin or Editor account. It creates a
151
+ uniquely named customer, invoice, payment, and Project, checks
152
+ updates, queries, validation, protected deletes, then removes its own records. Use a disposable database via `EVLET_DATABASE` for validation runs when you
153
+ do not want sample records in your working database. It also checks validation,
154
+ foreign-key errors, and exact decimal serialization through real HTTP requests.
155
+
156
+ ## Use the Python API
157
+
158
+ ```python
159
+ from evlet import Application, Currency, Database, Link, Model, Registry, Text
160
+
161
+ class Customer(Model):
162
+ name = Text(required=True)
163
+
164
+ class Invoice(Model):
165
+ customer = Link(Customer, required=True)
166
+ reference = Text(required=True, unique=True)
167
+ total = Currency(required=True, minimum="0.01")
168
+
169
+ database = Database(".data/example.sqlite3", Registry(Customer, Invoice))
170
+ database.initialize()
171
+
172
+ with database.transaction() as transaction:
173
+ customer = transaction.create(Customer, name="Acme")
174
+ invoice = transaction.create(
175
+ Invoice, customer=customer.id, reference="INV-001", total="100.10"
176
+ )
177
+
178
+ assert database.get(Invoice, invoice.id).to_dict()["total"] == "100.10"
179
+ # Configure LocalAuth before serving protected records over HTTP.
180
+ app = Application(database)
181
+ ```
182
+
183
+ Transactions commit on success and roll back together on failure. Use decimal
184
+ strings for currency. `Integer` is also available; `Text` supports length bounds,
185
+ required values, defaults, and uniqueness. `Link` uses actual SQLite foreign keys.
186
+ An application registers models explicitly, so unrelated classes are not exposed.
187
+ When shipping migrations, declare the complete history with
188
+ `Database(path, registry, migrations=migrations)` so fresh initialization records
189
+ its baseline. Apply later schema changes explicitly with `database.migrate(migrations)`.
190
+ See the [migration guide](docs/model-engine.md#explicit-migrations).
191
+
192
+ ## Test and build
193
+
194
+ ```bash
195
+ .venv/bin/python -m pytest
196
+ npm --prefix frontend test
197
+ npm --prefix frontend run build
198
+ .venv/bin/python -m build --no-isolation
199
+ python3 -m venv /tmp/evlet-wheel-check
200
+ /tmp/evlet-wheel-check/bin/python -m pip install --no-deps dist/evlet-0.1.0-py3-none-any.whl
201
+ /tmp/evlet-wheel-check/bin/python -I scripts/check_package.py
202
+ ```
203
+
204
+ The Python suite exercises real SQLite files, validation, rollback, constraints,
205
+ concurrent short writes, and full ASGI requests. The frontend suite uses real
206
+ PrimeVue components and substitutes only HTTP responses and missing DOM layout
207
+ APIs. The live smoke check covers the actual server and Vite proxy. Package checks
208
+ verify the installed wheel outside the source tree. GitHub Actions runs Python
209
+ tests on 3.12 and 3.13, distribution checks, frontend tests/build, and a live API
210
+ smoke check. Cloud validation does not establish that remote CI has run.
211
+
212
+ Build output is in `dist/` and `frontend/dist/`. `npm --prefix frontend run preview`
213
+ serves the production frontend on port 4173 with the same local backend proxy.
214
+ This is a development preview, not a deployment recipe.
215
+
216
+ ## Current boundaries
217
+
218
+ - Create, read, update, delete, typed queries, and explicit additive/rename/index
219
+ migrations are supported. Destructive migrations and arbitrary field-type
220
+ conversions are not supported. Startup rejects schema drift.
221
+ - Local accounts and backend model/record/field permissions are implemented.
222
+ The Playground uses them; a bare `Application(database)` stays unauthenticated
223
+ for compatibility. Keep development servers on loopback. SSO and email recovery
224
+ remain outside the implemented scope.
225
+ - Currency has two decimal places and no currency-code conversion. The Playground
226
+ is a persistence example, not a ledger or payment processor.
227
+ - Email is a bounded text field; browser email validation is convenience only.
228
+ - Lists, counts, search, filters, and relationship choices use bounded server queries.
229
+ Text search uses SQLite ASCII case folding. Browser integer actions require safe integers.
230
+ - Forms, lists, and details are generated from renderer-neutral Python metadata.
231
+ Full PrimeVue controls and the theme currently produce a JavaScript bundle above
232
+ Vite's 500 kB advisory threshold. The build succeeds; bundle optimization is
233
+ follow-up work. No performance or scalability guarantees are claimed.
234
+
235
+ Read [architecture decisions](docs/architecture.md), the [full specification](docs/specification.md),
236
+ and [agent instructions](AGENTS.md). The [model engine guide](docs/model-engine.md)
237
+ covers the model engine. See [application generation](docs/application-generation.md)
238
+ for Milestone 3 metadata, defaults, generated screens, and upgrade instructions.
239
+ See [business capabilities](docs/business-capabilities.md) for Milestone 4 APIs,
240
+ account setup, permissions, actions, children, attachments, and limits.
241
+
242
+
243
+ ## Milestone 5: tenants and deployment
244
+
245
+ The [tenant and deployment guide](docs/tenancy-deployment.md) covers separate tenant
246
+ SQLite files, hostname routing, DNS ownership verification, private file storage,
247
+ and the Caddy/systemd reference deployment. The ordinary Playground retains its
248
+ existing database and startup command. Tenant setup uses a separate catalog and
249
+ prompts for its first administrator through the local management command.
250
+
251
+ Run `python scripts/smoke_tenants.py` with the virtual environment active to check
252
+ two disposable tenants over HTTP. Add `--frontend` to test Vite or `--caddy` to test
253
+ local HTTPS after building the frontend. No deployment runs automatically.
254
+
255
+
256
+ ## Milestone 6: jobs, live updates, and adapters
257
+
258
+ The [jobs and live-update guide](docs/jobs-realtime.md) covers transactional jobs,
259
+ retries, schedules, permission-filtered SSE and polling, and the optional S3/R2
260
+ storage and Lambda HTTP adapters. No Redis or distributed queue is required.
261
+ Use `EVLET_RUN_JOBS=0` to run the Playground without a worker.
262
+
263
+ The Lambda adapter supplies HTTP transport only. It does not make the SQLite
264
+ Playground deployable on an ephemeral filesystem. No cloud resources are created,
265
+ and live cloud operation has not been verified. WebSockets and broader production
266
+ hardening remain deferred.
267
+
268
+
269
+ ## Milestone 7: discovery and connector interfaces
270
+
271
+ The [connector guide](docs/connector.md) covers compact discovery, model input
272
+ schemas, a local MCP stdio connector, private session files, and starter generation.
273
+ Run `python -m evlet new ./my-app` to create a small authenticated application.
274
+ The connector starts with read tools; `--allow-writes` explicitly enables permitted
275
+ writes through the existing HTTP API. Every request retains backend permission
276
+ checks. No external provider or additional runtime dependency is required.
277
+
278
+ Install `requirements-mcp.lock` with `--require-hashes` to include the optional
279
+ official-client interoperability test. CI includes it; ordinary Playground setup
280
+ does not need it. Remote MCP hosting and production hardening remain separate work.
281
+
282
+ ## Milestone 8: performance and hardening
283
+
284
+ - [PostgreSQL setup, transaction behavior, and migration limits](docs/postgresql.md)
285
+ - [Reproducible workload and measured adapter comparison](docs/performance.md)
286
+ - [Deployment, backup, recovery, and monitoring](docs/production-operations.md)
287
+
288
+ The existing tenant catalog remains SQLite-only. PostgreSQL supports authenticated
289
+ single-application deployments and conservatively serializes writes per database.
290
+ No production scale or parallel-write capacity is implied by this release.
evlet-0.1.0/README.md ADDED
@@ -0,0 +1,270 @@
1
+ # Evlet
2
+
3
+ A small Python application framework for business applications. This repository
4
+ implements **Milestone 8**: optional PostgreSQL persistence, large-data and
5
+ concurrency measurements, tenant security regression tests, and deployment
6
+ operations documentation. SQLite remains the default; PostgreSQL is optional.
7
+
8
+ Python model definitions remain authoritative. The core has **zero third-party
9
+ runtime dependencies**. No database server, Redis, Docker, or worker is required.
10
+
11
+ ## Install the Python package
12
+
13
+ Requires Python 3.12 or newer:
14
+
15
+ ```bash
16
+ python -m pip install evlet
17
+ evlet --help
18
+ ```
19
+
20
+ Optional adapters are available with `python -m pip install 'evlet[postgres]'`
21
+ or `python -m pip install 'evlet[s3]'`. To serve an application, install an ASGI
22
+ server such as Uvicorn separately. The installed Python package contains the
23
+ framework and command-line tools. The Vue Playground requires the source
24
+ distribution or a repository checkout and the setup below.
25
+
26
+ ## License
27
+
28
+ Evlet is available under the [MIT License](https://github.com/dxb-aslam/evlet/blob/main/LICENSE).
29
+
30
+ ## Open the Playground on macOS
31
+
32
+ Install Git, Python 3.12+, and Node 24.15+ (24.x). If you use Homebrew:
33
+
34
+ ```bash
35
+ brew install git python@3.12 node@24
36
+ ```
37
+
38
+ Then, in Terminal:
39
+
40
+ ```bash
41
+ git clone https://github.com/dxb-aslam/evlet.git
42
+ cd evlet
43
+ bash scripts/playground.sh --setup
44
+ ```
45
+
46
+ This private repository requires your GitHub account to have access. You can also
47
+ download the feature branch as a ZIP while signed in to GitHub, extract it, open
48
+ Terminal in the extracted folder, and run the same launcher command.
49
+
50
+ The launcher installs the locked dependencies, starts both servers and an optional
51
+ job worker, checks the API, and opens the Playground in your default browser. Keep Terminal open while
52
+ using the app. Press **Control-C** to stop its processes; your SQLite data remains.
53
+ On later runs, use `bash scripts/playground.sh` from the same folder. The launcher
54
+ activates Homebrew's versioned Node and Python paths for its own process only.
55
+
56
+ Logs are in `examples/playground/.data/logs/5173/` by default. If ports 8000 or 5173 are already
57
+ occupied, the launcher exits without stopping any existing service. Linux can
58
+ use the same launcher with Python and Node already installed. Set
59
+ `EVLET_OPEN_BROWSER=0` for noninteractive validation.
60
+
61
+ For an existing Milestone 1, 2, or 3 database, stop the launcher and run
62
+ `.venv/bin/python -m examples.playground.migrate` before restarting it. SQLite upgrades create
63
+ a backup and preserve existing records. When `EVLET_POSTGRES_DSN` is set, the
64
+ command upgrades PostgreSQL instead; take an operator-managed PostgreSQL backup
65
+ first, as described in the [PostgreSQL guide](docs/postgresql.md). See the [model engine guide](docs/model-engine.md)
66
+ for the API, migration operations, and current limits.
67
+
68
+ ## Install for development
69
+
70
+ Requires Python 3.12+ with `venv`, Node **24.15+ in the 24.x line**, and npm.
71
+ The cloud environment was verified with Python 3.12.14 and Node 24.19.0.
72
+ Run from the repository root:
73
+
74
+ ```bash
75
+ python3 -m venv .venv
76
+ .venv/bin/python -m pip install --require-hashes -r requirements-dev.lock
77
+ .venv/bin/python -m pip install --no-build-isolation --no-deps -e .
78
+ npm --prefix frontend ci
79
+ ```
80
+
81
+ In a managed cloud checkout, use the existing checkout at `/workspace/evlet` and set writable
82
+ package caches if the default home directory is read-only:
83
+
84
+ ```bash
85
+ export PIP_CACHE_DIR=/workspace/.cache/pip
86
+ export npm_config_cache=/workspace/.cache/npm
87
+ ```
88
+
89
+ The lockfiles pin development dependencies and preserve package-integrity checks.
90
+ Do not regenerate them during routine setup. To intentionally update the Python
91
+ lock with `uv` installed, run `uv pip compile pyproject.toml --extra dev --universal
92
+ --generate-hashes --output-file requirements-dev.lock`, then rerun validation.
93
+ `uv` is only a lock-maintenance tool; ordinary setup uses pip.
94
+
95
+ ## Run the Playground
96
+
97
+ From the root, start the backend in one terminal:
98
+
99
+ ```bash
100
+ .venv/bin/python -m uvicorn examples.playground.app:create_app --factory --host 127.0.0.1 --port 8000
101
+ ```
102
+
103
+ In another terminal, start Vite:
104
+
105
+ ```bash
106
+ npm --prefix frontend run dev
107
+ ```
108
+
109
+ The backend listens on port 8000; Vite listens on port 5173 and proxies `/api` and
110
+ `/health` to it. Both bind to loopback. Use your development environment's normal
111
+ browser access where supported. The onboarding UI itself does not provide a web
112
+ preview; local HTTP requests still verify the running application.
113
+
114
+ Create the first administrator account when prompted. Use Accounts to add Editor
115
+ or Viewer accounts. Then create a customer, an invoice referencing it, and a payment
116
+ referencing that invoice. Refresh or restart the backend to verify persistence.
117
+ The default database is `examples/playground/.data/playground.sqlite3`, ignored
118
+ by Git. `EVLET_DATABASE` can select another SQLite file. Each database has its own accounts.
119
+ Projects demonstrate child tasks, Start/Complete actions, private attachments, and
120
+ a queued **Recalculate progress** action. The launcher starts its worker; with
121
+ manual startup, run `.venv/bin/python -m examples.playground.worker` separately.
122
+
123
+ Check the live workflow from the root:
124
+
125
+ ```bash
126
+ curl --fail http://127.0.0.1:8000/health
127
+ .venv/bin/python scripts/smoke.py --base-url http://127.0.0.1:5173
128
+ ```
129
+
130
+ The smoke check prompts for an existing Admin or Editor account. It creates a
131
+ uniquely named customer, invoice, payment, and Project, checks
132
+ updates, queries, validation, protected deletes, then removes its own records. Use a disposable database via `EVLET_DATABASE` for validation runs when you
133
+ do not want sample records in your working database. It also checks validation,
134
+ foreign-key errors, and exact decimal serialization through real HTTP requests.
135
+
136
+ ## Use the Python API
137
+
138
+ ```python
139
+ from evlet import Application, Currency, Database, Link, Model, Registry, Text
140
+
141
+ class Customer(Model):
142
+ name = Text(required=True)
143
+
144
+ class Invoice(Model):
145
+ customer = Link(Customer, required=True)
146
+ reference = Text(required=True, unique=True)
147
+ total = Currency(required=True, minimum="0.01")
148
+
149
+ database = Database(".data/example.sqlite3", Registry(Customer, Invoice))
150
+ database.initialize()
151
+
152
+ with database.transaction() as transaction:
153
+ customer = transaction.create(Customer, name="Acme")
154
+ invoice = transaction.create(
155
+ Invoice, customer=customer.id, reference="INV-001", total="100.10"
156
+ )
157
+
158
+ assert database.get(Invoice, invoice.id).to_dict()["total"] == "100.10"
159
+ # Configure LocalAuth before serving protected records over HTTP.
160
+ app = Application(database)
161
+ ```
162
+
163
+ Transactions commit on success and roll back together on failure. Use decimal
164
+ strings for currency. `Integer` is also available; `Text` supports length bounds,
165
+ required values, defaults, and uniqueness. `Link` uses actual SQLite foreign keys.
166
+ An application registers models explicitly, so unrelated classes are not exposed.
167
+ When shipping migrations, declare the complete history with
168
+ `Database(path, registry, migrations=migrations)` so fresh initialization records
169
+ its baseline. Apply later schema changes explicitly with `database.migrate(migrations)`.
170
+ See the [migration guide](docs/model-engine.md#explicit-migrations).
171
+
172
+ ## Test and build
173
+
174
+ ```bash
175
+ .venv/bin/python -m pytest
176
+ npm --prefix frontend test
177
+ npm --prefix frontend run build
178
+ .venv/bin/python -m build --no-isolation
179
+ python3 -m venv /tmp/evlet-wheel-check
180
+ /tmp/evlet-wheel-check/bin/python -m pip install --no-deps dist/evlet-0.1.0-py3-none-any.whl
181
+ /tmp/evlet-wheel-check/bin/python -I scripts/check_package.py
182
+ ```
183
+
184
+ The Python suite exercises real SQLite files, validation, rollback, constraints,
185
+ concurrent short writes, and full ASGI requests. The frontend suite uses real
186
+ PrimeVue components and substitutes only HTTP responses and missing DOM layout
187
+ APIs. The live smoke check covers the actual server and Vite proxy. Package checks
188
+ verify the installed wheel outside the source tree. GitHub Actions runs Python
189
+ tests on 3.12 and 3.13, distribution checks, frontend tests/build, and a live API
190
+ smoke check. Cloud validation does not establish that remote CI has run.
191
+
192
+ Build output is in `dist/` and `frontend/dist/`. `npm --prefix frontend run preview`
193
+ serves the production frontend on port 4173 with the same local backend proxy.
194
+ This is a development preview, not a deployment recipe.
195
+
196
+ ## Current boundaries
197
+
198
+ - Create, read, update, delete, typed queries, and explicit additive/rename/index
199
+ migrations are supported. Destructive migrations and arbitrary field-type
200
+ conversions are not supported. Startup rejects schema drift.
201
+ - Local accounts and backend model/record/field permissions are implemented.
202
+ The Playground uses them; a bare `Application(database)` stays unauthenticated
203
+ for compatibility. Keep development servers on loopback. SSO and email recovery
204
+ remain outside the implemented scope.
205
+ - Currency has two decimal places and no currency-code conversion. The Playground
206
+ is a persistence example, not a ledger or payment processor.
207
+ - Email is a bounded text field; browser email validation is convenience only.
208
+ - Lists, counts, search, filters, and relationship choices use bounded server queries.
209
+ Text search uses SQLite ASCII case folding. Browser integer actions require safe integers.
210
+ - Forms, lists, and details are generated from renderer-neutral Python metadata.
211
+ Full PrimeVue controls and the theme currently produce a JavaScript bundle above
212
+ Vite's 500 kB advisory threshold. The build succeeds; bundle optimization is
213
+ follow-up work. No performance or scalability guarantees are claimed.
214
+
215
+ Read [architecture decisions](docs/architecture.md), the [full specification](docs/specification.md),
216
+ and [agent instructions](AGENTS.md). The [model engine guide](docs/model-engine.md)
217
+ covers the model engine. See [application generation](docs/application-generation.md)
218
+ for Milestone 3 metadata, defaults, generated screens, and upgrade instructions.
219
+ See [business capabilities](docs/business-capabilities.md) for Milestone 4 APIs,
220
+ account setup, permissions, actions, children, attachments, and limits.
221
+
222
+
223
+ ## Milestone 5: tenants and deployment
224
+
225
+ The [tenant and deployment guide](docs/tenancy-deployment.md) covers separate tenant
226
+ SQLite files, hostname routing, DNS ownership verification, private file storage,
227
+ and the Caddy/systemd reference deployment. The ordinary Playground retains its
228
+ existing database and startup command. Tenant setup uses a separate catalog and
229
+ prompts for its first administrator through the local management command.
230
+
231
+ Run `python scripts/smoke_tenants.py` with the virtual environment active to check
232
+ two disposable tenants over HTTP. Add `--frontend` to test Vite or `--caddy` to test
233
+ local HTTPS after building the frontend. No deployment runs automatically.
234
+
235
+
236
+ ## Milestone 6: jobs, live updates, and adapters
237
+
238
+ The [jobs and live-update guide](docs/jobs-realtime.md) covers transactional jobs,
239
+ retries, schedules, permission-filtered SSE and polling, and the optional S3/R2
240
+ storage and Lambda HTTP adapters. No Redis or distributed queue is required.
241
+ Use `EVLET_RUN_JOBS=0` to run the Playground without a worker.
242
+
243
+ The Lambda adapter supplies HTTP transport only. It does not make the SQLite
244
+ Playground deployable on an ephemeral filesystem. No cloud resources are created,
245
+ and live cloud operation has not been verified. WebSockets and broader production
246
+ hardening remain deferred.
247
+
248
+
249
+ ## Milestone 7: discovery and connector interfaces
250
+
251
+ The [connector guide](docs/connector.md) covers compact discovery, model input
252
+ schemas, a local MCP stdio connector, private session files, and starter generation.
253
+ Run `python -m evlet new ./my-app` to create a small authenticated application.
254
+ The connector starts with read tools; `--allow-writes` explicitly enables permitted
255
+ writes through the existing HTTP API. Every request retains backend permission
256
+ checks. No external provider or additional runtime dependency is required.
257
+
258
+ Install `requirements-mcp.lock` with `--require-hashes` to include the optional
259
+ official-client interoperability test. CI includes it; ordinary Playground setup
260
+ does not need it. Remote MCP hosting and production hardening remain separate work.
261
+
262
+ ## Milestone 8: performance and hardening
263
+
264
+ - [PostgreSQL setup, transaction behavior, and migration limits](docs/postgresql.md)
265
+ - [Reproducible workload and measured adapter comparison](docs/performance.md)
266
+ - [Deployment, backup, recovery, and monitoring](docs/production-operations.md)
267
+
268
+ The existing tenant catalog remains SQLite-only. PostgreSQL supports authenticated
269
+ single-application deployments and conservatively serializes writes per database.
270
+ No production scale or parallel-write capacity is implied by this release.