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.
Files changed (105) hide show
  1. {mdb_engine-0.2.3/mdb_engine.egg-info → mdb_engine-0.3.0}/PKG-INFO +193 -14
  2. {mdb_engine-0.2.3 → mdb_engine-0.3.0}/README.md +192 -13
  3. {mdb_engine-0.2.3 → mdb_engine-0.3.0}/mdb_engine/__init__.py +8 -1
  4. {mdb_engine-0.2.3 → mdb_engine-0.3.0}/mdb_engine/auth/README.md +6 -0
  5. {mdb_engine-0.2.3 → mdb_engine-0.3.0}/mdb_engine/auth/shared_middleware.py +330 -119
  6. {mdb_engine-0.2.3 → mdb_engine-0.3.0}/mdb_engine/core/engine.py +417 -5
  7. {mdb_engine-0.2.3 → mdb_engine-0.3.0}/mdb_engine/core/manifest.py +114 -0
  8. {mdb_engine-0.2.3 → mdb_engine-0.3.0}/mdb_engine/embeddings/service.py +37 -8
  9. {mdb_engine-0.2.3 → mdb_engine-0.3.0}/mdb_engine/memory/README.md +93 -2
  10. mdb_engine-0.3.0/mdb_engine/memory/service.py +480 -0
  11. {mdb_engine-0.2.3 → mdb_engine-0.3.0}/mdb_engine/utils/__init__.py +3 -1
  12. mdb_engine-0.3.0/mdb_engine/utils/mongo.py +117 -0
  13. {mdb_engine-0.2.3 → mdb_engine-0.3.0/mdb_engine.egg-info}/PKG-INFO +193 -14
  14. {mdb_engine-0.2.3 → mdb_engine-0.3.0}/mdb_engine.egg-info/SOURCES.txt +2 -1
  15. {mdb_engine-0.2.3 → mdb_engine-0.3.0}/pyproject.toml +1 -1
  16. {mdb_engine-0.2.3 → mdb_engine-0.3.0}/setup.py +1 -1
  17. mdb_engine-0.2.3/mdb_engine/memory/service.py +0 -1228
  18. {mdb_engine-0.2.3 → mdb_engine-0.3.0}/LICENSE +0 -0
  19. {mdb_engine-0.2.3 → mdb_engine-0.3.0}/MANIFEST.in +0 -0
  20. {mdb_engine-0.2.3 → mdb_engine-0.3.0}/mdb_engine/README.md +0 -0
  21. {mdb_engine-0.2.3 → mdb_engine-0.3.0}/mdb_engine/auth/ARCHITECTURE.md +0 -0
  22. {mdb_engine-0.2.3 → mdb_engine-0.3.0}/mdb_engine/auth/__init__.py +0 -0
  23. {mdb_engine-0.2.3 → mdb_engine-0.3.0}/mdb_engine/auth/audit.py +0 -0
  24. {mdb_engine-0.2.3 → mdb_engine-0.3.0}/mdb_engine/auth/base.py +0 -0
  25. {mdb_engine-0.2.3 → mdb_engine-0.3.0}/mdb_engine/auth/casbin_factory.py +0 -0
  26. {mdb_engine-0.2.3 → mdb_engine-0.3.0}/mdb_engine/auth/casbin_models.py +0 -0
  27. {mdb_engine-0.2.3 → mdb_engine-0.3.0}/mdb_engine/auth/config_defaults.py +0 -0
  28. {mdb_engine-0.2.3 → mdb_engine-0.3.0}/mdb_engine/auth/config_helpers.py +0 -0
  29. {mdb_engine-0.2.3 → mdb_engine-0.3.0}/mdb_engine/auth/cookie_utils.py +0 -0
  30. {mdb_engine-0.2.3 → mdb_engine-0.3.0}/mdb_engine/auth/csrf.py +0 -0
  31. {mdb_engine-0.2.3 → mdb_engine-0.3.0}/mdb_engine/auth/decorators.py +0 -0
  32. {mdb_engine-0.2.3 → mdb_engine-0.3.0}/mdb_engine/auth/dependencies.py +0 -0
  33. {mdb_engine-0.2.3 → mdb_engine-0.3.0}/mdb_engine/auth/helpers.py +0 -0
  34. {mdb_engine-0.2.3 → mdb_engine-0.3.0}/mdb_engine/auth/integration.py +0 -0
  35. {mdb_engine-0.2.3 → mdb_engine-0.3.0}/mdb_engine/auth/jwt.py +0 -0
  36. {mdb_engine-0.2.3 → mdb_engine-0.3.0}/mdb_engine/auth/middleware.py +0 -0
  37. {mdb_engine-0.2.3 → mdb_engine-0.3.0}/mdb_engine/auth/oso_factory.py +0 -0
  38. {mdb_engine-0.2.3 → mdb_engine-0.3.0}/mdb_engine/auth/provider.py +0 -0
  39. {mdb_engine-0.2.3 → mdb_engine-0.3.0}/mdb_engine/auth/rate_limiter.py +0 -0
  40. {mdb_engine-0.2.3 → mdb_engine-0.3.0}/mdb_engine/auth/restrictions.py +0 -0
  41. {mdb_engine-0.2.3 → mdb_engine-0.3.0}/mdb_engine/auth/session_manager.py +0 -0
  42. {mdb_engine-0.2.3 → mdb_engine-0.3.0}/mdb_engine/auth/shared_users.py +0 -0
  43. {mdb_engine-0.2.3 → mdb_engine-0.3.0}/mdb_engine/auth/token_lifecycle.py +0 -0
  44. {mdb_engine-0.2.3 → mdb_engine-0.3.0}/mdb_engine/auth/token_store.py +0 -0
  45. {mdb_engine-0.2.3 → mdb_engine-0.3.0}/mdb_engine/auth/users.py +0 -0
  46. {mdb_engine-0.2.3 → mdb_engine-0.3.0}/mdb_engine/auth/utils.py +0 -0
  47. {mdb_engine-0.2.3 → mdb_engine-0.3.0}/mdb_engine/cli/__init__.py +0 -0
  48. {mdb_engine-0.2.3 → mdb_engine-0.3.0}/mdb_engine/cli/commands/__init__.py +0 -0
  49. {mdb_engine-0.2.3 → mdb_engine-0.3.0}/mdb_engine/cli/commands/generate.py +0 -0
  50. {mdb_engine-0.2.3 → mdb_engine-0.3.0}/mdb_engine/cli/commands/migrate.py +0 -0
  51. {mdb_engine-0.2.3 → mdb_engine-0.3.0}/mdb_engine/cli/commands/show.py +0 -0
  52. {mdb_engine-0.2.3 → mdb_engine-0.3.0}/mdb_engine/cli/commands/validate.py +0 -0
  53. {mdb_engine-0.2.3 → mdb_engine-0.3.0}/mdb_engine/cli/main.py +0 -0
  54. {mdb_engine-0.2.3 → mdb_engine-0.3.0}/mdb_engine/cli/utils.py +0 -0
  55. {mdb_engine-0.2.3 → mdb_engine-0.3.0}/mdb_engine/config.py +0 -0
  56. {mdb_engine-0.2.3 → mdb_engine-0.3.0}/mdb_engine/constants.py +0 -0
  57. {mdb_engine-0.2.3 → mdb_engine-0.3.0}/mdb_engine/core/README.md +0 -0
  58. {mdb_engine-0.2.3 → mdb_engine-0.3.0}/mdb_engine/core/__init__.py +0 -0
  59. {mdb_engine-0.2.3 → mdb_engine-0.3.0}/mdb_engine/core/app_registration.py +0 -0
  60. {mdb_engine-0.2.3 → mdb_engine-0.3.0}/mdb_engine/core/app_secrets.py +0 -0
  61. {mdb_engine-0.2.3 → mdb_engine-0.3.0}/mdb_engine/core/connection.py +0 -0
  62. {mdb_engine-0.2.3 → mdb_engine-0.3.0}/mdb_engine/core/encryption.py +0 -0
  63. {mdb_engine-0.2.3 → mdb_engine-0.3.0}/mdb_engine/core/index_management.py +0 -0
  64. {mdb_engine-0.2.3 → mdb_engine-0.3.0}/mdb_engine/core/ray_integration.py +0 -0
  65. {mdb_engine-0.2.3 → mdb_engine-0.3.0}/mdb_engine/core/seeding.py +0 -0
  66. {mdb_engine-0.2.3 → mdb_engine-0.3.0}/mdb_engine/core/service_initialization.py +0 -0
  67. {mdb_engine-0.2.3 → mdb_engine-0.3.0}/mdb_engine/core/types.py +0 -0
  68. {mdb_engine-0.2.3 → mdb_engine-0.3.0}/mdb_engine/database/README.md +0 -0
  69. {mdb_engine-0.2.3 → mdb_engine-0.3.0}/mdb_engine/database/__init__.py +0 -0
  70. {mdb_engine-0.2.3 → mdb_engine-0.3.0}/mdb_engine/database/abstraction.py +0 -0
  71. {mdb_engine-0.2.3 → mdb_engine-0.3.0}/mdb_engine/database/connection.py +0 -0
  72. {mdb_engine-0.2.3 → mdb_engine-0.3.0}/mdb_engine/database/query_validator.py +0 -0
  73. {mdb_engine-0.2.3 → mdb_engine-0.3.0}/mdb_engine/database/resource_limiter.py +0 -0
  74. {mdb_engine-0.2.3 → mdb_engine-0.3.0}/mdb_engine/database/scoped_wrapper.py +0 -0
  75. {mdb_engine-0.2.3 → mdb_engine-0.3.0}/mdb_engine/dependencies.py +0 -0
  76. {mdb_engine-0.2.3 → mdb_engine-0.3.0}/mdb_engine/di/__init__.py +0 -0
  77. {mdb_engine-0.2.3 → mdb_engine-0.3.0}/mdb_engine/di/container.py +0 -0
  78. {mdb_engine-0.2.3 → mdb_engine-0.3.0}/mdb_engine/di/providers.py +0 -0
  79. {mdb_engine-0.2.3 → mdb_engine-0.3.0}/mdb_engine/di/scopes.py +0 -0
  80. {mdb_engine-0.2.3 → mdb_engine-0.3.0}/mdb_engine/embeddings/README.md +0 -0
  81. {mdb_engine-0.2.3 → mdb_engine-0.3.0}/mdb_engine/embeddings/__init__.py +0 -0
  82. {mdb_engine-0.2.3 → mdb_engine-0.3.0}/mdb_engine/embeddings/dependencies.py +0 -0
  83. {mdb_engine-0.2.3 → mdb_engine-0.3.0}/mdb_engine/exceptions.py +0 -0
  84. {mdb_engine-0.2.3 → mdb_engine-0.3.0}/mdb_engine/indexes/README.md +0 -0
  85. {mdb_engine-0.2.3 → mdb_engine-0.3.0}/mdb_engine/indexes/__init__.py +0 -0
  86. {mdb_engine-0.2.3 → mdb_engine-0.3.0}/mdb_engine/indexes/helpers.py +0 -0
  87. {mdb_engine-0.2.3 → mdb_engine-0.3.0}/mdb_engine/indexes/manager.py +0 -0
  88. {mdb_engine-0.2.3 → mdb_engine-0.3.0}/mdb_engine/memory/__init__.py +0 -0
  89. {mdb_engine-0.2.3 → mdb_engine-0.3.0}/mdb_engine/observability/README.md +0 -0
  90. {mdb_engine-0.2.3 → mdb_engine-0.3.0}/mdb_engine/observability/__init__.py +0 -0
  91. {mdb_engine-0.2.3 → mdb_engine-0.3.0}/mdb_engine/observability/health.py +0 -0
  92. {mdb_engine-0.2.3 → mdb_engine-0.3.0}/mdb_engine/observability/logging.py +0 -0
  93. {mdb_engine-0.2.3 → mdb_engine-0.3.0}/mdb_engine/observability/metrics.py +0 -0
  94. {mdb_engine-0.2.3 → mdb_engine-0.3.0}/mdb_engine/repositories/__init__.py +0 -0
  95. {mdb_engine-0.2.3 → mdb_engine-0.3.0}/mdb_engine/repositories/base.py +0 -0
  96. {mdb_engine-0.2.3 → mdb_engine-0.3.0}/mdb_engine/repositories/mongo.py +0 -0
  97. {mdb_engine-0.2.3 → mdb_engine-0.3.0}/mdb_engine/repositories/unit_of_work.py +0 -0
  98. {mdb_engine-0.2.3 → mdb_engine-0.3.0}/mdb_engine/routing/README.md +0 -0
  99. {mdb_engine-0.2.3 → mdb_engine-0.3.0}/mdb_engine/routing/__init__.py +0 -0
  100. {mdb_engine-0.2.3 → mdb_engine-0.3.0}/mdb_engine/routing/websockets.py +0 -0
  101. {mdb_engine-0.2.3 → mdb_engine-0.3.0}/mdb_engine.egg-info/dependency_links.txt +0 -0
  102. {mdb_engine-0.2.3 → mdb_engine-0.3.0}/mdb_engine.egg-info/entry_points.txt +0 -0
  103. {mdb_engine-0.2.3 → mdb_engine-0.3.0}/mdb_engine.egg-info/requires.txt +0 -0
  104. {mdb_engine-0.2.3 → mdb_engine-0.3.0}/mdb_engine.egg-info/top_level.txt +0 -0
  105. {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.2.3
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 fastapi import Depends
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
- # 1. Initialize the engine
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
- # 2. Create a FastAPI app with automatic lifecycle management
99
- app = engine.create_app(slug="my_app", manifest=Path("manifest.json"))
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
- # 3. Use request-scoped dependencies - all queries automatically isolated
102
- @app.post("/tasks")
103
- async def create_task(task: dict, db=Depends(get_scoped_db)):
104
- result = await db.tasks.insert_one(task)
105
- return {"id": str(result.inserted_id)}
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
- That's it. Your data is automatically sandboxed, indexes are created, and cleanup is handled.
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](https://github.com/ranfysvalle02/mdb-engine/blob/main/docs/QUICK_START.md)
309
- - [Contributing](https://github.com/ranfysvalle02/mdb-engine/blob/main/CONTRIBUTING.md)
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 fastapi import Depends
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
- # 1. Initialize the engine
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
- # 2. Create a FastAPI app with automatic lifecycle management
34
- app = engine.create_app(slug="my_app", manifest=Path("manifest.json"))
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
- # 3. Use request-scoped dependencies - all queries automatically isolated
37
- @app.post("/tasks")
38
- async def create_task(task: dict, db=Depends(get_scoped_db)):
39
- result = await db.tasks.insert_one(task)
40
- return {"id": str(result.inserted_id)}
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
- That's it. Your data is automatically sandboxed, indexes are created, and cleanup is handled.
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](https://github.com/ranfysvalle02/mdb-engine/blob/main/docs/QUICK_START.md)
244
- - [Contributing](https://github.com/ranfysvalle02/mdb-engine/blob/main/CONTRIBUTING.md)
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
- __version__ = "0.2.1" # Major version bump for new DI system
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 |