mdb-engine 0.2.3__tar.gz → 0.3.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.
- {mdb_engine-0.2.3/mdb_engine.egg-info → mdb_engine-0.3.0}/PKG-INFO +193 -14
- {mdb_engine-0.2.3 → mdb_engine-0.3.0}/README.md +192 -13
- {mdb_engine-0.2.3 → mdb_engine-0.3.0}/mdb_engine/__init__.py +8 -1
- {mdb_engine-0.2.3 → mdb_engine-0.3.0}/mdb_engine/auth/README.md +6 -0
- {mdb_engine-0.2.3 → mdb_engine-0.3.0}/mdb_engine/auth/shared_middleware.py +330 -119
- {mdb_engine-0.2.3 → mdb_engine-0.3.0}/mdb_engine/core/engine.py +417 -5
- {mdb_engine-0.2.3 → mdb_engine-0.3.0}/mdb_engine/core/manifest.py +114 -0
- {mdb_engine-0.2.3 → mdb_engine-0.3.0}/mdb_engine/embeddings/service.py +37 -8
- {mdb_engine-0.2.3 → mdb_engine-0.3.0}/mdb_engine/memory/README.md +93 -2
- mdb_engine-0.3.0/mdb_engine/memory/service.py +480 -0
- {mdb_engine-0.2.3 → mdb_engine-0.3.0}/mdb_engine/utils/__init__.py +3 -1
- mdb_engine-0.3.0/mdb_engine/utils/mongo.py +117 -0
- {mdb_engine-0.2.3 → mdb_engine-0.3.0/mdb_engine.egg-info}/PKG-INFO +193 -14
- {mdb_engine-0.2.3 → mdb_engine-0.3.0}/mdb_engine.egg-info/SOURCES.txt +2 -1
- {mdb_engine-0.2.3 → mdb_engine-0.3.0}/pyproject.toml +1 -1
- {mdb_engine-0.2.3 → mdb_engine-0.3.0}/setup.py +1 -1
- mdb_engine-0.2.3/mdb_engine/memory/service.py +0 -1228
- {mdb_engine-0.2.3 → mdb_engine-0.3.0}/LICENSE +0 -0
- {mdb_engine-0.2.3 → mdb_engine-0.3.0}/MANIFEST.in +0 -0
- {mdb_engine-0.2.3 → mdb_engine-0.3.0}/mdb_engine/README.md +0 -0
- {mdb_engine-0.2.3 → mdb_engine-0.3.0}/mdb_engine/auth/ARCHITECTURE.md +0 -0
- {mdb_engine-0.2.3 → mdb_engine-0.3.0}/mdb_engine/auth/__init__.py +0 -0
- {mdb_engine-0.2.3 → mdb_engine-0.3.0}/mdb_engine/auth/audit.py +0 -0
- {mdb_engine-0.2.3 → mdb_engine-0.3.0}/mdb_engine/auth/base.py +0 -0
- {mdb_engine-0.2.3 → mdb_engine-0.3.0}/mdb_engine/auth/casbin_factory.py +0 -0
- {mdb_engine-0.2.3 → mdb_engine-0.3.0}/mdb_engine/auth/casbin_models.py +0 -0
- {mdb_engine-0.2.3 → mdb_engine-0.3.0}/mdb_engine/auth/config_defaults.py +0 -0
- {mdb_engine-0.2.3 → mdb_engine-0.3.0}/mdb_engine/auth/config_helpers.py +0 -0
- {mdb_engine-0.2.3 → mdb_engine-0.3.0}/mdb_engine/auth/cookie_utils.py +0 -0
- {mdb_engine-0.2.3 → mdb_engine-0.3.0}/mdb_engine/auth/csrf.py +0 -0
- {mdb_engine-0.2.3 → mdb_engine-0.3.0}/mdb_engine/auth/decorators.py +0 -0
- {mdb_engine-0.2.3 → mdb_engine-0.3.0}/mdb_engine/auth/dependencies.py +0 -0
- {mdb_engine-0.2.3 → mdb_engine-0.3.0}/mdb_engine/auth/helpers.py +0 -0
- {mdb_engine-0.2.3 → mdb_engine-0.3.0}/mdb_engine/auth/integration.py +0 -0
- {mdb_engine-0.2.3 → mdb_engine-0.3.0}/mdb_engine/auth/jwt.py +0 -0
- {mdb_engine-0.2.3 → mdb_engine-0.3.0}/mdb_engine/auth/middleware.py +0 -0
- {mdb_engine-0.2.3 → mdb_engine-0.3.0}/mdb_engine/auth/oso_factory.py +0 -0
- {mdb_engine-0.2.3 → mdb_engine-0.3.0}/mdb_engine/auth/provider.py +0 -0
- {mdb_engine-0.2.3 → mdb_engine-0.3.0}/mdb_engine/auth/rate_limiter.py +0 -0
- {mdb_engine-0.2.3 → mdb_engine-0.3.0}/mdb_engine/auth/restrictions.py +0 -0
- {mdb_engine-0.2.3 → mdb_engine-0.3.0}/mdb_engine/auth/session_manager.py +0 -0
- {mdb_engine-0.2.3 → mdb_engine-0.3.0}/mdb_engine/auth/shared_users.py +0 -0
- {mdb_engine-0.2.3 → mdb_engine-0.3.0}/mdb_engine/auth/token_lifecycle.py +0 -0
- {mdb_engine-0.2.3 → mdb_engine-0.3.0}/mdb_engine/auth/token_store.py +0 -0
- {mdb_engine-0.2.3 → mdb_engine-0.3.0}/mdb_engine/auth/users.py +0 -0
- {mdb_engine-0.2.3 → mdb_engine-0.3.0}/mdb_engine/auth/utils.py +0 -0
- {mdb_engine-0.2.3 → mdb_engine-0.3.0}/mdb_engine/cli/__init__.py +0 -0
- {mdb_engine-0.2.3 → mdb_engine-0.3.0}/mdb_engine/cli/commands/__init__.py +0 -0
- {mdb_engine-0.2.3 → mdb_engine-0.3.0}/mdb_engine/cli/commands/generate.py +0 -0
- {mdb_engine-0.2.3 → mdb_engine-0.3.0}/mdb_engine/cli/commands/migrate.py +0 -0
- {mdb_engine-0.2.3 → mdb_engine-0.3.0}/mdb_engine/cli/commands/show.py +0 -0
- {mdb_engine-0.2.3 → mdb_engine-0.3.0}/mdb_engine/cli/commands/validate.py +0 -0
- {mdb_engine-0.2.3 → mdb_engine-0.3.0}/mdb_engine/cli/main.py +0 -0
- {mdb_engine-0.2.3 → mdb_engine-0.3.0}/mdb_engine/cli/utils.py +0 -0
- {mdb_engine-0.2.3 → mdb_engine-0.3.0}/mdb_engine/config.py +0 -0
- {mdb_engine-0.2.3 → mdb_engine-0.3.0}/mdb_engine/constants.py +0 -0
- {mdb_engine-0.2.3 → mdb_engine-0.3.0}/mdb_engine/core/README.md +0 -0
- {mdb_engine-0.2.3 → mdb_engine-0.3.0}/mdb_engine/core/__init__.py +0 -0
- {mdb_engine-0.2.3 → mdb_engine-0.3.0}/mdb_engine/core/app_registration.py +0 -0
- {mdb_engine-0.2.3 → mdb_engine-0.3.0}/mdb_engine/core/app_secrets.py +0 -0
- {mdb_engine-0.2.3 → mdb_engine-0.3.0}/mdb_engine/core/connection.py +0 -0
- {mdb_engine-0.2.3 → mdb_engine-0.3.0}/mdb_engine/core/encryption.py +0 -0
- {mdb_engine-0.2.3 → mdb_engine-0.3.0}/mdb_engine/core/index_management.py +0 -0
- {mdb_engine-0.2.3 → mdb_engine-0.3.0}/mdb_engine/core/ray_integration.py +0 -0
- {mdb_engine-0.2.3 → mdb_engine-0.3.0}/mdb_engine/core/seeding.py +0 -0
- {mdb_engine-0.2.3 → mdb_engine-0.3.0}/mdb_engine/core/service_initialization.py +0 -0
- {mdb_engine-0.2.3 → mdb_engine-0.3.0}/mdb_engine/core/types.py +0 -0
- {mdb_engine-0.2.3 → mdb_engine-0.3.0}/mdb_engine/database/README.md +0 -0
- {mdb_engine-0.2.3 → mdb_engine-0.3.0}/mdb_engine/database/__init__.py +0 -0
- {mdb_engine-0.2.3 → mdb_engine-0.3.0}/mdb_engine/database/abstraction.py +0 -0
- {mdb_engine-0.2.3 → mdb_engine-0.3.0}/mdb_engine/database/connection.py +0 -0
- {mdb_engine-0.2.3 → mdb_engine-0.3.0}/mdb_engine/database/query_validator.py +0 -0
- {mdb_engine-0.2.3 → mdb_engine-0.3.0}/mdb_engine/database/resource_limiter.py +0 -0
- {mdb_engine-0.2.3 → mdb_engine-0.3.0}/mdb_engine/database/scoped_wrapper.py +0 -0
- {mdb_engine-0.2.3 → mdb_engine-0.3.0}/mdb_engine/dependencies.py +0 -0
- {mdb_engine-0.2.3 → mdb_engine-0.3.0}/mdb_engine/di/__init__.py +0 -0
- {mdb_engine-0.2.3 → mdb_engine-0.3.0}/mdb_engine/di/container.py +0 -0
- {mdb_engine-0.2.3 → mdb_engine-0.3.0}/mdb_engine/di/providers.py +0 -0
- {mdb_engine-0.2.3 → mdb_engine-0.3.0}/mdb_engine/di/scopes.py +0 -0
- {mdb_engine-0.2.3 → mdb_engine-0.3.0}/mdb_engine/embeddings/README.md +0 -0
- {mdb_engine-0.2.3 → mdb_engine-0.3.0}/mdb_engine/embeddings/__init__.py +0 -0
- {mdb_engine-0.2.3 → mdb_engine-0.3.0}/mdb_engine/embeddings/dependencies.py +0 -0
- {mdb_engine-0.2.3 → mdb_engine-0.3.0}/mdb_engine/exceptions.py +0 -0
- {mdb_engine-0.2.3 → mdb_engine-0.3.0}/mdb_engine/indexes/README.md +0 -0
- {mdb_engine-0.2.3 → mdb_engine-0.3.0}/mdb_engine/indexes/__init__.py +0 -0
- {mdb_engine-0.2.3 → mdb_engine-0.3.0}/mdb_engine/indexes/helpers.py +0 -0
- {mdb_engine-0.2.3 → mdb_engine-0.3.0}/mdb_engine/indexes/manager.py +0 -0
- {mdb_engine-0.2.3 → mdb_engine-0.3.0}/mdb_engine/memory/__init__.py +0 -0
- {mdb_engine-0.2.3 → mdb_engine-0.3.0}/mdb_engine/observability/README.md +0 -0
- {mdb_engine-0.2.3 → mdb_engine-0.3.0}/mdb_engine/observability/__init__.py +0 -0
- {mdb_engine-0.2.3 → mdb_engine-0.3.0}/mdb_engine/observability/health.py +0 -0
- {mdb_engine-0.2.3 → mdb_engine-0.3.0}/mdb_engine/observability/logging.py +0 -0
- {mdb_engine-0.2.3 → mdb_engine-0.3.0}/mdb_engine/observability/metrics.py +0 -0
- {mdb_engine-0.2.3 → mdb_engine-0.3.0}/mdb_engine/repositories/__init__.py +0 -0
- {mdb_engine-0.2.3 → mdb_engine-0.3.0}/mdb_engine/repositories/base.py +0 -0
- {mdb_engine-0.2.3 → mdb_engine-0.3.0}/mdb_engine/repositories/mongo.py +0 -0
- {mdb_engine-0.2.3 → mdb_engine-0.3.0}/mdb_engine/repositories/unit_of_work.py +0 -0
- {mdb_engine-0.2.3 → mdb_engine-0.3.0}/mdb_engine/routing/README.md +0 -0
- {mdb_engine-0.2.3 → mdb_engine-0.3.0}/mdb_engine/routing/__init__.py +0 -0
- {mdb_engine-0.2.3 → mdb_engine-0.3.0}/mdb_engine/routing/websockets.py +0 -0
- {mdb_engine-0.2.3 → mdb_engine-0.3.0}/mdb_engine.egg-info/dependency_links.txt +0 -0
- {mdb_engine-0.2.3 → mdb_engine-0.3.0}/mdb_engine.egg-info/entry_points.txt +0 -0
- {mdb_engine-0.2.3 → mdb_engine-0.3.0}/mdb_engine.egg-info/requires.txt +0 -0
- {mdb_engine-0.2.3 → mdb_engine-0.3.0}/mdb_engine.egg-info/top_level.txt +0 -0
- {mdb_engine-0.2.3 → mdb_engine-0.3.0}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: mdb-engine
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.3.0
|
|
4
4
|
Summary: MongoDB Engine
|
|
5
5
|
Home-page: https://github.com/ranfysvalle02/mdb-engine
|
|
6
6
|
Author: Fabian Valle
|
|
@@ -73,6 +73,31 @@ Dynamic: requires-python
|
|
|
73
73
|
|
|
74
74
|
---
|
|
75
75
|
|
|
76
|
+
## 🎯 manifest.json: The Key to Everything
|
|
77
|
+
|
|
78
|
+
**`manifest.json` is the foundation of your application.** It's a single configuration file that defines your app's identity, data structure, authentication, indexes, and services. Everything flows from this file.
|
|
79
|
+
|
|
80
|
+
### Your First manifest.json
|
|
81
|
+
|
|
82
|
+
Create a `manifest.json` file with just 3 fields:
|
|
83
|
+
|
|
84
|
+
```json
|
|
85
|
+
{
|
|
86
|
+
"schema_version": "2.0",
|
|
87
|
+
"slug": "my_app",
|
|
88
|
+
"name": "My App"
|
|
89
|
+
}
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
That's it! This minimal manifest gives you:
|
|
93
|
+
- ✅ Automatic data scoping (all queries filtered by `app_id`)
|
|
94
|
+
- ✅ Collection name prefixing (`db.tasks` → `my_app_tasks`)
|
|
95
|
+
- ✅ App registration and lifecycle management
|
|
96
|
+
|
|
97
|
+
**Learn more**: [Quick Start Guide](docs/QUICK_START.md) | [Manifest Deep Dive](docs/MANIFEST_DEEP_DIVE.md)
|
|
98
|
+
|
|
99
|
+
---
|
|
100
|
+
|
|
76
101
|
## Installation
|
|
77
102
|
|
|
78
103
|
```bash
|
|
@@ -81,31 +106,162 @@ pip install mdb-engine
|
|
|
81
106
|
|
|
82
107
|
---
|
|
83
108
|
|
|
84
|
-
## 30-Second Quick Start
|
|
109
|
+
## 30-Second Quick Start: Build a Todo List API
|
|
110
|
+
|
|
111
|
+
Let's build a complete CRUD todo list app in 3 steps!
|
|
112
|
+
|
|
113
|
+
### Step 1: Create `manifest.json`
|
|
114
|
+
|
|
115
|
+
```json
|
|
116
|
+
{
|
|
117
|
+
"schema_version": "2.0",
|
|
118
|
+
"slug": "todo_app",
|
|
119
|
+
"name": "Todo List App",
|
|
120
|
+
"managed_indexes": {
|
|
121
|
+
"todos": [
|
|
122
|
+
{
|
|
123
|
+
"type": "regular",
|
|
124
|
+
"keys": {"completed": 1, "created_at": -1},
|
|
125
|
+
"name": "completed_sort"
|
|
126
|
+
}
|
|
127
|
+
]
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
### Step 2: Create `app.py` with Full CRUD
|
|
85
133
|
|
|
86
134
|
```python
|
|
135
|
+
from datetime import datetime
|
|
87
136
|
from pathlib import Path
|
|
88
|
-
from
|
|
137
|
+
from typing import Optional
|
|
138
|
+
|
|
139
|
+
from bson import ObjectId
|
|
140
|
+
from fastapi import Depends, HTTPException
|
|
141
|
+
from pydantic import BaseModel
|
|
142
|
+
|
|
89
143
|
from mdb_engine import MongoDBEngine
|
|
90
144
|
from mdb_engine.dependencies import get_scoped_db
|
|
91
145
|
|
|
92
|
-
#
|
|
146
|
+
# Initialize engine
|
|
93
147
|
engine = MongoDBEngine(
|
|
94
148
|
mongo_uri="mongodb://localhost:27017",
|
|
95
149
|
db_name="my_database"
|
|
96
150
|
)
|
|
97
151
|
|
|
98
|
-
#
|
|
99
|
-
app = engine.create_app(
|
|
152
|
+
# Create app - manifest.json loaded automatically!
|
|
153
|
+
app = engine.create_app(
|
|
154
|
+
slug="todo_app",
|
|
155
|
+
manifest=Path("manifest.json")
|
|
156
|
+
)
|
|
100
157
|
|
|
101
|
-
#
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
158
|
+
# Pydantic models
|
|
159
|
+
class TodoCreate(BaseModel):
|
|
160
|
+
title: str
|
|
161
|
+
description: Optional[str] = None
|
|
162
|
+
|
|
163
|
+
class TodoUpdate(BaseModel):
|
|
164
|
+
title: Optional[str] = None
|
|
165
|
+
description: Optional[str] = None
|
|
166
|
+
completed: Optional[bool] = None
|
|
167
|
+
|
|
168
|
+
# CREATE - Add a new todo
|
|
169
|
+
@app.post("/todos")
|
|
170
|
+
async def create_todo(todo: TodoCreate, db=Depends(get_scoped_db)):
|
|
171
|
+
doc = {
|
|
172
|
+
**todo.dict(),
|
|
173
|
+
"completed": False,
|
|
174
|
+
"created_at": datetime.utcnow()
|
|
175
|
+
}
|
|
176
|
+
result = await db.todos.insert_one(doc)
|
|
177
|
+
return {"id": str(result.inserted_id), "message": "Todo created"}
|
|
178
|
+
|
|
179
|
+
# READ - List all todos
|
|
180
|
+
@app.get("/todos")
|
|
181
|
+
async def list_todos(completed: Optional[bool] = None, db=Depends(get_scoped_db)):
|
|
182
|
+
query = {}
|
|
183
|
+
if completed is not None:
|
|
184
|
+
query["completed"] = completed
|
|
185
|
+
|
|
186
|
+
todos = await db.todos.find(query).sort("created_at", -1).to_list(length=100)
|
|
187
|
+
for todo in todos:
|
|
188
|
+
todo["_id"] = str(todo["_id"])
|
|
189
|
+
return {"todos": todos, "count": len(todos)}
|
|
190
|
+
|
|
191
|
+
# READ - Get single todo
|
|
192
|
+
@app.get("/todos/{todo_id}")
|
|
193
|
+
async def get_todo(todo_id: str, db=Depends(get_scoped_db)):
|
|
194
|
+
todo = await db.todos.find_one({"_id": ObjectId(todo_id)})
|
|
195
|
+
if not todo:
|
|
196
|
+
raise HTTPException(status_code=404, detail="Todo not found")
|
|
197
|
+
todo["_id"] = str(todo["_id"])
|
|
198
|
+
return todo
|
|
199
|
+
|
|
200
|
+
# UPDATE - Update a todo
|
|
201
|
+
@app.put("/todos/{todo_id}")
|
|
202
|
+
async def update_todo(todo_id: str, todo: TodoUpdate, db=Depends(get_scoped_db)):
|
|
203
|
+
updates = {k: v for k, v in todo.dict(exclude_unset=True).items() if v is not None}
|
|
204
|
+
if not updates:
|
|
205
|
+
raise HTTPException(status_code=400, detail="No fields to update")
|
|
206
|
+
|
|
207
|
+
updates["updated_at"] = datetime.utcnow()
|
|
208
|
+
result = await db.todos.update_one(
|
|
209
|
+
{"_id": ObjectId(todo_id)},
|
|
210
|
+
{"$set": updates}
|
|
211
|
+
)
|
|
212
|
+
|
|
213
|
+
if result.matched_count == 0:
|
|
214
|
+
raise HTTPException(status_code=404, detail="Todo not found")
|
|
215
|
+
return {"message": "Todo updated"}
|
|
216
|
+
|
|
217
|
+
# DELETE - Delete a todo
|
|
218
|
+
@app.delete("/todos/{todo_id}")
|
|
219
|
+
async def delete_todo(todo_id: str, db=Depends(get_scoped_db)):
|
|
220
|
+
result = await db.todos.delete_one({"_id": ObjectId(todo_id)})
|
|
221
|
+
if result.deleted_count == 0:
|
|
222
|
+
raise HTTPException(status_code=404, detail="Todo not found")
|
|
223
|
+
return {"message": "Todo deleted"}
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
### Step 3: Run It!
|
|
227
|
+
|
|
228
|
+
```bash
|
|
229
|
+
# Start MongoDB (if not running)
|
|
230
|
+
mongod
|
|
231
|
+
|
|
232
|
+
# Install dependencies
|
|
233
|
+
pip install mdb-engine fastapi uvicorn
|
|
234
|
+
|
|
235
|
+
# Run the app
|
|
236
|
+
uvicorn app:app --reload
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
**Test your API:**
|
|
240
|
+
```bash
|
|
241
|
+
# Create a todo
|
|
242
|
+
curl -X POST http://localhost:8000/todos \
|
|
243
|
+
-H "Content-Type: application/json" \
|
|
244
|
+
-d '{"title": "Buy groceries", "description": "Milk and eggs"}'
|
|
245
|
+
|
|
246
|
+
# List todos
|
|
247
|
+
curl http://localhost:8000/todos
|
|
248
|
+
|
|
249
|
+
# Update a todo (replace {id} with actual ID)
|
|
250
|
+
curl -X PUT http://localhost:8000/todos/{id} \
|
|
251
|
+
-H "Content-Type: application/json" \
|
|
252
|
+
-d '{"completed": true}'
|
|
253
|
+
|
|
254
|
+
# Delete a todo
|
|
255
|
+
curl -X DELETE http://localhost:8000/todos/{id}
|
|
106
256
|
```
|
|
107
257
|
|
|
108
|
-
|
|
258
|
+
**What just happened?**
|
|
259
|
+
- ✅ **Automatic scoping**: All queries filtered by `app_id` — your data is isolated
|
|
260
|
+
- ✅ **Indexes created**: The `completed_sort` index was created automatically
|
|
261
|
+
- ✅ **Lifecycle managed**: Startup/shutdown handled automatically
|
|
262
|
+
- ✅ **Zero boilerplate**: No connection setup, no index scripts, no auth handlers
|
|
263
|
+
|
|
264
|
+
**That's it!** You now have a fully functional, production-ready todo API with automatic data sandboxing, index management, and lifecycle handling.
|
|
109
265
|
|
|
110
266
|
---
|
|
111
267
|
|
|
@@ -200,9 +356,11 @@ async def health():
|
|
|
200
356
|
|
|
201
357
|
## Why mdb-engine?
|
|
202
358
|
|
|
359
|
+
- **manifest.json is everything** — Single source of truth for your entire app configuration
|
|
203
360
|
- **Zero boilerplate** — No more connection setup, index creation scripts, or auth handlers
|
|
204
361
|
- **Data isolation** — Multi-tenant ready with automatic app sandboxing
|
|
205
362
|
- **Manifest-driven** — Define your app's "DNA" in JSON, not scattered code
|
|
363
|
+
- **Incremental adoption** — Start minimal, add features as needed
|
|
206
364
|
- **No lock-in** — Standard Motor/PyMongo underneath; export anytime with `mongodump --query='{"app_id":"my_app"}'`
|
|
207
365
|
|
|
208
366
|
---
|
|
@@ -300,13 +458,34 @@ async def get_items():
|
|
|
300
458
|
|
|
301
459
|
---
|
|
302
460
|
|
|
461
|
+
## Understanding manifest.json
|
|
462
|
+
|
|
463
|
+
Your `manifest.json` is the heart of your application. It defines:
|
|
464
|
+
|
|
465
|
+
- **App Identity**: `slug`, `name`, `description`
|
|
466
|
+
- **Data Access**: `data_access.read_scopes`, `data_access.write_scope`
|
|
467
|
+
- **Indexes**: `managed_indexes` (regular, vector, text, TTL, compound)
|
|
468
|
+
- **Authentication**: `auth.policy`, `auth.users` (Casbin/OSO, demo users)
|
|
469
|
+
- **AI Services**: `embedding_config`, `memory_config`
|
|
470
|
+
- **Real-time**: `websockets` endpoints
|
|
471
|
+
- **CORS**: `cors` settings
|
|
472
|
+
|
|
473
|
+
**Start minimal, grow as needed.** You can begin with just `slug`, `name`, and `schema_version`, then add features incrementally.
|
|
474
|
+
|
|
475
|
+
**📖 Learn More:**
|
|
476
|
+
- [Quick Start Guide](docs/QUICK_START.md) - Get started with manifest.json
|
|
477
|
+
- [Manifest Deep Dive](docs/MANIFEST_DEEP_DIVE.md) - Comprehensive manifest.json guide
|
|
478
|
+
- [Examples](examples/) - Real-world manifest.json files
|
|
479
|
+
|
|
480
|
+
---
|
|
481
|
+
|
|
303
482
|
## Links
|
|
304
483
|
|
|
305
484
|
- [GitHub Repository](https://github.com/ranfysvalle02/mdb-engine)
|
|
306
485
|
- [Documentation](https://github.com/ranfysvalle02/mdb-engine/tree/main/docs)
|
|
307
486
|
- [All Examples](https://github.com/ranfysvalle02/mdb-engine/tree/main/examples)
|
|
308
|
-
- [Quick Start Guide](
|
|
309
|
-
- [Contributing](
|
|
487
|
+
- [Quick Start Guide](docs/QUICK_START.md) - **Start here!**
|
|
488
|
+
- [Contributing](CONTRIBUTING.md)
|
|
310
489
|
|
|
311
490
|
---
|
|
312
491
|
|
|
@@ -8,6 +8,31 @@
|
|
|
8
8
|
|
|
9
9
|
---
|
|
10
10
|
|
|
11
|
+
## 🎯 manifest.json: The Key to Everything
|
|
12
|
+
|
|
13
|
+
**`manifest.json` is the foundation of your application.** It's a single configuration file that defines your app's identity, data structure, authentication, indexes, and services. Everything flows from this file.
|
|
14
|
+
|
|
15
|
+
### Your First manifest.json
|
|
16
|
+
|
|
17
|
+
Create a `manifest.json` file with just 3 fields:
|
|
18
|
+
|
|
19
|
+
```json
|
|
20
|
+
{
|
|
21
|
+
"schema_version": "2.0",
|
|
22
|
+
"slug": "my_app",
|
|
23
|
+
"name": "My App"
|
|
24
|
+
}
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
That's it! This minimal manifest gives you:
|
|
28
|
+
- ✅ Automatic data scoping (all queries filtered by `app_id`)
|
|
29
|
+
- ✅ Collection name prefixing (`db.tasks` → `my_app_tasks`)
|
|
30
|
+
- ✅ App registration and lifecycle management
|
|
31
|
+
|
|
32
|
+
**Learn more**: [Quick Start Guide](docs/QUICK_START.md) | [Manifest Deep Dive](docs/MANIFEST_DEEP_DIVE.md)
|
|
33
|
+
|
|
34
|
+
---
|
|
35
|
+
|
|
11
36
|
## Installation
|
|
12
37
|
|
|
13
38
|
```bash
|
|
@@ -16,31 +41,162 @@ pip install mdb-engine
|
|
|
16
41
|
|
|
17
42
|
---
|
|
18
43
|
|
|
19
|
-
## 30-Second Quick Start
|
|
44
|
+
## 30-Second Quick Start: Build a Todo List API
|
|
45
|
+
|
|
46
|
+
Let's build a complete CRUD todo list app in 3 steps!
|
|
47
|
+
|
|
48
|
+
### Step 1: Create `manifest.json`
|
|
49
|
+
|
|
50
|
+
```json
|
|
51
|
+
{
|
|
52
|
+
"schema_version": "2.0",
|
|
53
|
+
"slug": "todo_app",
|
|
54
|
+
"name": "Todo List App",
|
|
55
|
+
"managed_indexes": {
|
|
56
|
+
"todos": [
|
|
57
|
+
{
|
|
58
|
+
"type": "regular",
|
|
59
|
+
"keys": {"completed": 1, "created_at": -1},
|
|
60
|
+
"name": "completed_sort"
|
|
61
|
+
}
|
|
62
|
+
]
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
### Step 2: Create `app.py` with Full CRUD
|
|
20
68
|
|
|
21
69
|
```python
|
|
70
|
+
from datetime import datetime
|
|
22
71
|
from pathlib import Path
|
|
23
|
-
from
|
|
72
|
+
from typing import Optional
|
|
73
|
+
|
|
74
|
+
from bson import ObjectId
|
|
75
|
+
from fastapi import Depends, HTTPException
|
|
76
|
+
from pydantic import BaseModel
|
|
77
|
+
|
|
24
78
|
from mdb_engine import MongoDBEngine
|
|
25
79
|
from mdb_engine.dependencies import get_scoped_db
|
|
26
80
|
|
|
27
|
-
#
|
|
81
|
+
# Initialize engine
|
|
28
82
|
engine = MongoDBEngine(
|
|
29
83
|
mongo_uri="mongodb://localhost:27017",
|
|
30
84
|
db_name="my_database"
|
|
31
85
|
)
|
|
32
86
|
|
|
33
|
-
#
|
|
34
|
-
app = engine.create_app(
|
|
87
|
+
# Create app - manifest.json loaded automatically!
|
|
88
|
+
app = engine.create_app(
|
|
89
|
+
slug="todo_app",
|
|
90
|
+
manifest=Path("manifest.json")
|
|
91
|
+
)
|
|
35
92
|
|
|
36
|
-
#
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
93
|
+
# Pydantic models
|
|
94
|
+
class TodoCreate(BaseModel):
|
|
95
|
+
title: str
|
|
96
|
+
description: Optional[str] = None
|
|
97
|
+
|
|
98
|
+
class TodoUpdate(BaseModel):
|
|
99
|
+
title: Optional[str] = None
|
|
100
|
+
description: Optional[str] = None
|
|
101
|
+
completed: Optional[bool] = None
|
|
102
|
+
|
|
103
|
+
# CREATE - Add a new todo
|
|
104
|
+
@app.post("/todos")
|
|
105
|
+
async def create_todo(todo: TodoCreate, db=Depends(get_scoped_db)):
|
|
106
|
+
doc = {
|
|
107
|
+
**todo.dict(),
|
|
108
|
+
"completed": False,
|
|
109
|
+
"created_at": datetime.utcnow()
|
|
110
|
+
}
|
|
111
|
+
result = await db.todos.insert_one(doc)
|
|
112
|
+
return {"id": str(result.inserted_id), "message": "Todo created"}
|
|
113
|
+
|
|
114
|
+
# READ - List all todos
|
|
115
|
+
@app.get("/todos")
|
|
116
|
+
async def list_todos(completed: Optional[bool] = None, db=Depends(get_scoped_db)):
|
|
117
|
+
query = {}
|
|
118
|
+
if completed is not None:
|
|
119
|
+
query["completed"] = completed
|
|
120
|
+
|
|
121
|
+
todos = await db.todos.find(query).sort("created_at", -1).to_list(length=100)
|
|
122
|
+
for todo in todos:
|
|
123
|
+
todo["_id"] = str(todo["_id"])
|
|
124
|
+
return {"todos": todos, "count": len(todos)}
|
|
125
|
+
|
|
126
|
+
# READ - Get single todo
|
|
127
|
+
@app.get("/todos/{todo_id}")
|
|
128
|
+
async def get_todo(todo_id: str, db=Depends(get_scoped_db)):
|
|
129
|
+
todo = await db.todos.find_one({"_id": ObjectId(todo_id)})
|
|
130
|
+
if not todo:
|
|
131
|
+
raise HTTPException(status_code=404, detail="Todo not found")
|
|
132
|
+
todo["_id"] = str(todo["_id"])
|
|
133
|
+
return todo
|
|
134
|
+
|
|
135
|
+
# UPDATE - Update a todo
|
|
136
|
+
@app.put("/todos/{todo_id}")
|
|
137
|
+
async def update_todo(todo_id: str, todo: TodoUpdate, db=Depends(get_scoped_db)):
|
|
138
|
+
updates = {k: v for k, v in todo.dict(exclude_unset=True).items() if v is not None}
|
|
139
|
+
if not updates:
|
|
140
|
+
raise HTTPException(status_code=400, detail="No fields to update")
|
|
141
|
+
|
|
142
|
+
updates["updated_at"] = datetime.utcnow()
|
|
143
|
+
result = await db.todos.update_one(
|
|
144
|
+
{"_id": ObjectId(todo_id)},
|
|
145
|
+
{"$set": updates}
|
|
146
|
+
)
|
|
147
|
+
|
|
148
|
+
if result.matched_count == 0:
|
|
149
|
+
raise HTTPException(status_code=404, detail="Todo not found")
|
|
150
|
+
return {"message": "Todo updated"}
|
|
151
|
+
|
|
152
|
+
# DELETE - Delete a todo
|
|
153
|
+
@app.delete("/todos/{todo_id}")
|
|
154
|
+
async def delete_todo(todo_id: str, db=Depends(get_scoped_db)):
|
|
155
|
+
result = await db.todos.delete_one({"_id": ObjectId(todo_id)})
|
|
156
|
+
if result.deleted_count == 0:
|
|
157
|
+
raise HTTPException(status_code=404, detail="Todo not found")
|
|
158
|
+
return {"message": "Todo deleted"}
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
### Step 3: Run It!
|
|
162
|
+
|
|
163
|
+
```bash
|
|
164
|
+
# Start MongoDB (if not running)
|
|
165
|
+
mongod
|
|
166
|
+
|
|
167
|
+
# Install dependencies
|
|
168
|
+
pip install mdb-engine fastapi uvicorn
|
|
169
|
+
|
|
170
|
+
# Run the app
|
|
171
|
+
uvicorn app:app --reload
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
**Test your API:**
|
|
175
|
+
```bash
|
|
176
|
+
# Create a todo
|
|
177
|
+
curl -X POST http://localhost:8000/todos \
|
|
178
|
+
-H "Content-Type: application/json" \
|
|
179
|
+
-d '{"title": "Buy groceries", "description": "Milk and eggs"}'
|
|
180
|
+
|
|
181
|
+
# List todos
|
|
182
|
+
curl http://localhost:8000/todos
|
|
183
|
+
|
|
184
|
+
# Update a todo (replace {id} with actual ID)
|
|
185
|
+
curl -X PUT http://localhost:8000/todos/{id} \
|
|
186
|
+
-H "Content-Type: application/json" \
|
|
187
|
+
-d '{"completed": true}'
|
|
188
|
+
|
|
189
|
+
# Delete a todo
|
|
190
|
+
curl -X DELETE http://localhost:8000/todos/{id}
|
|
41
191
|
```
|
|
42
192
|
|
|
43
|
-
|
|
193
|
+
**What just happened?**
|
|
194
|
+
- ✅ **Automatic scoping**: All queries filtered by `app_id` — your data is isolated
|
|
195
|
+
- ✅ **Indexes created**: The `completed_sort` index was created automatically
|
|
196
|
+
- ✅ **Lifecycle managed**: Startup/shutdown handled automatically
|
|
197
|
+
- ✅ **Zero boilerplate**: No connection setup, no index scripts, no auth handlers
|
|
198
|
+
|
|
199
|
+
**That's it!** You now have a fully functional, production-ready todo API with automatic data sandboxing, index management, and lifecycle handling.
|
|
44
200
|
|
|
45
201
|
---
|
|
46
202
|
|
|
@@ -135,9 +291,11 @@ async def health():
|
|
|
135
291
|
|
|
136
292
|
## Why mdb-engine?
|
|
137
293
|
|
|
294
|
+
- **manifest.json is everything** — Single source of truth for your entire app configuration
|
|
138
295
|
- **Zero boilerplate** — No more connection setup, index creation scripts, or auth handlers
|
|
139
296
|
- **Data isolation** — Multi-tenant ready with automatic app sandboxing
|
|
140
297
|
- **Manifest-driven** — Define your app's "DNA" in JSON, not scattered code
|
|
298
|
+
- **Incremental adoption** — Start minimal, add features as needed
|
|
141
299
|
- **No lock-in** — Standard Motor/PyMongo underneath; export anytime with `mongodump --query='{"app_id":"my_app"}'`
|
|
142
300
|
|
|
143
301
|
---
|
|
@@ -235,13 +393,34 @@ async def get_items():
|
|
|
235
393
|
|
|
236
394
|
---
|
|
237
395
|
|
|
396
|
+
## Understanding manifest.json
|
|
397
|
+
|
|
398
|
+
Your `manifest.json` is the heart of your application. It defines:
|
|
399
|
+
|
|
400
|
+
- **App Identity**: `slug`, `name`, `description`
|
|
401
|
+
- **Data Access**: `data_access.read_scopes`, `data_access.write_scope`
|
|
402
|
+
- **Indexes**: `managed_indexes` (regular, vector, text, TTL, compound)
|
|
403
|
+
- **Authentication**: `auth.policy`, `auth.users` (Casbin/OSO, demo users)
|
|
404
|
+
- **AI Services**: `embedding_config`, `memory_config`
|
|
405
|
+
- **Real-time**: `websockets` endpoints
|
|
406
|
+
- **CORS**: `cors` settings
|
|
407
|
+
|
|
408
|
+
**Start minimal, grow as needed.** You can begin with just `slug`, `name`, and `schema_version`, then add features incrementally.
|
|
409
|
+
|
|
410
|
+
**📖 Learn More:**
|
|
411
|
+
- [Quick Start Guide](docs/QUICK_START.md) - Get started with manifest.json
|
|
412
|
+
- [Manifest Deep Dive](docs/MANIFEST_DEEP_DIVE.md) - Comprehensive manifest.json guide
|
|
413
|
+
- [Examples](examples/) - Real-world manifest.json files
|
|
414
|
+
|
|
415
|
+
---
|
|
416
|
+
|
|
238
417
|
## Links
|
|
239
418
|
|
|
240
419
|
- [GitHub Repository](https://github.com/ranfysvalle02/mdb-engine)
|
|
241
420
|
- [Documentation](https://github.com/ranfysvalle02/mdb-engine/tree/main/docs)
|
|
242
421
|
- [All Examples](https://github.com/ranfysvalle02/mdb-engine/tree/main/examples)
|
|
243
|
-
- [Quick Start Guide](
|
|
244
|
-
- [Contributing](
|
|
422
|
+
- [Quick Start Guide](docs/QUICK_START.md) - **Start here!**
|
|
423
|
+
- [Contributing](CONTRIBUTING.md)
|
|
245
424
|
|
|
246
425
|
---
|
|
247
426
|
|
|
@@ -78,7 +78,11 @@ from .indexes import (
|
|
|
78
78
|
# Repository pattern
|
|
79
79
|
from .repositories import Entity, MongoRepository, Repository, UnitOfWork
|
|
80
80
|
|
|
81
|
-
|
|
81
|
+
# Utilities
|
|
82
|
+
from .utils import clean_mongo_doc, clean_mongo_docs
|
|
83
|
+
|
|
84
|
+
__version__ = "0.3.0" # Minor version bump: Multi-app mounting, SSO improvements,
|
|
85
|
+
# and exception handling fixes
|
|
82
86
|
|
|
83
87
|
__all__ = [
|
|
84
88
|
# Core Engine
|
|
@@ -127,4 +131,7 @@ __all__ = [
|
|
|
127
131
|
"AsyncAtlasIndexManager",
|
|
128
132
|
"AutoIndexManager",
|
|
129
133
|
"run_index_creation_for_collection",
|
|
134
|
+
# Utilities
|
|
135
|
+
"clean_mongo_doc",
|
|
136
|
+
"clean_mongo_docs",
|
|
130
137
|
]
|
|
@@ -42,6 +42,10 @@ All apps share a central user pool. Users authenticate once and can access any a
|
|
|
42
42
|
{
|
|
43
43
|
"auth": {
|
|
44
44
|
"mode": "shared",
|
|
45
|
+
"auth_hub_url": "http://localhost:8000",
|
|
46
|
+
"related_apps": {
|
|
47
|
+
"dashboard": "http://localhost:8001"
|
|
48
|
+
},
|
|
45
49
|
"roles": ["viewer", "editor", "admin"],
|
|
46
50
|
"default_role": "viewer",
|
|
47
51
|
"require_role": "viewer",
|
|
@@ -60,6 +64,8 @@ All apps share a central user pool. Users authenticate once and can access any a
|
|
|
60
64
|
| Field | Description |
|
|
61
65
|
|-------|-------------|
|
|
62
66
|
| `roles` | Available roles for this app |
|
|
67
|
+
| `auth_hub_url` | URL of the authentication hub for SSO apps. Used for redirecting unauthenticated users to login. Can be overridden via `AUTH_HUB_URL` environment variable |
|
|
68
|
+
| `related_apps` | Map of related app slugs to their URLs for cross-app navigation. Keys are app slugs, values are URLs. Can be overridden via `{APP_SLUG_UPPER}_URL` environment variables |
|
|
63
69
|
| `default_role` | Role assigned to new users |
|
|
64
70
|
| `require_role` | Minimum role required to access app |
|
|
65
71
|
| `public_routes` | Routes that don't require authentication |
|