geek-cafe-saas-sdk 0.6.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.
Potentially problematic release.
This version of geek-cafe-saas-sdk might be problematic. Click here for more details.
- geek_cafe_saas_sdk-0.6.0/.env.mock +22 -0
- geek_cafe_saas_sdk-0.6.0/.gitignore +151 -0
- geek_cafe_saas_sdk-0.6.0/.windsurf/rules/cascade.yaml +9 -0
- geek_cafe_saas_sdk-0.6.0/ARCHITECTURE.md +278 -0
- geek_cafe_saas_sdk-0.6.0/CHANGELOG.md +467 -0
- geek_cafe_saas_sdk-0.6.0/CHANGELOG_0.4.1.md +145 -0
- geek_cafe_saas_sdk-0.6.0/LICENSE +47 -0
- geek_cafe_saas_sdk-0.6.0/PKG-INFO +397 -0
- geek_cafe_saas_sdk-0.6.0/README.md +322 -0
- geek_cafe_saas_sdk-0.6.0/README_FILE_SYSTEM_SDK_USAGE.md +442 -0
- geek_cafe_saas_sdk-0.6.0/coverage.json +1 -0
- geek_cafe_saas_sdk-0.6.0/examples/decorator_pattern_handlers.py +497 -0
- geek_cafe_saas_sdk-0.6.0/examples/factory_authorization_example.py +431 -0
- geek_cafe_saas_sdk-0.6.0/examples/hierarchical_routing_handler_example.py +434 -0
- geek_cafe_saas_sdk-0.6.0/examples/lambda_handler_examples.py +356 -0
- geek_cafe_saas_sdk-0.6.0/examples/lambda_handlers/api_key_example.py +144 -0
- geek_cafe_saas_sdk-0.6.0/examples/website_analytics_example.py +323 -0
- geek_cafe_saas_sdk-0.6.0/lambda_handlers/auth/confirm_forgot_password/app.py +145 -0
- geek_cafe_saas_sdk-0.6.0/lambda_handlers/auth/forgot_password/app.py +125 -0
- geek_cafe_saas_sdk-0.6.0/lambda_handlers/users/change_password/app.py +148 -0
- geek_cafe_saas_sdk-0.6.0/lambda_handlers/users/reset_password/app.py +135 -0
- geek_cafe_saas_sdk-0.6.0/publish_to_pypi.py +706 -0
- geek_cafe_saas_sdk-0.6.0/publish_to_pypi.sh +104 -0
- geek_cafe_saas_sdk-0.6.0/pyproject.toml +66 -0
- geek_cafe_saas_sdk-0.6.0/pysetup.py +2531 -0
- geek_cafe_saas_sdk-0.6.0/pysetup.sh +77 -0
- geek_cafe_saas_sdk-0.6.0/requirements.dev.txt +16 -0
- geek_cafe_saas_sdk-0.6.0/requirements.txt +3 -0
- geek_cafe_saas_sdk-0.6.0/run_unit_tests.sh +110 -0
- geek_cafe_saas_sdk-0.6.0/src/geek_cafe_saas_sdk/__init__.py +9 -0
- geek_cafe_saas_sdk-0.6.0/src/geek_cafe_saas_sdk/core/__init__.py +11 -0
- geek_cafe_saas_sdk-0.6.0/src/geek_cafe_saas_sdk/core/audit_mixin.py +33 -0
- geek_cafe_saas_sdk-0.6.0/src/geek_cafe_saas_sdk/core/error_codes.py +132 -0
- geek_cafe_saas_sdk-0.6.0/src/geek_cafe_saas_sdk/core/service_errors.py +19 -0
- geek_cafe_saas_sdk-0.6.0/src/geek_cafe_saas_sdk/core/service_result.py +121 -0
- geek_cafe_saas_sdk-0.6.0/src/geek_cafe_saas_sdk/decorators/__init__.py +64 -0
- geek_cafe_saas_sdk-0.6.0/src/geek_cafe_saas_sdk/decorators/auth.py +373 -0
- geek_cafe_saas_sdk-0.6.0/src/geek_cafe_saas_sdk/decorators/core.py +358 -0
- geek_cafe_saas_sdk-0.6.0/src/geek_cafe_saas_sdk/domains/__init__.py +0 -0
- geek_cafe_saas_sdk-0.6.0/src/geek_cafe_saas_sdk/domains/analytics/__init__.py +0 -0
- geek_cafe_saas_sdk-0.6.0/src/geek_cafe_saas_sdk/domains/analytics/handlers/__init__.py +0 -0
- geek_cafe_saas_sdk-0.6.0/src/geek_cafe_saas_sdk/domains/analytics/models/__init__.py +9 -0
- geek_cafe_saas_sdk-0.6.0/src/geek_cafe_saas_sdk/domains/analytics/models/website_analytics.py +219 -0
- geek_cafe_saas_sdk-0.6.0/src/geek_cafe_saas_sdk/domains/analytics/models/website_analytics_summary.py +220 -0
- geek_cafe_saas_sdk-0.6.0/src/geek_cafe_saas_sdk/domains/analytics/services/__init__.py +11 -0
- geek_cafe_saas_sdk-0.6.0/src/geek_cafe_saas_sdk/domains/analytics/services/website_analytics_service.py +232 -0
- geek_cafe_saas_sdk-0.6.0/src/geek_cafe_saas_sdk/domains/analytics/services/website_analytics_summary_service.py +212 -0
- geek_cafe_saas_sdk-0.6.0/src/geek_cafe_saas_sdk/domains/analytics/services/website_analytics_tally_service.py +610 -0
- geek_cafe_saas_sdk-0.6.0/src/geek_cafe_saas_sdk/domains/auth/__init__.py +0 -0
- geek_cafe_saas_sdk-0.6.0/src/geek_cafe_saas_sdk/domains/auth/handlers/__init__.py +0 -0
- geek_cafe_saas_sdk-0.6.0/src/geek_cafe_saas_sdk/domains/auth/handlers/users/create/app.py +41 -0
- geek_cafe_saas_sdk-0.6.0/src/geek_cafe_saas_sdk/domains/auth/handlers/users/delete/app.py +41 -0
- geek_cafe_saas_sdk-0.6.0/src/geek_cafe_saas_sdk/domains/auth/handlers/users/get/app.py +39 -0
- geek_cafe_saas_sdk-0.6.0/src/geek_cafe_saas_sdk/domains/auth/handlers/users/list/app.py +36 -0
- geek_cafe_saas_sdk-0.6.0/src/geek_cafe_saas_sdk/domains/auth/handlers/users/update/app.py +44 -0
- geek_cafe_saas_sdk-0.6.0/src/geek_cafe_saas_sdk/domains/auth/models/__init__.py +13 -0
- geek_cafe_saas_sdk-0.6.0/src/geek_cafe_saas_sdk/domains/auth/models/permission.py +134 -0
- geek_cafe_saas_sdk-0.6.0/src/geek_cafe_saas_sdk/domains/auth/models/resource_permission.py +245 -0
- geek_cafe_saas_sdk-0.6.0/src/geek_cafe_saas_sdk/domains/auth/models/role.py +213 -0
- geek_cafe_saas_sdk-0.6.0/src/geek_cafe_saas_sdk/domains/auth/models/user.py +285 -0
- geek_cafe_saas_sdk-0.6.0/src/geek_cafe_saas_sdk/domains/auth/services/__init__.py +16 -0
- geek_cafe_saas_sdk-0.6.0/src/geek_cafe_saas_sdk/domains/auth/services/authorization_service.py +376 -0
- geek_cafe_saas_sdk-0.6.0/src/geek_cafe_saas_sdk/domains/auth/services/permission_registry.py +464 -0
- geek_cafe_saas_sdk-0.6.0/src/geek_cafe_saas_sdk/domains/auth/services/resource_permission_service.py +408 -0
- geek_cafe_saas_sdk-0.6.0/src/geek_cafe_saas_sdk/domains/auth/services/user_service.py +274 -0
- geek_cafe_saas_sdk-0.6.0/src/geek_cafe_saas_sdk/domains/communities/__init__.py +0 -0
- geek_cafe_saas_sdk-0.6.0/src/geek_cafe_saas_sdk/domains/communities/handlers/__init__.py +0 -0
- geek_cafe_saas_sdk-0.6.0/src/geek_cafe_saas_sdk/domains/communities/handlers/communities/create/app.py +41 -0
- geek_cafe_saas_sdk-0.6.0/src/geek_cafe_saas_sdk/domains/communities/handlers/communities/delete/app.py +41 -0
- geek_cafe_saas_sdk-0.6.0/src/geek_cafe_saas_sdk/domains/communities/handlers/communities/get/app.py +39 -0
- geek_cafe_saas_sdk-0.6.0/src/geek_cafe_saas_sdk/domains/communities/handlers/communities/list/app.py +36 -0
- geek_cafe_saas_sdk-0.6.0/src/geek_cafe_saas_sdk/domains/communities/handlers/communities/update/app.py +44 -0
- geek_cafe_saas_sdk-0.6.0/src/geek_cafe_saas_sdk/domains/communities/models/__init__.py +6 -0
- geek_cafe_saas_sdk-0.6.0/src/geek_cafe_saas_sdk/domains/communities/models/community.py +326 -0
- geek_cafe_saas_sdk-0.6.0/src/geek_cafe_saas_sdk/domains/communities/models/community_member.py +227 -0
- geek_cafe_saas_sdk-0.6.0/src/geek_cafe_saas_sdk/domains/communities/services/__init__.py +6 -0
- geek_cafe_saas_sdk-0.6.0/src/geek_cafe_saas_sdk/domains/communities/services/community_member_service.py +412 -0
- geek_cafe_saas_sdk-0.6.0/src/geek_cafe_saas_sdk/domains/communities/services/community_service.py +479 -0
- geek_cafe_saas_sdk-0.6.0/src/geek_cafe_saas_sdk/domains/events/__init__.py +0 -0
- geek_cafe_saas_sdk-0.6.0/src/geek_cafe_saas_sdk/domains/events/handlers/__init__.py +0 -0
- geek_cafe_saas_sdk-0.6.0/src/geek_cafe_saas_sdk/domains/events/handlers/attendees/app.py +67 -0
- geek_cafe_saas_sdk-0.6.0/src/geek_cafe_saas_sdk/domains/events/handlers/cancel/app.py +66 -0
- geek_cafe_saas_sdk-0.6.0/src/geek_cafe_saas_sdk/domains/events/handlers/check_in/app.py +60 -0
- geek_cafe_saas_sdk-0.6.0/src/geek_cafe_saas_sdk/domains/events/handlers/create/app.py +93 -0
- geek_cafe_saas_sdk-0.6.0/src/geek_cafe_saas_sdk/domains/events/handlers/delete/app.py +42 -0
- geek_cafe_saas_sdk-0.6.0/src/geek_cafe_saas_sdk/domains/events/handlers/get/app.py +39 -0
- geek_cafe_saas_sdk-0.6.0/src/geek_cafe_saas_sdk/domains/events/handlers/invite/app.py +98 -0
- geek_cafe_saas_sdk-0.6.0/src/geek_cafe_saas_sdk/domains/events/handlers/list/app.py +125 -0
- geek_cafe_saas_sdk-0.6.0/src/geek_cafe_saas_sdk/domains/events/handlers/publish/app.py +49 -0
- geek_cafe_saas_sdk-0.6.0/src/geek_cafe_saas_sdk/domains/events/handlers/rsvp/app.py +83 -0
- geek_cafe_saas_sdk-0.6.0/src/geek_cafe_saas_sdk/domains/events/handlers/update/app.py +44 -0
- geek_cafe_saas_sdk-0.6.0/src/geek_cafe_saas_sdk/domains/events/models/__init__.py +3 -0
- geek_cafe_saas_sdk-0.6.0/src/geek_cafe_saas_sdk/domains/events/models/event.py +681 -0
- geek_cafe_saas_sdk-0.6.0/src/geek_cafe_saas_sdk/domains/events/models/event_attendee.py +324 -0
- geek_cafe_saas_sdk-0.6.0/src/geek_cafe_saas_sdk/domains/events/services/__init__.py +9 -0
- geek_cafe_saas_sdk-0.6.0/src/geek_cafe_saas_sdk/domains/events/services/event_attendee_service.py +571 -0
- geek_cafe_saas_sdk-0.6.0/src/geek_cafe_saas_sdk/domains/events/services/event_service.py +684 -0
- geek_cafe_saas_sdk-0.6.0/src/geek_cafe_saas_sdk/domains/files/__init__.py +0 -0
- geek_cafe_saas_sdk-0.6.0/src/geek_cafe_saas_sdk/domains/files/models/__init__.py +0 -0
- geek_cafe_saas_sdk-0.6.0/src/geek_cafe_saas_sdk/domains/files/models/directory.py +258 -0
- geek_cafe_saas_sdk-0.6.0/src/geek_cafe_saas_sdk/domains/files/models/file.py +312 -0
- geek_cafe_saas_sdk-0.6.0/src/geek_cafe_saas_sdk/domains/files/models/file_share.py +268 -0
- geek_cafe_saas_sdk-0.6.0/src/geek_cafe_saas_sdk/domains/files/models/file_version.py +216 -0
- geek_cafe_saas_sdk-0.6.0/src/geek_cafe_saas_sdk/domains/files/services/__init__.py +0 -0
- geek_cafe_saas_sdk-0.6.0/src/geek_cafe_saas_sdk/domains/files/services/directory_service.py +701 -0
- geek_cafe_saas_sdk-0.6.0/src/geek_cafe_saas_sdk/domains/files/services/file_share_service.py +663 -0
- geek_cafe_saas_sdk-0.6.0/src/geek_cafe_saas_sdk/domains/files/services/file_system_service.py +575 -0
- geek_cafe_saas_sdk-0.6.0/src/geek_cafe_saas_sdk/domains/files/services/file_version_service.py +739 -0
- geek_cafe_saas_sdk-0.6.0/src/geek_cafe_saas_sdk/domains/files/services/s3_file_service.py +501 -0
- geek_cafe_saas_sdk-0.6.0/src/geek_cafe_saas_sdk/domains/messaging/__init__.py +0 -0
- geek_cafe_saas_sdk-0.6.0/src/geek_cafe_saas_sdk/domains/messaging/handlers/__init__.py +0 -0
- geek_cafe_saas_sdk-0.6.0/src/geek_cafe_saas_sdk/domains/messaging/handlers/chat_channels/create/app.py +86 -0
- geek_cafe_saas_sdk-0.6.0/src/geek_cafe_saas_sdk/domains/messaging/handlers/chat_channels/delete/app.py +65 -0
- geek_cafe_saas_sdk-0.6.0/src/geek_cafe_saas_sdk/domains/messaging/handlers/chat_channels/get/app.py +64 -0
- geek_cafe_saas_sdk-0.6.0/src/geek_cafe_saas_sdk/domains/messaging/handlers/chat_channels/list/app.py +97 -0
- geek_cafe_saas_sdk-0.6.0/src/geek_cafe_saas_sdk/domains/messaging/handlers/chat_channels/update/app.py +149 -0
- geek_cafe_saas_sdk-0.6.0/src/geek_cafe_saas_sdk/domains/messaging/handlers/chat_messages/create/app.py +67 -0
- geek_cafe_saas_sdk-0.6.0/src/geek_cafe_saas_sdk/domains/messaging/handlers/chat_messages/delete/app.py +65 -0
- geek_cafe_saas_sdk-0.6.0/src/geek_cafe_saas_sdk/domains/messaging/handlers/chat_messages/get/app.py +64 -0
- geek_cafe_saas_sdk-0.6.0/src/geek_cafe_saas_sdk/domains/messaging/handlers/chat_messages/list/app.py +102 -0
- geek_cafe_saas_sdk-0.6.0/src/geek_cafe_saas_sdk/domains/messaging/handlers/chat_messages/update/app.py +127 -0
- geek_cafe_saas_sdk-0.6.0/src/geek_cafe_saas_sdk/domains/messaging/handlers/contact_threads/create/app.py +94 -0
- geek_cafe_saas_sdk-0.6.0/src/geek_cafe_saas_sdk/domains/messaging/handlers/contact_threads/delete/app.py +66 -0
- geek_cafe_saas_sdk-0.6.0/src/geek_cafe_saas_sdk/domains/messaging/handlers/contact_threads/get/app.py +67 -0
- geek_cafe_saas_sdk-0.6.0/src/geek_cafe_saas_sdk/domains/messaging/handlers/contact_threads/list/app.py +95 -0
- geek_cafe_saas_sdk-0.6.0/src/geek_cafe_saas_sdk/domains/messaging/handlers/contact_threads/update/app.py +156 -0
- geek_cafe_saas_sdk-0.6.0/src/geek_cafe_saas_sdk/domains/messaging/models/__init__.py +13 -0
- geek_cafe_saas_sdk-0.6.0/src/geek_cafe_saas_sdk/domains/messaging/models/chat_channel.py +337 -0
- geek_cafe_saas_sdk-0.6.0/src/geek_cafe_saas_sdk/domains/messaging/models/chat_channel_member.py +180 -0
- geek_cafe_saas_sdk-0.6.0/src/geek_cafe_saas_sdk/domains/messaging/models/chat_message.py +426 -0
- geek_cafe_saas_sdk-0.6.0/src/geek_cafe_saas_sdk/domains/messaging/models/contact_thread.py +392 -0
- geek_cafe_saas_sdk-0.6.0/src/geek_cafe_saas_sdk/domains/messaging/services/__init__.py +11 -0
- geek_cafe_saas_sdk-0.6.0/src/geek_cafe_saas_sdk/domains/messaging/services/chat_channel_service.py +700 -0
- geek_cafe_saas_sdk-0.6.0/src/geek_cafe_saas_sdk/domains/messaging/services/chat_message_service.py +491 -0
- geek_cafe_saas_sdk-0.6.0/src/geek_cafe_saas_sdk/domains/messaging/services/contact_thread_service.py +497 -0
- geek_cafe_saas_sdk-0.6.0/src/geek_cafe_saas_sdk/domains/tenancy/__init__.py +0 -0
- geek_cafe_saas_sdk-0.6.0/src/geek_cafe_saas_sdk/domains/tenancy/handlers/__init__.py +0 -0
- geek_cafe_saas_sdk-0.6.0/src/geek_cafe_saas_sdk/domains/tenancy/handlers/subscriptions/activate/app.py +52 -0
- geek_cafe_saas_sdk-0.6.0/src/geek_cafe_saas_sdk/domains/tenancy/handlers/subscriptions/active/app.py +37 -0
- geek_cafe_saas_sdk-0.6.0/src/geek_cafe_saas_sdk/domains/tenancy/handlers/subscriptions/cancel/app.py +55 -0
- geek_cafe_saas_sdk-0.6.0/src/geek_cafe_saas_sdk/domains/tenancy/handlers/subscriptions/get/app.py +39 -0
- geek_cafe_saas_sdk-0.6.0/src/geek_cafe_saas_sdk/domains/tenancy/handlers/subscriptions/list/app.py +44 -0
- geek_cafe_saas_sdk-0.6.0/src/geek_cafe_saas_sdk/domains/tenancy/handlers/subscriptions/record_payment/app.py +56 -0
- geek_cafe_saas_sdk-0.6.0/src/geek_cafe_saas_sdk/domains/tenancy/handlers/tenants/get/app.py +39 -0
- geek_cafe_saas_sdk-0.6.0/src/geek_cafe_saas_sdk/domains/tenancy/handlers/tenants/me/app.py +37 -0
- geek_cafe_saas_sdk-0.6.0/src/geek_cafe_saas_sdk/domains/tenancy/handlers/tenants/signup/app.py +61 -0
- geek_cafe_saas_sdk-0.6.0/src/geek_cafe_saas_sdk/domains/tenancy/handlers/tenants/update/app.py +44 -0
- geek_cafe_saas_sdk-0.6.0/src/geek_cafe_saas_sdk/domains/tenancy/models/__init__.py +6 -0
- geek_cafe_saas_sdk-0.6.0/src/geek_cafe_saas_sdk/domains/tenancy/models/subscription.py +440 -0
- geek_cafe_saas_sdk-0.6.0/src/geek_cafe_saas_sdk/domains/tenancy/models/tenant.py +258 -0
- geek_cafe_saas_sdk-0.6.0/src/geek_cafe_saas_sdk/domains/tenancy/services/__init__.py +6 -0
- geek_cafe_saas_sdk-0.6.0/src/geek_cafe_saas_sdk/domains/tenancy/services/subscription_service.py +557 -0
- geek_cafe_saas_sdk-0.6.0/src/geek_cafe_saas_sdk/domains/tenancy/services/tenant_service.py +575 -0
- geek_cafe_saas_sdk-0.6.0/src/geek_cafe_saas_sdk/domains/voting/__init__.py +0 -0
- geek_cafe_saas_sdk-0.6.0/src/geek_cafe_saas_sdk/domains/voting/handlers/__init__.py +0 -0
- geek_cafe_saas_sdk-0.6.0/src/geek_cafe_saas_sdk/domains/voting/handlers/votes/create/app.py +128 -0
- geek_cafe_saas_sdk-0.6.0/src/geek_cafe_saas_sdk/domains/voting/handlers/votes/delete/app.py +41 -0
- geek_cafe_saas_sdk-0.6.0/src/geek_cafe_saas_sdk/domains/voting/handlers/votes/get/app.py +39 -0
- geek_cafe_saas_sdk-0.6.0/src/geek_cafe_saas_sdk/domains/voting/handlers/votes/list/app.py +38 -0
- geek_cafe_saas_sdk-0.6.0/src/geek_cafe_saas_sdk/domains/voting/handlers/votes/summerize/README.md +3 -0
- geek_cafe_saas_sdk-0.6.0/src/geek_cafe_saas_sdk/domains/voting/handlers/votes/update/app.py +44 -0
- geek_cafe_saas_sdk-0.6.0/src/geek_cafe_saas_sdk/domains/voting/models/__init__.py +9 -0
- geek_cafe_saas_sdk-0.6.0/src/geek_cafe_saas_sdk/domains/voting/models/vote.py +231 -0
- geek_cafe_saas_sdk-0.6.0/src/geek_cafe_saas_sdk/domains/voting/models/vote_summary.py +193 -0
- geek_cafe_saas_sdk-0.6.0/src/geek_cafe_saas_sdk/domains/voting/services/__init__.py +11 -0
- geek_cafe_saas_sdk-0.6.0/src/geek_cafe_saas_sdk/domains/voting/services/vote_service.py +264 -0
- geek_cafe_saas_sdk-0.6.0/src/geek_cafe_saas_sdk/domains/voting/services/vote_summary_service.py +198 -0
- geek_cafe_saas_sdk-0.6.0/src/geek_cafe_saas_sdk/domains/voting/services/vote_tally_service.py +533 -0
- geek_cafe_saas_sdk-0.6.0/src/geek_cafe_saas_sdk/lambda_handlers/README.md +404 -0
- geek_cafe_saas_sdk-0.6.0/src/geek_cafe_saas_sdk/lambda_handlers/__init__.py +67 -0
- geek_cafe_saas_sdk-0.6.0/src/geek_cafe_saas_sdk/lambda_handlers/_base/__init__.py +25 -0
- geek_cafe_saas_sdk-0.6.0/src/geek_cafe_saas_sdk/lambda_handlers/_base/api_key_handler.py +129 -0
- geek_cafe_saas_sdk-0.6.0/src/geek_cafe_saas_sdk/lambda_handlers/_base/authorized_secure_handler.py +218 -0
- geek_cafe_saas_sdk-0.6.0/src/geek_cafe_saas_sdk/lambda_handlers/_base/base_handler.py +185 -0
- geek_cafe_saas_sdk-0.6.0/src/geek_cafe_saas_sdk/lambda_handlers/_base/handler_factory.py +256 -0
- geek_cafe_saas_sdk-0.6.0/src/geek_cafe_saas_sdk/lambda_handlers/_base/public_handler.py +53 -0
- geek_cafe_saas_sdk-0.6.0/src/geek_cafe_saas_sdk/lambda_handlers/_base/secure_handler.py +89 -0
- geek_cafe_saas_sdk-0.6.0/src/geek_cafe_saas_sdk/lambda_handlers/_base/service_pool.py +94 -0
- geek_cafe_saas_sdk-0.6.0/src/geek_cafe_saas_sdk/lambda_handlers/directories/create/app.py +79 -0
- geek_cafe_saas_sdk-0.6.0/src/geek_cafe_saas_sdk/lambda_handlers/directories/delete/app.py +76 -0
- geek_cafe_saas_sdk-0.6.0/src/geek_cafe_saas_sdk/lambda_handlers/directories/get/app.py +74 -0
- geek_cafe_saas_sdk-0.6.0/src/geek_cafe_saas_sdk/lambda_handlers/directories/list/app.py +75 -0
- geek_cafe_saas_sdk-0.6.0/src/geek_cafe_saas_sdk/lambda_handlers/directories/move/app.py +79 -0
- geek_cafe_saas_sdk-0.6.0/src/geek_cafe_saas_sdk/lambda_handlers/files/delete/app.py +121 -0
- geek_cafe_saas_sdk-0.6.0/src/geek_cafe_saas_sdk/lambda_handlers/files/download/app.py +187 -0
- geek_cafe_saas_sdk-0.6.0/src/geek_cafe_saas_sdk/lambda_handlers/files/get/app.py +127 -0
- geek_cafe_saas_sdk-0.6.0/src/geek_cafe_saas_sdk/lambda_handlers/files/list/app.py +108 -0
- geek_cafe_saas_sdk-0.6.0/src/geek_cafe_saas_sdk/lambda_handlers/files/share/app.py +83 -0
- geek_cafe_saas_sdk-0.6.0/src/geek_cafe_saas_sdk/lambda_handlers/files/shares/list/app.py +84 -0
- geek_cafe_saas_sdk-0.6.0/src/geek_cafe_saas_sdk/lambda_handlers/files/shares/revoke/app.py +76 -0
- geek_cafe_saas_sdk-0.6.0/src/geek_cafe_saas_sdk/lambda_handlers/files/update/app.py +143 -0
- geek_cafe_saas_sdk-0.6.0/src/geek_cafe_saas_sdk/lambda_handlers/files/upload/app.py +151 -0
- geek_cafe_saas_sdk-0.6.0/src/geek_cafe_saas_sdk/middleware/__init__.py +36 -0
- geek_cafe_saas_sdk-0.6.0/src/geek_cafe_saas_sdk/middleware/auth.py +85 -0
- geek_cafe_saas_sdk-0.6.0/src/geek_cafe_saas_sdk/middleware/authorization.py +523 -0
- geek_cafe_saas_sdk-0.6.0/src/geek_cafe_saas_sdk/middleware/cors.py +63 -0
- geek_cafe_saas_sdk-0.6.0/src/geek_cafe_saas_sdk/middleware/error_handling.py +114 -0
- geek_cafe_saas_sdk-0.6.0/src/geek_cafe_saas_sdk/middleware/validation.py +80 -0
- geek_cafe_saas_sdk-0.6.0/src/geek_cafe_saas_sdk/models/__init__.py +20 -0
- geek_cafe_saas_sdk-0.6.0/src/geek_cafe_saas_sdk/models/base_model.py +233 -0
- geek_cafe_saas_sdk-0.6.0/src/geek_cafe_saas_sdk/services/__init__.py +18 -0
- geek_cafe_saas_sdk-0.6.0/src/geek_cafe_saas_sdk/services/database_service.py +441 -0
- geek_cafe_saas_sdk-0.6.0/src/geek_cafe_saas_sdk/utilities/__init__.py +88 -0
- geek_cafe_saas_sdk-0.6.0/src/geek_cafe_saas_sdk/utilities/cognito_utility.py +568 -0
- geek_cafe_saas_sdk-0.6.0/src/geek_cafe_saas_sdk/utilities/custom_exceptions.py +183 -0
- geek_cafe_saas_sdk-0.6.0/src/geek_cafe_saas_sdk/utilities/datetime_utility.py +410 -0
- geek_cafe_saas_sdk-0.6.0/src/geek_cafe_saas_sdk/utilities/dictionary_utility.py +78 -0
- geek_cafe_saas_sdk-0.6.0/src/geek_cafe_saas_sdk/utilities/dynamodb_utils.py +151 -0
- geek_cafe_saas_sdk-0.6.0/src/geek_cafe_saas_sdk/utilities/environment_loader.py +149 -0
- geek_cafe_saas_sdk-0.6.0/src/geek_cafe_saas_sdk/utilities/environment_variables.py +228 -0
- geek_cafe_saas_sdk-0.6.0/src/geek_cafe_saas_sdk/utilities/http_body_parameters.py +44 -0
- geek_cafe_saas_sdk-0.6.0/src/geek_cafe_saas_sdk/utilities/http_path_parameters.py +60 -0
- geek_cafe_saas_sdk-0.6.0/src/geek_cafe_saas_sdk/utilities/http_status_code.py +63 -0
- geek_cafe_saas_sdk-0.6.0/src/geek_cafe_saas_sdk/utilities/jwt_utility.py +234 -0
- geek_cafe_saas_sdk-0.6.0/src/geek_cafe_saas_sdk/utilities/lambda_event_utility.py +776 -0
- geek_cafe_saas_sdk-0.6.0/src/geek_cafe_saas_sdk/utilities/logging_utility.py +64 -0
- geek_cafe_saas_sdk-0.6.0/src/geek_cafe_saas_sdk/utilities/message_query_helper.py +340 -0
- geek_cafe_saas_sdk-0.6.0/src/geek_cafe_saas_sdk/utilities/response.py +209 -0
- geek_cafe_saas_sdk-0.6.0/src/geek_cafe_saas_sdk/utilities/string_functions.py +180 -0
- geek_cafe_saas_sdk-0.6.0/update_readme_badges.py +195 -0
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# let's make sure we don't hit any actual aws resources
|
|
2
|
+
# when running moto mock tests
|
|
3
|
+
AWS_ACCESS_KEY_ID="testing"
|
|
4
|
+
AWS_SECRET_ACCESS_KEY="testing"
|
|
5
|
+
AWS_SECURITY_TOKEN="testing"
|
|
6
|
+
AWS_SESSION_TOKEN="testing"
|
|
7
|
+
AWS_DEFAULT_REGION="us-east-1"
|
|
8
|
+
AWS_REGION="us-east-1"
|
|
9
|
+
# So far it looks like I need a profile or I get an error like the one below
|
|
10
|
+
# "The config profile (<profile>) could not be found"
|
|
11
|
+
# "The config profile () could not be found" <- if using the default profile
|
|
12
|
+
# AWS_PROFILE="default"
|
|
13
|
+
# AWS_DEFAULT_PROFILE="default"
|
|
14
|
+
# I don't want to use default profile, so I'm using a mock profile
|
|
15
|
+
# However it must exist in ~/.aws/config or you'll get the same error above
|
|
16
|
+
AWS_PROFILE="moto-mock-tests"
|
|
17
|
+
AWS_DEFAULT_PROFILE="moto-mock-tests"
|
|
18
|
+
|
|
19
|
+
COGNITO_USER_POOL="us-east-1_ABC123"
|
|
20
|
+
COGNITO_CLIENT_ID="fake-client-id"
|
|
21
|
+
DYNAMODB_TABLE_NAME="geek_cafe_main"
|
|
22
|
+
AWS_REGION="us-east-1"
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
|
|
2
|
+
# Byte-compiled / optimized / DLL files
|
|
3
|
+
__pycache__/
|
|
4
|
+
*.py[codz]
|
|
5
|
+
*$py.class
|
|
6
|
+
|
|
7
|
+
# C extensions
|
|
8
|
+
*.so
|
|
9
|
+
|
|
10
|
+
# Distribution / packaging
|
|
11
|
+
.Python
|
|
12
|
+
build/
|
|
13
|
+
develop-eggs/
|
|
14
|
+
dist/
|
|
15
|
+
downloads/
|
|
16
|
+
eggs/
|
|
17
|
+
.eggs/
|
|
18
|
+
lib/
|
|
19
|
+
lib64/
|
|
20
|
+
parts/
|
|
21
|
+
sdist/
|
|
22
|
+
var/
|
|
23
|
+
wheels/
|
|
24
|
+
share/python-wheels/
|
|
25
|
+
*.egg-info/
|
|
26
|
+
.installed.cfg
|
|
27
|
+
*.egg
|
|
28
|
+
MANIFEST
|
|
29
|
+
|
|
30
|
+
# PyInstaller
|
|
31
|
+
# Usually these files are written by a python script from a template
|
|
32
|
+
# before PyInstaller builds the exe, so as to inject date/other infos into it.
|
|
33
|
+
*.manifest
|
|
34
|
+
*.spec
|
|
35
|
+
|
|
36
|
+
# Installer logs
|
|
37
|
+
pip-log.txt
|
|
38
|
+
pip-delete-this-directory.txt
|
|
39
|
+
|
|
40
|
+
# Unit test / coverage reports
|
|
41
|
+
htmlcov/
|
|
42
|
+
.tox/
|
|
43
|
+
.nox/
|
|
44
|
+
.coverage
|
|
45
|
+
.coverage.*
|
|
46
|
+
.cache
|
|
47
|
+
nosetests.xml
|
|
48
|
+
coverage.xml
|
|
49
|
+
*.cover
|
|
50
|
+
*.py.cover
|
|
51
|
+
.hypothesis/
|
|
52
|
+
.pytest_cache/
|
|
53
|
+
cover/
|
|
54
|
+
reports/
|
|
55
|
+
|
|
56
|
+
# Translations
|
|
57
|
+
*.mo
|
|
58
|
+
*.pot
|
|
59
|
+
|
|
60
|
+
# Django stuff:
|
|
61
|
+
*.log
|
|
62
|
+
local_settings.py
|
|
63
|
+
db.sqlite3
|
|
64
|
+
db.sqlite3-journal
|
|
65
|
+
|
|
66
|
+
# Flask stuff:
|
|
67
|
+
instance/
|
|
68
|
+
.webassets-cache
|
|
69
|
+
|
|
70
|
+
# Scrapy stuff:
|
|
71
|
+
.scrapy
|
|
72
|
+
|
|
73
|
+
# Sphinx documentation
|
|
74
|
+
docs/_build/
|
|
75
|
+
|
|
76
|
+
# PyBuilder
|
|
77
|
+
.pybuilder/
|
|
78
|
+
target/
|
|
79
|
+
|
|
80
|
+
# Jupyter Notebook
|
|
81
|
+
.ipynb_checkpoints
|
|
82
|
+
|
|
83
|
+
# IPython
|
|
84
|
+
profile_default/
|
|
85
|
+
ipython_config.py
|
|
86
|
+
|
|
87
|
+
# pyenv
|
|
88
|
+
# For a library or package, you might want to ignore these files since the code is
|
|
89
|
+
# intended to run in multiple environments; otherwise, check them in:
|
|
90
|
+
# .python-version
|
|
91
|
+
|
|
92
|
+
# pipenv
|
|
93
|
+
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
|
|
94
|
+
# However, in case of collaboration, if having platform-specific dependencies or dependencies
|
|
95
|
+
# having no cross-platform support, pipenv may install dependencies that don't work, or not
|
|
96
|
+
# install all needed dependencies.
|
|
97
|
+
#Pipfile.lock
|
|
98
|
+
|
|
99
|
+
# poetry
|
|
100
|
+
# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
|
|
101
|
+
# This is especially recommended for binary packages to ensure reproducibility, and is more
|
|
102
|
+
# commonly ignored for libraries.
|
|
103
|
+
# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
|
|
104
|
+
#poetry.lock
|
|
105
|
+
|
|
106
|
+
# Environments
|
|
107
|
+
.env
|
|
108
|
+
.venv
|
|
109
|
+
env/
|
|
110
|
+
venv/
|
|
111
|
+
ENV/
|
|
112
|
+
env.bak/
|
|
113
|
+
venv.bak/
|
|
114
|
+
|
|
115
|
+
# Spyder project settings
|
|
116
|
+
.spyderproject
|
|
117
|
+
.spyproject
|
|
118
|
+
|
|
119
|
+
# Rope project settings
|
|
120
|
+
.ropeproject
|
|
121
|
+
|
|
122
|
+
# mkdocs documentation
|
|
123
|
+
/site
|
|
124
|
+
|
|
125
|
+
# mypy
|
|
126
|
+
.mypy_cache/
|
|
127
|
+
.dmypy.json
|
|
128
|
+
dmypy.json
|
|
129
|
+
|
|
130
|
+
# Pyre type checker
|
|
131
|
+
.pyre/
|
|
132
|
+
|
|
133
|
+
# pytype static type analyzer
|
|
134
|
+
.pytype/
|
|
135
|
+
|
|
136
|
+
# Cython debug symbols
|
|
137
|
+
cython_debug/
|
|
138
|
+
|
|
139
|
+
# PyCharm
|
|
140
|
+
#.idea/
|
|
141
|
+
|
|
142
|
+
# VS Code
|
|
143
|
+
#.vscode/
|
|
144
|
+
# Local configuration
|
|
145
|
+
.pysetup.json
|
|
146
|
+
|
|
147
|
+
activate.sh
|
|
148
|
+
.pypirc
|
|
149
|
+
.prompts
|
|
150
|
+
.DS_Store
|
|
151
|
+
.local
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
rules:
|
|
2
|
+
- name: Documentation Standards
|
|
3
|
+
path: docs/guidelines/DOCUMENTATION_STANDARDS.md
|
|
4
|
+
description: File naming and structure conventions
|
|
5
|
+
- name: Production Ready
|
|
6
|
+
path: docs/guidelines/PRODUCTION_READY.md
|
|
7
|
+
description: Production ready conventions
|
|
8
|
+
- name: Testing Standards
|
|
9
|
+
|
|
@@ -0,0 +1,278 @@
|
|
|
1
|
+
# Architecture Overview
|
|
2
|
+
|
|
3
|
+
## Project Structure
|
|
4
|
+
|
|
5
|
+
```
|
|
6
|
+
geek-cafe-services/
|
|
7
|
+
├── src/geek_cafe_saas_sdk/
|
|
8
|
+
│ ├── core/ # Foundational types and patterns
|
|
9
|
+
│ │ ├── service_result.py # Standardized service response wrapper
|
|
10
|
+
│ │ ├── service_errors.py # Common error types
|
|
11
|
+
│ │ └── audit_mixin.py # Audit trail functionality
|
|
12
|
+
│ │
|
|
13
|
+
│ ├── models/ # DynamoDB models
|
|
14
|
+
│ │ ├── base_model.py # Base model with common patterns
|
|
15
|
+
│ │ ├── event.py # Event model
|
|
16
|
+
│ │ ├── user.py # User model
|
|
17
|
+
│ │ ├── group.py # Group model
|
|
18
|
+
│ │ ├── message_thread.py # Message thread model
|
|
19
|
+
│ │ ├── vote.py # Vote model
|
|
20
|
+
│ │ └── website_analytics.py # Analytics models
|
|
21
|
+
│ │
|
|
22
|
+
│ ├── services/ # Business logic layer
|
|
23
|
+
│ │ ├── database_service.py # Base database service
|
|
24
|
+
│ │ ├── event_service.py # Event operations
|
|
25
|
+
│ │ ├── user_service.py # User operations
|
|
26
|
+
│ │ ├── group_service.py # Group operations
|
|
27
|
+
│ │ ├── message_thread_service.py # Message operations
|
|
28
|
+
│ │ ├── vote_service.py # Vote operations
|
|
29
|
+
│ │ └── vote_tally_service.py # Vote aggregation
|
|
30
|
+
│ │
|
|
31
|
+
│ ├── lambda_handlers/ # AWS Lambda handlers
|
|
32
|
+
│ │ ├── _base/ # Internal base handlers
|
|
33
|
+
│ │ │ ├── base_handler.py
|
|
34
|
+
│ │ │ ├── api_key_handler.py
|
|
35
|
+
│ │ │ ├── public_handler.py
|
|
36
|
+
│ │ │ └── service_pool.py
|
|
37
|
+
│ │ ├── events/ # ✅ Complete CRUDL
|
|
38
|
+
│ │ ├── users/ # ✅ Complete CRUDL
|
|
39
|
+
│ │ ├── groups/ # ✅ Complete CRUDL
|
|
40
|
+
│ │ ├── messages/ # ✅ Complete CRUDL
|
|
41
|
+
│ │ └── votes/ # ✅ Complete CRUDL
|
|
42
|
+
│ │
|
|
43
|
+
│ ├── middleware/ # Cross-cutting concerns
|
|
44
|
+
│ │ ├── auth.py # Authentication middleware
|
|
45
|
+
│ │ ├── cors.py # CORS handling
|
|
46
|
+
│ │ ├── error_handling.py # Error middleware
|
|
47
|
+
│ │ └── validation.py # Request validation
|
|
48
|
+
│ │
|
|
49
|
+
│ └── utilities/ # Helper utilities
|
|
50
|
+
│ ├── response.py # HTTP response builders
|
|
51
|
+
│ ├── lambda_event_utility.py # Lambda event parsing
|
|
52
|
+
│ ├── dynamodb_utils.py # DynamoDB helpers
|
|
53
|
+
│ ├── jwt_utility.py # JWT handling
|
|
54
|
+
│ └── custom_exceptions.py # Custom exceptions
|
|
55
|
+
│
|
|
56
|
+
├── tests/ # Test suite
|
|
57
|
+
│ ├── common/ # Shared test utilities
|
|
58
|
+
│ ├── test_*_service.py # Service tests
|
|
59
|
+
│ ├── test_lambda_handlers/ # Handler integration tests
|
|
60
|
+
│ └── test_*.py # Various test files
|
|
61
|
+
│
|
|
62
|
+
└── docs/ # Documentation
|
|
63
|
+
├── api/ # API documentation
|
|
64
|
+
├── guides/ # Usage guides
|
|
65
|
+
└── services/ # Service documentation
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
## Design Principles
|
|
69
|
+
|
|
70
|
+
### 1. Multi-Tenant by Default
|
|
71
|
+
Every resource is scoped by `tenant_id`, ensuring complete data isolation between customers.
|
|
72
|
+
|
|
73
|
+
```python
|
|
74
|
+
# All service methods require tenant_id
|
|
75
|
+
result = event_service.create(
|
|
76
|
+
tenant_id="tenant-123",
|
|
77
|
+
user_id="user-456",
|
|
78
|
+
title="My Event"
|
|
79
|
+
)
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
### 2. Consistent Service Pattern
|
|
83
|
+
All services follow the same pattern:
|
|
84
|
+
|
|
85
|
+
- **ServiceResult wrapper**: Consistent return type for success/error handling
|
|
86
|
+
- **CRUD operations**: Create, Read, Update, Delete with soft deletes
|
|
87
|
+
- **Access control**: Built-in tenant and user validation
|
|
88
|
+
- **Error handling**: Standardized error responses
|
|
89
|
+
|
|
90
|
+
```python
|
|
91
|
+
# Every service method returns ServiceResult
|
|
92
|
+
result: ServiceResult[Event] = service.create(...)
|
|
93
|
+
|
|
94
|
+
if result.success:
|
|
95
|
+
event = result.data
|
|
96
|
+
else:
|
|
97
|
+
error = result.error
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
### 3. Lambda Handler Infrastructure
|
|
101
|
+
|
|
102
|
+
**Base Handlers** (`_base/`)
|
|
103
|
+
- `BaseLambdaHandler`: Core handler functionality
|
|
104
|
+
- `ApiKeyLambdaHandler`: Adds API key validation
|
|
105
|
+
- `PublicLambdaHandler`: No authentication required
|
|
106
|
+
- `ServicePool`: Connection pooling for warm starts
|
|
107
|
+
|
|
108
|
+
**Resource Handlers** (events, users, groups, messages, votes)
|
|
109
|
+
- Each resource has complete CRUDL operations
|
|
110
|
+
- Consistent authentication via Cognito JWT
|
|
111
|
+
- Service pooling for performance
|
|
112
|
+
- Testability via service injection
|
|
113
|
+
|
|
114
|
+
### 4. DynamoDB Optimization
|
|
115
|
+
|
|
116
|
+
**Single Table Design**
|
|
117
|
+
- One table for all resources
|
|
118
|
+
- Efficient GSI indexes for common queries
|
|
119
|
+
- Tenant-isolated partitions
|
|
120
|
+
|
|
121
|
+
**Key Patterns**
|
|
122
|
+
```python
|
|
123
|
+
# Primary Key (PK/SK)
|
|
124
|
+
PK: "TENANT#{tenant_id}"
|
|
125
|
+
SK: "EVENT#{event_id}"
|
|
126
|
+
|
|
127
|
+
# GSI for user queries
|
|
128
|
+
GSI1PK: "USER#{user_id}"
|
|
129
|
+
GSI1SK: "ts#{timestamp}"
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
### 5. Testing Strategy
|
|
133
|
+
|
|
134
|
+
**Integration Tests**
|
|
135
|
+
- Use `moto` for DynamoDB mocking
|
|
136
|
+
- Service injection for handler testing
|
|
137
|
+
- Complete end-to-end workflows
|
|
138
|
+
|
|
139
|
+
**Test Fixtures**
|
|
140
|
+
- `db_helpers.py`: DynamoDB setup helpers
|
|
141
|
+
- `lambda_helpers.py`: Event builders and test utilities
|
|
142
|
+
|
|
143
|
+
```python
|
|
144
|
+
# Clean test pattern
|
|
145
|
+
def test_create_event(integration_setup, helper):
|
|
146
|
+
db, event_service = integration_setup
|
|
147
|
+
|
|
148
|
+
event = helper.build_proxy_event(body={"title": "Test"})
|
|
149
|
+
response = handler(event, None, injected_service=event_service)
|
|
150
|
+
|
|
151
|
+
assert response['statusCode'] == 201
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
## Key Features
|
|
155
|
+
|
|
156
|
+
### Service Pooling
|
|
157
|
+
Reduces Lambda cold starts by 80-90% through connection reuse:
|
|
158
|
+
|
|
159
|
+
```python
|
|
160
|
+
# Module level - initialized once
|
|
161
|
+
service_pool = ServicePool(EventService)
|
|
162
|
+
|
|
163
|
+
def handler(event, context):
|
|
164
|
+
# Reuses service on warm invocations
|
|
165
|
+
service = service_pool.get()
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
### Authentication Flow
|
|
169
|
+
1. API Gateway validates Cognito JWT
|
|
170
|
+
2. Claims passed in `requestContext.authorizer.claims`
|
|
171
|
+
3. Handler extracts `custom:user_id` and `custom:tenant_id`
|
|
172
|
+
4. Service enforces tenant isolation
|
|
173
|
+
|
|
174
|
+
### Error Handling
|
|
175
|
+
Consistent error responses across all handlers:
|
|
176
|
+
|
|
177
|
+
```python
|
|
178
|
+
{
|
|
179
|
+
"statusCode": 400,
|
|
180
|
+
"body": {
|
|
181
|
+
"error": "Validation failed",
|
|
182
|
+
"errorCode": "VALIDATION_ERROR"
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
### Soft Deletes
|
|
188
|
+
Resources are marked as deleted, not physically removed:
|
|
189
|
+
|
|
190
|
+
```python
|
|
191
|
+
# Delete operation
|
|
192
|
+
result = service.delete(resource_id, tenant_id, user_id)
|
|
193
|
+
# Sets: deleted=True, deleted_at=timestamp
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
## Performance Optimizations
|
|
197
|
+
|
|
198
|
+
1. **Service Pooling**: Reuse DB connections on warm starts
|
|
199
|
+
2. **GSI Indexes**: Efficient queries without table scans
|
|
200
|
+
3. **Batch Operations**: Support for bulk reads/writes
|
|
201
|
+
4. **Pagination**: Cursor-based pagination for large result sets
|
|
202
|
+
|
|
203
|
+
## Security Features
|
|
204
|
+
|
|
205
|
+
1. **Tenant Isolation**: Every query scoped by tenant_id
|
|
206
|
+
2. **Soft Deletes**: Audit trail preservation
|
|
207
|
+
3. **Access Control**: User-level permissions per operation
|
|
208
|
+
4. **JWT Validation**: Via API Gateway authorizer
|
|
209
|
+
|
|
210
|
+
## Extension Points
|
|
211
|
+
|
|
212
|
+
### Adding New Resources
|
|
213
|
+
|
|
214
|
+
1. **Create Model** in `models/`
|
|
215
|
+
2. **Create Service** in `services/`
|
|
216
|
+
3. **Create Lambda Handlers** in `lambda_handlers/`
|
|
217
|
+
4. **Write Tests** following existing patterns
|
|
218
|
+
|
|
219
|
+
### Custom Middleware
|
|
220
|
+
|
|
221
|
+
Add to `middleware/` and apply to handlers:
|
|
222
|
+
|
|
223
|
+
```python
|
|
224
|
+
@custom_middleware
|
|
225
|
+
@handle_cors
|
|
226
|
+
@handle_errors
|
|
227
|
+
def lambda_handler(event, context):
|
|
228
|
+
pass
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
### Custom Validators
|
|
232
|
+
|
|
233
|
+
Extend validation in `utilities/` or add per-service validation.
|
|
234
|
+
|
|
235
|
+
## Deployment
|
|
236
|
+
|
|
237
|
+
### As a Library
|
|
238
|
+
```bash
|
|
239
|
+
pip install geek-cafe-services
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
### Lambda Deployment
|
|
243
|
+
Each handler directory is deployment-ready:
|
|
244
|
+
|
|
245
|
+
```bash
|
|
246
|
+
# AWS SAM
|
|
247
|
+
sam deploy --code-uri lambda_handlers/events/create
|
|
248
|
+
|
|
249
|
+
# AWS CDK
|
|
250
|
+
lambda.Function(this, 'EventCreate', {
|
|
251
|
+
code: lambda.Code.fromAsset('lambda_handlers/events/create'),
|
|
252
|
+
handler: 'app.handler'
|
|
253
|
+
})
|
|
254
|
+
```
|
|
255
|
+
|
|
256
|
+
## Best Practices
|
|
257
|
+
|
|
258
|
+
1. ✅ Always use `ServiceResult` for service responses
|
|
259
|
+
2. ✅ Require `tenant_id` for all operations
|
|
260
|
+
3. ✅ Use soft deletes, never hard deletes
|
|
261
|
+
4. ✅ Pool services in Lambda handlers
|
|
262
|
+
5. ✅ Inject services in tests
|
|
263
|
+
6. ✅ Follow CRUDL pattern for consistency
|
|
264
|
+
7. ✅ Document breaking changes until 1.0 GA
|
|
265
|
+
|
|
266
|
+
## Version Information
|
|
267
|
+
|
|
268
|
+
- **Current Version**: 0.3.0
|
|
269
|
+
- **Python**: 3.13+
|
|
270
|
+
- **Status**: Pre-1.0 (breaking changes possible)
|
|
271
|
+
- **Test Coverage**: 83.7% (482 tests)
|
|
272
|
+
|
|
273
|
+
## References
|
|
274
|
+
|
|
275
|
+
- **Service Pattern**: `docs/services_pattern.md`
|
|
276
|
+
- **Lambda Handlers**: `docs/api/lambda_handlers.md`
|
|
277
|
+
- **Handler Structure**: `docs/guides/lambda_handler_structure.md`
|
|
278
|
+
- **DynamoDB Models**: `docs/dynamodb_models.md`
|