fastapi-fullstack 0.2.18__py3-none-any.whl → 0.2.19__py3-none-any.whl
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.
- {fastapi_fullstack-0.2.18.dist-info → fastapi_fullstack-0.2.19.dist-info}/METADATA +10 -11
- {fastapi_fullstack-0.2.18.dist-info → fastapi_fullstack-0.2.19.dist-info}/RECORD +33 -35
- fastapi_gen/UPGRADES.yaml +16 -0
- fastapi_gen/prompts.py +1 -1
- fastapi_gen/template/hooks/post_gen_project.py +0 -1
- fastapi_gen/template/{{cookiecutter.project_slug}}/backend/alembic/versions/0027_user_magic_link_epoch.py +55 -0
- fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/admin.py +24 -2
- fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/api/deps.py +56 -5
- fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/api/routes/v1/auth.py +81 -11
- fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/api/routes/v1/knowledge_bases.py +3 -4
- fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/api/routes/v1/org_integrations.py +2 -3
- fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/core/crypto.py +11 -2
- fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/core/security.py +36 -4
- fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/db/models/user.py +19 -2
- fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/main.py +3 -11
- fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/schemas/webhook.py +5 -1
- fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/services/agent_session.py +80 -10
- fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/services/rate_limit/__init__.py +18 -0
- fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/services/rate_limit/service.py +87 -26
- fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/services/rate_limit/storage.py +25 -10
- fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/services/sync_source.py +22 -2
- fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/services/user.py +52 -6
- fastapi_gen/template/{{cookiecutter.project_slug}}/backend/pyproject.toml +0 -3
- fastapi_gen/template/{{cookiecutter.project_slug}}/backend/tests/api/test_auth.py +52 -0
- fastapi_gen/template/{{cookiecutter.project_slug}}/backend/tests/api/test_exceptions.py +1 -1
- fastapi_gen/template/{{cookiecutter.project_slug}}/backend/tests/api/test_openapi.py +17 -0
- fastapi_gen/template/{{cookiecutter.project_slug}}/backend/tests/conftest.py +18 -0
- fastapi_gen/template/{{cookiecutter.project_slug}}/backend/tests/test_core.py +48 -5
- fastapi_gen/template/{{cookiecutter.project_slug}}/backend/tests/test_security.py +47 -0
- fastapi_gen/template/{{cookiecutter.project_slug}}/backend/tests/test_services.py +94 -0
- fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/api/versioning.py +0 -173
- fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/core/csrf.py +0 -140
- fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/core/rate_limit.py +0 -53
- {fastapi_fullstack-0.2.18.dist-info → fastapi_fullstack-0.2.19.dist-info}/WHEEL +0 -0
- {fastapi_fullstack-0.2.18.dist-info → fastapi_fullstack-0.2.19.dist-info}/entry_points.txt +0 -0
- {fastapi_fullstack-0.2.18.dist-info → fastapi_fullstack-0.2.19.dist-info}/licenses/LICENSE +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: fastapi-fullstack
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.19
|
|
4
4
|
Summary: Full-stack FastAPI + Next.js template generator with PydanticAI/LangChain agents, WebSocket streaming, 20+ enterprise integrations, and Logfire/LangSmith observability. Ship AI apps fast. CLI tool to generate production-ready FastAPI + Next.js projects with AI agents, auth, and observability.
|
|
5
5
|
Project-URL: Homepage, https://github.com/vstorm-co/full-stack-ai-agent-template
|
|
6
6
|
Project-URL: Documentation, https://github.com/vstorm-co/full-stack-ai-agent-template#readme
|
|
@@ -19,27 +19,26 @@ Classifier: Programming Language :: Python :: 3.11
|
|
|
19
19
|
Classifier: Programming Language :: Python :: 3.12
|
|
20
20
|
Classifier: Topic :: Software Development :: Code Generators
|
|
21
21
|
Requires-Python: >=3.11
|
|
22
|
-
Requires-Dist: arq>=0.28.0
|
|
23
|
-
Requires-Dist: celery>=5.6.3
|
|
24
22
|
Requires-Dist: click>=8.3.3
|
|
25
23
|
Requires-Dist: cookiecutter>=2.7.0
|
|
26
24
|
Requires-Dist: email-validator>=2.3.0
|
|
27
|
-
Requires-Dist: httpx>=0.28.1
|
|
28
25
|
Requires-Dist: packaging>=24.0
|
|
29
|
-
Requires-Dist: pydantic-settings>=2.14.2
|
|
30
26
|
Requires-Dist: pydantic>=2.13.0
|
|
31
|
-
Requires-Dist: pytest-asyncio>=1.3.0
|
|
32
|
-
Requires-Dist: pytest>=9.0.3
|
|
33
27
|
Requires-Dist: pyyaml>=6.0
|
|
34
28
|
Requires-Dist: questionary>=2.1.0
|
|
35
29
|
Requires-Dist: rich>=15.0.0
|
|
36
30
|
Requires-Dist: ruff>=0.14.0
|
|
37
|
-
Requires-Dist: stripe>=15.1.0
|
|
38
|
-
Requires-Dist: taskiq>=0.12.4
|
|
39
31
|
Provides-Extra: dev
|
|
32
|
+
Requires-Dist: arq>=0.28.0; extra == 'dev'
|
|
33
|
+
Requires-Dist: celery>=5.6.3; extra == 'dev'
|
|
34
|
+
Requires-Dist: httpx>=0.28.1; extra == 'dev'
|
|
40
35
|
Requires-Dist: pre-commit>=4.0.0; extra == 'dev'
|
|
36
|
+
Requires-Dist: pydantic-settings>=2.14.2; extra == 'dev'
|
|
37
|
+
Requires-Dist: pytest-asyncio>=1.3.0; extra == 'dev'
|
|
41
38
|
Requires-Dist: pytest-cov>=7.0.0; extra == 'dev'
|
|
42
39
|
Requires-Dist: pytest>=9.0.0; extra == 'dev'
|
|
40
|
+
Requires-Dist: stripe>=15.1.0; extra == 'dev'
|
|
41
|
+
Requires-Dist: taskiq>=0.12.4; extra == 'dev'
|
|
43
42
|
Requires-Dist: ty>=0.0.31; extra == 'dev'
|
|
44
43
|
Provides-Extra: docs
|
|
45
44
|
Requires-Dist: mkdocs-material>=9.7.0; extra == 'docs'
|
|
@@ -810,7 +809,7 @@ They also ship a ready-to-use **`.claude/` toolkit** that adapts to the options
|
|
|
810
809
|
| **Background Tasks** | Celery, Taskiq, ARQ, Prefect |
|
|
811
810
|
| **Billing** | Stripe subscriptions (seat-based), credits + usage metering, invoices, Customer Portal |
|
|
812
811
|
| **Caching & State** | Redis, fastapi-cache2 |
|
|
813
|
-
| **Security** |
|
|
812
|
+
| **Security** | Per-plan sliding-window rate limiting (per user / org / IP), CORS, SSRF-guarded webhook delivery, httpOnly + SameSite session cookies |
|
|
814
813
|
| **Observability** | Logfire, LangSmith, Sentry, Prometheus |
|
|
815
814
|
| **Admin** | SQLAdmin panel with auth |
|
|
816
815
|
| **Collaboration** | Conversation sharing (direct + link), admin conversation browser |
|
|
@@ -1315,7 +1314,7 @@ Select what you need:
|
|
|
1315
1314
|
```bash
|
|
1316
1315
|
fastapi-fullstack new
|
|
1317
1316
|
# ✓ Redis (caching/sessions)
|
|
1318
|
-
# ✓ Rate limiting (
|
|
1317
|
+
# ✓ Rate limiting (per user/org/IP, Redis or in-memory)
|
|
1319
1318
|
# ✓ Pagination (fastapi-pagination)
|
|
1320
1319
|
# ✓ Admin Panel (SQLAdmin)
|
|
1321
1320
|
# ✓ AI Agent (PydanticAI or LangChain)
|
|
@@ -2,7 +2,7 @@ fastapi_gen/__init__.py,sha256=oK2gEM45SpSYBb-Itgr0GII88-5qfB0kmNkj90FkvQw,257
|
|
|
2
2
|
fastapi_gen/cli.py,sha256=ZpwdniivCiP1bVP54xW2H5hSaQzqUuu7ktfFxBIrNg0,60765
|
|
3
3
|
fastapi_gen/config.py,sha256=zZaIF5erTvs9Cv1cONnMMQ9voI6OLSz0-9d-eztYRDU,44147
|
|
4
4
|
fastapi_gen/generator.py,sha256=vMZ18ANuhCKva2pDklIIAZO7bkwX-ehvPzmFV0ND3vw,8441
|
|
5
|
-
fastapi_gen/prompts.py,sha256=
|
|
5
|
+
fastapi_gen/prompts.py,sha256=YNPNCiBmOC7-rlpH79tMYsyLSJoPzpmFAnOQsR-sjfw,66494
|
|
6
6
|
fastapi_gen/upgrade/__init__.py,sha256=-JlxOkKPW-rAbldIj2V4czXN3RGoP_tSm2hB0U8OO8M,640
|
|
7
7
|
fastapi_gen/upgrade/_render_worker.py,sha256=dAq5pmWJPdB3VRujFSYSh9tQ8z7klow6rCucgXEH6rE,1363
|
|
8
8
|
fastapi_gen/upgrade/classify.py,sha256=19veC5-h88WX8gf8MWHR0c8e9-G7Am5F6-TxI8NhE30,5745
|
|
@@ -17,10 +17,10 @@ fastapi_gen/upgrade/rename_guard.py,sha256=ap0ds5k93Hh6hhQhOxrDPsh-utTE1BeBYysrT
|
|
|
17
17
|
fastapi_gen/upgrade/render.py,sha256=PmEm7BPmEfUK29RcVgPN9PttTX7oHeWnDgf_vgGja1s,5497
|
|
18
18
|
fastapi_gen/upgrade/report.py,sha256=49v9kq2tkbeqqbdH-kRIM3kccaFfPVfjhi7Tm5cCVvE,3802
|
|
19
19
|
fastapi_gen/upgrade/runner.py,sha256=msnj2RYii6low6gPeZ4TRMlL01Hq8a0zJyLBzPotxCI,19302
|
|
20
|
-
fastapi_gen/UPGRADES.yaml,sha256=
|
|
20
|
+
fastapi_gen/UPGRADES.yaml,sha256=TaVbh-X3gstDtDrAZ7HhT1Dojp0qf8BNfVWSmehL4Lw,3682
|
|
21
21
|
fastapi_gen/template/VARIABLES.md,sha256=9CcimCDgXLshogzr1pjRYUTTmECCL9NAb1OzDFNTfgw,34322
|
|
22
22
|
fastapi_gen/template/cookiecutter.json,sha256=xikYtcbOLG4VOwZXAk-0acbELW8jXhHAGEg4kGEgRdg,6337
|
|
23
|
-
fastapi_gen/template/hooks/post_gen_project.py,sha256=
|
|
23
|
+
fastapi_gen/template/hooks/post_gen_project.py,sha256=RWwUmM6bVZnwFozyi_x1KLS2BHWAet0B0up6zWFZmd0,57986
|
|
24
24
|
fastapi_gen/template/{{cookiecutter.project_slug}}/.gitignore,sha256=yC3ZUp8Txp_1TPDabDlz4pGa2p1cNwr49de0dCcctOw,1515
|
|
25
25
|
fastapi_gen/template/{{cookiecutter.project_slug}}/.gitlab-ci.yml,sha256=dZh-VSLL5beOtj8_UxBbD86sBdE9ubTpmWvMcrRqr-M,4651
|
|
26
26
|
fastapi_gen/template/{{cookiecutter.project_slug}}/AGENTS.md,sha256=HqhXNdBq1ZXlFJCC4V3CY8DorTkZkwFJcvv2O77Pwk4,2454
|
|
@@ -60,7 +60,7 @@ fastapi_gen/template/{{cookiecutter.project_slug}}/backend/.env.example,sha256=H
|
|
|
60
60
|
fastapi_gen/template/{{cookiecutter.project_slug}}/backend/.pre-commit-config.yaml,sha256=22sYeJOrYywl_5PWgPzCyIwhpqmymIDIzx2hlBRQ-yI,681
|
|
61
61
|
fastapi_gen/template/{{cookiecutter.project_slug}}/backend/Dockerfile,sha256=CKyuUKwt41LHIH9VB28TEzes5_TQkUEo9rIBjE3v8a8,2184
|
|
62
62
|
fastapi_gen/template/{{cookiecutter.project_slug}}/backend/alembic.ini,sha256=vncO8XHTAW1ospWsdvtXD5PyMhp91CJmdVfv-6TakAY,737
|
|
63
|
-
fastapi_gen/template/{{cookiecutter.project_slug}}/backend/pyproject.toml,sha256=
|
|
63
|
+
fastapi_gen/template/{{cookiecutter.project_slug}}/backend/pyproject.toml,sha256=dIs_3KaQ7P1FqjTjd8WtvVX_ZHNxVKwbfieS3ByPGJA,14701
|
|
64
64
|
fastapi_gen/template/{{cookiecutter.project_slug}}/backend/alembic/env.py,sha256=ifDazpmfYDUI0KGxaGcAgJbz6HNzu9bQYB6li88OMcU,3163
|
|
65
65
|
fastapi_gen/template/{{cookiecutter.project_slug}}/backend/alembic/script.py.mako,sha256=ZCfgWrEMJRDF_WF_GRGptwAIJI6YnAditBG1axwAP9Q,700
|
|
66
66
|
fastapi_gen/template/{{cookiecutter.project_slug}}/backend/alembic/versions/.gitkeep,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
@@ -91,9 +91,10 @@ fastapi_gen/template/{{cookiecutter.project_slug}}/backend/alembic/versions/0023
|
|
|
91
91
|
fastapi_gen/template/{{cookiecutter.project_slug}}/backend/alembic/versions/0024_create_webhook_tables.py,sha256=HExnIhQAJXNCe1vxhagIhUr0BeBBv2MTBadQEY4GtY8,3233
|
|
92
92
|
fastapi_gen/template/{{cookiecutter.project_slug}}/backend/alembic/versions/0025_message_thinking.py,sha256=8Wi3zcAXADP6WbjuB-Na_Y_OZTx6DDETkrZAVrNEdl8,727
|
|
93
93
|
fastapi_gen/template/{{cookiecutter.project_slug}}/backend/alembic/versions/0026_create_mcp_connections.py,sha256=ADbedBphmfFnRiZ7fssMjD2fgfqz6YIUf7F2DguKm68,3188
|
|
94
|
+
fastapi_gen/template/{{cookiecutter.project_slug}}/backend/alembic/versions/0027_user_magic_link_epoch.py,sha256=tbI74ZtMv0UVT1sUiAzCZSd6w_efFVh-8-E_bypdt00,1411
|
|
94
95
|
fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/__init__.py,sha256=vNnuyVXC5oZ3yq46meWLNhkUYlMgod70TgvWyvgNhBk,68
|
|
95
|
-
fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/admin.py,sha256=
|
|
96
|
-
fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/main.py,sha256=
|
|
96
|
+
fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/admin.py,sha256=jK6iIS4OlsSBID2xZOYWZCEndpSAhxwclc_lceZKIUI,14043
|
|
97
|
+
fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/main.py,sha256=9MqX6pAhFf5Qwq4zF53c83qlab4HQrVLHFYwfpjFXPo,18584
|
|
97
98
|
fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/agents/__init__.py,sha256=DP_Hrjq0WlyuWhrkplLKmS3pVsoGZgFQgXhAcsjqBlQ,1889
|
|
98
99
|
fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/agents/assistant.py,sha256=NXZTvQBn7iaqQVcXCUwAusSKx1PmBpcDiYl2uUa6hKA,22196
|
|
99
100
|
fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/agents/deepagents_assistant.py,sha256=vziHT47EmLWSh7RJWCAUHGu5orxm1PrINwLEc7OJJN8,30372
|
|
@@ -113,10 +114,9 @@ fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/agents/tools/rag_
|
|
|
113
114
|
fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/agents/tools/research.py,sha256=p3j5K5FdjJ3JyktyEHVRj_P0DQBV3KJAha7lDyLCrIk,168
|
|
114
115
|
fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/agents/tools/web_search.py,sha256=CyRc7-rklcMl6s_9Cnl1xLDcBNm8Q3mMiEu3bYKagQk,3177
|
|
115
116
|
fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/api/__init__.py,sha256=NeESK8RjcyjY9KL1c9H2jIw34RpWmtlHgd8rhPBuolo,18
|
|
116
|
-
fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/api/deps.py,sha256=
|
|
117
|
+
fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/api/deps.py,sha256=DbimT-gx2At1hdnS0SIxOmiZWmJDkLxCDOHK5euJkoQ,27384
|
|
117
118
|
fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/api/exception_handlers.py,sha256=FGDbVsO-UzvWZtcnLW6joZXPZahZc9O13p_tqzlhF6c,3453
|
|
118
119
|
fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/api/router.py,sha256=8E0e0Oef6KrB6raDgrV0Lj-tPKRiQ-5UlGM3yGnz50Q,233
|
|
119
|
-
fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/api/versioning.py,sha256=O5FQre_y1hwJGsbREeKbRKoxEWUVhGNg7gIC76FqyPo,5906
|
|
120
120
|
fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/api/routes/__init__.py,sha256=wIJD_xpViBStOBb4iWBX_hxdPfSKJyAGlcOw81NTWXo,207
|
|
121
121
|
fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/api/routes/v1/__init__.py,sha256=WeCCXp1dETT-BsVXFzS86wlzXp6YScgij2ahudY2gBg,7292
|
|
122
122
|
fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/api/routes/v1/admin_conversations.py,sha256=Kmzwl-ve6jbukTa5WNQIydOOR1cmIvXWLtamXS9Oj4E,2612
|
|
@@ -124,7 +124,7 @@ fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/api/routes/v1/adm
|
|
|
124
124
|
fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/api/routes/v1/admin_stats.py,sha256=z6xVC9yac5jcGpt5QK91VdzpgYap9ETWgCx2M6yKITM,1177
|
|
125
125
|
fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/api/routes/v1/admin_users.py,sha256=dcg36c-q-1qb7H1m7gQOF52SHclfeEyCqbqUpjUrxMw,3924
|
|
126
126
|
fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/api/routes/v1/agent.py,sha256=muXxu5PJnZivVV_fgci6_iRvibg9ZyKwuVOtbJT37Wg,10573
|
|
127
|
-
fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/api/routes/v1/auth.py,sha256=
|
|
127
|
+
fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/api/routes/v1/auth.py,sha256=owJbU0Pk3474cXY0m7vpXDE1RaSFNvbhfO1MrZhu388,10575
|
|
128
128
|
fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/api/routes/v1/billing.py,sha256=NNEGZBkqC9mBc1eCQRyrVSbDPu00H8jwo1zq_DBoPWY,7533
|
|
129
129
|
fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/api/routes/v1/channels.py,sha256=Zr9m3GqWNNoBIGps4rmNBf4a5ha8jEuzNZSPMRhNPyE,3512
|
|
130
130
|
fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/api/routes/v1/contact.py,sha256=o7NDT4ZaHem3Bdj4aVL3oOhUT9owWCIErttJ68TmmPU,722
|
|
@@ -133,13 +133,13 @@ fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/api/routes/v1/fil
|
|
|
133
133
|
fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/api/routes/v1/health.py,sha256=pGvisRQ8dLK6jbIpm5Q2hxvWq6VYi0BF_EFN6RWnvVY,8329
|
|
134
134
|
fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/api/routes/v1/invitations.py,sha256=ZN4SKxzw14rIovpJAj9TkSbfpedo56zW2s9PfJq7FU4,2978
|
|
135
135
|
fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/api/routes/v1/items.py,sha256=43S9OPXxAxrk_F10toYeLM0MRW_O37-w-0CQ8JAwDbo,2285
|
|
136
|
-
fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/api/routes/v1/knowledge_bases.py,sha256=
|
|
136
|
+
fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/api/routes/v1/knowledge_bases.py,sha256=QQolJKIDUjqpVoBvdn1jrfnmBRKc7nRmoHiMMo2J6aI,14155
|
|
137
137
|
fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/api/routes/v1/marketing.py,sha256=QG_CjH8_xk9Ii_D0Vjxu4li0y2pHvulUmB8X7n2l58o,750
|
|
138
138
|
fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/api/routes/v1/me_mcp_connections.py,sha256=HTCzfTqkLTjYzfMzNFYlvXFAArJomTjZB93eMBBgx0w,4660
|
|
139
139
|
fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/api/routes/v1/me_slash_commands.py,sha256=cCQP6JS8LRaTazgk2K0R4EASZSop1iCK34CAG3Fc3Kc,2685
|
|
140
140
|
fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/api/routes/v1/members.py,sha256=5_Tfwc8s8JqTZUk5XMJ4HAGwEDSsehkrk73VSHUvQjQ,3329
|
|
141
141
|
fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/api/routes/v1/oauth.py,sha256=Zz_fNrh2xNwRpoGdqOCGeZBPf4TcjMm0cAkq0I80x_U,2862
|
|
142
|
-
fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/api/routes/v1/org_integrations.py,sha256=
|
|
142
|
+
fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/api/routes/v1/org_integrations.py,sha256=uAAZT2WKhMs8maTBacAWfE8-o-8eFh_K9ovD7ZLcJis,3919
|
|
143
143
|
fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/api/routes/v1/organizations.py,sha256=Zl3bJPy-RfpluSgadeStrp_KodVpLQKmUPkoFkXiXxU,4992
|
|
144
144
|
fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/api/routes/v1/projects.py,sha256=d9l5HZ5wJl_MGnIvEJss_gXomxUR3XYLXB-grLV_81s,4565
|
|
145
145
|
fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/api/routes/v1/public_demos.py,sha256=XP6KDu2U6LaJKydkuE5fYjO1PgggGrQVU9j1a9VRq9M,1538
|
|
@@ -164,16 +164,14 @@ fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/core/audit.py,sha
|
|
|
164
164
|
fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/core/cache.py,sha256=VYZfvIdLdtb1Y8h09IoxqPkDyG8pZtY96hR15Hff8YM,626
|
|
165
165
|
fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/core/channel_crypto.py,sha256=VG98BxIMoXL_6U6B40gCX_p8xHSoOTBPre3zCclVyQs,1608
|
|
166
166
|
fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/core/config.py,sha256=HnVa4gZwadFI8x9bhUvCdnPGCPbscZB4_gEGACMhgKM,28332
|
|
167
|
-
fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/core/crypto.py,sha256=
|
|
168
|
-
fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/core/csrf.py,sha256=5tXguJXdMr8rs2TYTEyvUkY4r6nxcQa1ZrA8E3HPon4,4575
|
|
167
|
+
fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/core/crypto.py,sha256=1XM09Vxf4yYzU-wiZAK4lN4Wy4j7aLTbPjbeTURnIfE,1760
|
|
169
168
|
fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/core/exceptions.py,sha256=DRMaSCDwajxldiC530gJLHbsg4NeqdYdat7zBq5i4IQ,3000
|
|
170
169
|
fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/core/logfire_setup.py,sha256=Aq6k4FY7wrFUwFMPmTcVbq_VNfNdYJ5FOs5vOCsI1EI,1773
|
|
171
170
|
fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/core/logging.py,sha256=7TFYXXeNAa5UnNLff2K-kwZFqi_VJ4jILMtLpm8H6Sw,2651
|
|
172
171
|
fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/core/middleware.py,sha256=hYEOf45mYc9PRrayiO3XOd0cdLM2GYYS76o1Jiv6tUQ,3570
|
|
173
172
|
fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/core/oauth.py,sha256=YtyJBlHY6qsond8aKOrg0S7OyKA22LZ7RN8QWi8G8Tg,571
|
|
174
|
-
fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/core/rate_limit.py,sha256=cdn1M1JeoNPLiWkWKa5MzXDnpbUa403PTF3n4TioGAg,1435
|
|
175
173
|
fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/core/sanitize.py,sha256=VuvNiccu2gErxVDmVAJ04E_oy-KxAzTLyujVaO2XCag,11567
|
|
176
|
-
fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/core/security.py,sha256=
|
|
174
|
+
fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/core/security.py,sha256=nXjXx1MN3mR_mqZvBEZQbSOdFV8hM1oJyCx8FfJ2ofc,7661
|
|
177
175
|
fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/db/__init__.py,sha256=VRbMV3VsQxDygLTek0L9_q1v1T_L9MjfGFobSUa2FHg,284
|
|
178
176
|
fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/db/base.py,sha256=TWjarV2D4yIKC7w_e8gR0v6hUE94cBnl0bSa8GYp56s,2108
|
|
179
177
|
fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/db/session.py,sha256=4aGrpl4JQDQVu5kOVQnI2dA4ObbJY5kOZYD94b5afpQ,2991
|
|
@@ -200,7 +198,7 @@ fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/db/models/stripe_
|
|
|
200
198
|
fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/db/models/subscription.py,sha256=0odUi8jukbdbuhia74wZG4ARCog-_Ie2bjWusThm5AQ,5138
|
|
201
199
|
fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/db/models/sync_log.py,sha256=6xnp8USm0oizrzMtZWAuZEppAlbA7k7C7wZfwi-iBFQ,3683
|
|
202
200
|
fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/db/models/sync_source.py,sha256=BcY3gwEcwvPlRm4H2n2bVuXOEt9QkkSapwHd81z8ot0,4080
|
|
203
|
-
fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/db/models/user.py,sha256=
|
|
201
|
+
fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/db/models/user.py,sha256=PaFft2fL4ifrb0vK1hGgCkOmmRYRg1ddXx97dmON0Bw,6877
|
|
204
202
|
fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/db/models/user_slash_command.py,sha256=ZN71Ry1RcIlG1eUoahySsJW1Q7rxm3gKbeoiVnskspQ,4109
|
|
205
203
|
fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/db/models/webhook.py,sha256=kl-2FRe0ineDl8mtI9wT1SFnQwqvZtebbfplfE3QtNI,5697
|
|
206
204
|
fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/repositories/__init__.py,sha256=Wog9087BD1uhNzf-epXUo7YA5M8QeTuADRYcjL-9C4w,3558
|
|
@@ -253,12 +251,12 @@ fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/schemas/sync_sour
|
|
|
253
251
|
fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/schemas/token.py,sha256=fle_Sx9A4c9e4ilLIpuxzLlwioRkkQJx2MhzgKrB7I4,618
|
|
254
252
|
fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/schemas/user.py,sha256=uu6YTYy-Y009d67kkBFV3q8UexTt1Ww7s1JXATPRB4Y,2425
|
|
255
253
|
fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/schemas/user_slash_command.py,sha256=94XnNqmSsaCPBhZIkkIl6yht_DoMisk6AN_CquJL40c,1887
|
|
256
|
-
fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/schemas/webhook.py,sha256=
|
|
254
|
+
fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/schemas/webhook.py,sha256=VRwBD9l_lBfnPjQxp8kg4DOLyd6FCAUj5BZjoXZN0oI,2166
|
|
257
255
|
fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/services/__init__.py,sha256=2eaFa3riNnh9BVf4A6i7ChK1yqCOA8VyTg1zeL2tYy0,523
|
|
258
256
|
fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/services/admin.py,sha256=FzwzW6FpIx1Ciwj_9lCbWMzi-EWv3v2-J8Sopi9LiZU,5576
|
|
259
257
|
fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/services/agent.py,sha256=nL7gsIBIHNsyePQHUBSWU5sO9jotfOkCXgE2T9t9hPY,12064
|
|
260
258
|
fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/services/agent_invocation.py,sha256=BOUuHp8QVXYmQTX30vQw4Wl2U9D3QsUA3sNrT7CMaRw,16486
|
|
261
|
-
fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/services/agent_session.py,sha256=
|
|
259
|
+
fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/services/agent_session.py,sha256=yLT1T0nPHnkurzyFSbFmQ9RNzyQW20T2H9rh6gGXIf0,115846
|
|
262
260
|
fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/services/anomaly_detection.py,sha256=uKPCzzdeyDSUbgkD7VwFIubEHhoU1LEoOp3R1_F0SlE,3112
|
|
263
261
|
fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/services/channel_bot.py,sha256=R1tfQQcNxHKZ9C3yOD6Hh4TANY77FL4XNic4Rf40qWo,6383
|
|
264
262
|
fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/services/contact.py,sha256=AuML8RHIozZkchZlNMjHsZhLWpTMxukfy1xk6mak3Bk,1697
|
|
@@ -281,9 +279,9 @@ fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/services/rag_stat
|
|
|
281
279
|
fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/services/rag_sync.py,sha256=7SJvrszd-z7k1jMz67Ez6gfbS45oxxCePa9WHZh_EVw,5958
|
|
282
280
|
fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/services/research.py,sha256=APGywGFljVcTi4D9LLBTmVYICe2VfyE2QnjKS2ppaHk,12154
|
|
283
281
|
fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/services/session.py,sha256=mABDVV3lMvmJsprr-y_XSMQ8hTb4PIEnK_bn5jasUUw,4103
|
|
284
|
-
fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/services/sync_source.py,sha256=
|
|
282
|
+
fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/services/sync_source.py,sha256=geoKqmIjDgxAzS5Jmm2qW7fdAl9i_1ZgfiGFMNf951k,12199
|
|
285
283
|
fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/services/usage.py,sha256=SUNAEnnOZjXr_PXoFGjfkMjAw7aB5FvIHReeAVI4wx8,3756
|
|
286
|
-
fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/services/user.py,sha256=
|
|
284
|
+
fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/services/user.py,sha256=OcOiIm2tIChbpb0FqvsGU1pMcXWs6PtParnoe3dVSaU,15172
|
|
287
285
|
fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/services/user_slash_command.py,sha256=t1-IIExupr-pvhCt_JjmiLrWfzMEzR2cDcLfhfPVRCQ,5427
|
|
288
286
|
fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/services/webhook.py,sha256=RCT96wAQDnr8CUG9_gzXYxi-Av3BXzjbl0BnxNY1qWw,7500
|
|
289
287
|
fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/services/billing/__init__.py,sha256=t953_p9xlo9jNiflpiQBBiht-wWXV-RJAHi75Dp7w-0,448
|
|
@@ -332,10 +330,10 @@ fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/services/rag/sour
|
|
|
332
330
|
fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/services/rag/sources/base.py,sha256=KGX85J0pHMX9j8PTJm64gYRckV53t3mGT3IYDj6J-Tg,3781
|
|
333
331
|
fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/services/rag/sources/google_drive.py,sha256=z4cComs7y9dKjm1VYyiLguB-t-JDJ-SQ9Q74_2c8vQ4,5001
|
|
334
332
|
fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/services/rag/sources/s3.py,sha256=mqW6lCmG2rsCal0P_IkL_C80SiTGkTNNBCK0nva7lS0,3055
|
|
335
|
-
fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/services/rate_limit/__init__.py,sha256=
|
|
333
|
+
fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/services/rate_limit/__init__.py,sha256=2J-r2Z8IywpsP5IUKjAuWzJ1CaH3x8M56cmYqtEB_dI,600
|
|
336
334
|
fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/services/rate_limit/rules.py,sha256=qhWTMlnGOrMlt3xb2mUwi_wsk4ND91mTMfjuaYfbqUM,1767
|
|
337
|
-
fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/services/rate_limit/service.py,sha256=
|
|
338
|
-
fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/services/rate_limit/storage.py,sha256
|
|
335
|
+
fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/services/rate_limit/service.py,sha256=kjx6CMorIYWoEh1HPpJ_IdUNI4r0SyjMZBAtup0p5RU,6769
|
|
336
|
+
fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/services/rate_limit/storage.py,sha256=-YN2F6OFikcU6jHxCUzRX6SnRSN_I27Lx_aKcl9aTHM,5422
|
|
339
337
|
fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/worker/__init__.py,sha256=wPhtHZI_FCMIJOeVnqX4BR85311K3ESYszlRZRadVYI,156
|
|
340
338
|
fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/worker/arq_app.py,sha256=re-StDERu9aB_YzMOBUoSOokxIBV6pb-EfATFKFeiZM,2594
|
|
341
339
|
fastapi_gen/template/{{cookiecutter.project_slug}}/backend/app/worker/celery_app.py,sha256=s4sHn9XBeIdknD6pKUlvJjI4Eg3aE_eHr3cLl0_WUnQ,2177
|
|
@@ -354,14 +352,14 @@ fastapi_gen/template/{{cookiecutter.project_slug}}/backend/cli/__init__.py,sha25
|
|
|
354
352
|
fastapi_gen/template/{{cookiecutter.project_slug}}/backend/cli/commands.py,sha256=T8GO9T32U5ceUMk-1kB8mu9884xQbfjlm_2fW7rvGUs,9349
|
|
355
353
|
fastapi_gen/template/{{cookiecutter.project_slug}}/backend/scripts/.gitkeep,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
356
354
|
fastapi_gen/template/{{cookiecutter.project_slug}}/backend/tests/__init__.py,sha256=xqsJPT1QR2TH_5GYK8tiHp-Lb29chxGsr147MWoLAZw,21
|
|
357
|
-
fastapi_gen/template/{{cookiecutter.project_slug}}/backend/tests/conftest.py,sha256=
|
|
355
|
+
fastapi_gen/template/{{cookiecutter.project_slug}}/backend/tests/conftest.py,sha256=2k-vyUbgGXcQdgIm3eEAgznNnzBP90Lfbuf-q5Jx_V0,4065
|
|
358
356
|
fastapi_gen/template/{{cookiecutter.project_slug}}/backend/tests/test_admin.py,sha256=hLh04pv85EmS8CURqXWpFQw6xOiN217da8EJIw9n0Io,29588
|
|
359
357
|
fastapi_gen/template/{{cookiecutter.project_slug}}/backend/tests/test_agents.py,sha256=SyR_iCoMzOoJl0vvcAp68rUbYvymXnCdGjt0zRjbrn8,12424
|
|
360
358
|
fastapi_gen/template/{{cookiecutter.project_slug}}/backend/tests/test_chart_tool.py,sha256=RJ2E6Ww0pvVLypE9QJtifV90Z7Pap2I2VZET2NkdCcE,4706
|
|
361
359
|
fastapi_gen/template/{{cookiecutter.project_slug}}/backend/tests/test_clients.py,sha256=qKU2z4YVQMWdnNE9aH5lnACsdzQ1G4fcE9_sK8x7K2U,6282
|
|
362
360
|
fastapi_gen/template/{{cookiecutter.project_slug}}/backend/tests/test_commands.py,sha256=G7pRJgk0pDQRBIFUIhi0bbDnujwKcWCjCP9Q1D9TzYA,4894
|
|
363
361
|
fastapi_gen/template/{{cookiecutter.project_slug}}/backend/tests/test_conversation_kb_toggle.py,sha256=ZDlX1lMuLl4q41g0f8IE0oPt3lbca4an_8c19Z1xyo8,3888
|
|
364
|
-
fastapi_gen/template/{{cookiecutter.project_slug}}/backend/tests/test_core.py,sha256=
|
|
362
|
+
fastapi_gen/template/{{cookiecutter.project_slug}}/backend/tests/test_core.py,sha256=dF_RgCNrHnI3PqhOVqqcYg_XgcDPCmkR_YWw6POCngw,5973
|
|
365
363
|
fastapi_gen/template/{{cookiecutter.project_slug}}/backend/tests/test_fetch_url.py,sha256=ZnPxBUYH6KyAWcQf1MTEQEUvb7tpDhXcmbVKRLR2Xuw,3595
|
|
366
364
|
fastapi_gen/template/{{cookiecutter.project_slug}}/backend/tests/test_kb_scoping.py,sha256=fEV6jEaPtW5oNyRBDAA_S2jHS2QyxXWmOG-EKhYD7Hk,6573
|
|
367
365
|
fastapi_gen/template/{{cookiecutter.project_slug}}/backend/tests/test_mcp_connections.py,sha256=bXtouBih2krDRw0Kb-kxvRJuHvI_5O3c-VRzCfif4Ig,34801
|
|
@@ -369,8 +367,8 @@ fastapi_gen/template/{{cookiecutter.project_slug}}/backend/tests/test_migrations
|
|
|
369
367
|
fastapi_gen/template/{{cookiecutter.project_slug}}/backend/tests/test_rbac_teams.py,sha256=ryLOK_4YMtSBfRqeVFEnvcQXoGkQEpDrX0OAsCmm-v8,7037
|
|
370
368
|
fastapi_gen/template/{{cookiecutter.project_slug}}/backend/tests/test_repositories.py,sha256=uQHtc5I5OZpWnO7rC1Y8C7uw1WZWtG_HNWwxpI2OhtM,1286
|
|
371
369
|
fastapi_gen/template/{{cookiecutter.project_slug}}/backend/tests/test_repositories_teams.py,sha256=bIvtIATkynFWyvi81zXphiVyFf1cWu6qgRiB-EQzgMo,9675
|
|
372
|
-
fastapi_gen/template/{{cookiecutter.project_slug}}/backend/tests/test_security.py,sha256=
|
|
373
|
-
fastapi_gen/template/{{cookiecutter.project_slug}}/backend/tests/test_services.py,sha256=
|
|
370
|
+
fastapi_gen/template/{{cookiecutter.project_slug}}/backend/tests/test_security.py,sha256=Hjs9Qzrqgqh2LDTurntiJhg3nNFVf5d5J5gZXyE6QwA,5615
|
|
371
|
+
fastapi_gen/template/{{cookiecutter.project_slug}}/backend/tests/test_services.py,sha256=RCjohaKjN9FR6gG7KsHf3-vm51T4XIA5ORN18vNMVbY,13067
|
|
374
372
|
fastapi_gen/template/{{cookiecutter.project_slug}}/backend/tests/test_services_conversation.py,sha256=d9cn9w86kjlxPbO1vBCECBHPIYb75S5jvcYUtU14qkU,35129
|
|
375
373
|
fastapi_gen/template/{{cookiecutter.project_slug}}/backend/tests/test_services_members.py,sha256=YTZDqwSfhZPuZIK6JSpYZa8tlr1PAvH2QpBhGxWrk-I,8812
|
|
376
374
|
fastapi_gen/template/{{cookiecutter.project_slug}}/backend/tests/test_services_organizations.py,sha256=LqguSbJVPhzVq3bHQZC37CNVF4MbQ93iDll0Vx28nV4,6277
|
|
@@ -380,11 +378,11 @@ fastapi_gen/template/{{cookiecutter.project_slug}}/backend/tests/test_tenant_iso
|
|
|
380
378
|
fastapi_gen/template/{{cookiecutter.project_slug}}/backend/tests/test_web_search.py,sha256=rGF8rftjC80Ujke0Ahw--3HfB7k2lJA5BkpPFKOKC2A,3119
|
|
381
379
|
fastapi_gen/template/{{cookiecutter.project_slug}}/backend/tests/test_worker_taskiq.py,sha256=1SsCCaZ-gBzakWdKvxRChl3PY0beocV17u8Rv1GPuUc,1557
|
|
382
380
|
fastapi_gen/template/{{cookiecutter.project_slug}}/backend/tests/api/__init__.py,sha256=WV9U5TSWbUYHVA2F3CD7gfod4RdX8EM1s4ewEnwszr0,25
|
|
383
|
-
fastapi_gen/template/{{cookiecutter.project_slug}}/backend/tests/api/test_auth.py,sha256=
|
|
384
|
-
fastapi_gen/template/{{cookiecutter.project_slug}}/backend/tests/api/test_exceptions.py,sha256=
|
|
381
|
+
fastapi_gen/template/{{cookiecutter.project_slug}}/backend/tests/api/test_auth.py,sha256=vSS2m9Z-IW-c8eOlEGcD9A9hpK6lbLMQc4AUXMcs-T0,9306
|
|
382
|
+
fastapi_gen/template/{{cookiecutter.project_slug}}/backend/tests/api/test_exceptions.py,sha256=X42FJacw5Sg32gufnNoreQOEDyPNuS3QhxtWlYRKEmQ,4657
|
|
385
383
|
fastapi_gen/template/{{cookiecutter.project_slug}}/backend/tests/api/test_health.py,sha256=OV3lPybEfyEDNrhmiCe4WMKsm8KxrXFKFBWoceDgrsc,2741
|
|
386
384
|
fastapi_gen/template/{{cookiecutter.project_slug}}/backend/tests/api/test_metrics.py,sha256=nikYPuAynnvHWSRFWsuFuqBYY3jyN5sJH2dgiONaVdA,1835
|
|
387
|
-
fastapi_gen/template/{{cookiecutter.project_slug}}/backend/tests/api/test_openapi.py,sha256=
|
|
385
|
+
fastapi_gen/template/{{cookiecutter.project_slug}}/backend/tests/api/test_openapi.py,sha256=V2HBIgRcuwk-Y7nwJK0tkKE_MtQpV6xBY66-TKRYCJk,4378
|
|
388
386
|
fastapi_gen/template/{{cookiecutter.project_slug}}/backend/tests/api/test_users.py,sha256=7QXy6Z0BflemKFtyViOIUVG3MjDpJi-FbLx4CWK9kBk,7231
|
|
389
387
|
fastapi_gen/template/{{cookiecutter.project_slug}}/docs/adding_features.md,sha256=oShZqruknW6iYaMLutNvSpXYQP3cmZGg3OuDVaxrAZY,6851
|
|
390
388
|
fastapi_gen/template/{{cookiecutter.project_slug}}/docs/architecture.md,sha256=Lg8RzpLDO9tA-zVE3lFnllnTkW-FvQwc7-XMseneTq4,11806
|
|
@@ -916,8 +914,8 @@ fastapi_gen/template/{{cookiecutter.project_slug}}/kubernetes/service.yaml,sha25
|
|
|
916
914
|
fastapi_gen/template/{{cookiecutter.project_slug}}/nginx/nginx.conf,sha256=2bWaxnv_rN4driEdtWgVz9eVfoKhB_Ohd_G8eOC3P3M,7619
|
|
917
915
|
fastapi_gen/template/{{cookiecutter.project_slug}}/nginx/ssl/.gitkeep,sha256=o_WQQOgVGOLttT48x0EXSC4BbbDFemApFpmwhybcVUU,617
|
|
918
916
|
fastapi_gen/template/{{cookiecutter.project_slug}}/scripts/export_demo_html.py,sha256=H1tbIfr1xrh2pRuoy5NwvAOYEu0S2vgnw_XsKNMKXeM,10414
|
|
919
|
-
fastapi_fullstack-0.2.
|
|
920
|
-
fastapi_fullstack-0.2.
|
|
921
|
-
fastapi_fullstack-0.2.
|
|
922
|
-
fastapi_fullstack-0.2.
|
|
923
|
-
fastapi_fullstack-0.2.
|
|
917
|
+
fastapi_fullstack-0.2.19.dist-info/METADATA,sha256=8uC2UYeJGbN1opmjhuTxoVSVBm_c9qNedB1KbtGd2mM,60801
|
|
918
|
+
fastapi_fullstack-0.2.19.dist-info/WHEEL,sha256=lCkmxWfQsSc9CfIClYeavTdQeEX2toPqufh9gI35EQA,87
|
|
919
|
+
fastapi_fullstack-0.2.19.dist-info/entry_points.txt,sha256=s9JXrISZp8LMYJGeVofOAd1wPTzpq-jwjSgSf4hWzjs,59
|
|
920
|
+
fastapi_fullstack-0.2.19.dist-info/licenses/LICENSE,sha256=bL4JuK_rcA8y__Gg7PEuTs3g2Qf6VvSz2w2Jajd6nVU,1063
|
|
921
|
+
fastapi_fullstack-0.2.19.dist-info/RECORD,,
|
fastapi_gen/UPGRADES.yaml
CHANGED
|
@@ -18,6 +18,22 @@
|
|
|
18
18
|
# manual_steps:
|
|
19
19
|
# - "Run `alembic upgrade head` (new billing tables)."
|
|
20
20
|
|
|
21
|
+
- version: "0.2.19"
|
|
22
|
+
removed:
|
|
23
|
+
- "backend/app/core/rate_limit.py"
|
|
24
|
+
- "backend/app/core/csrf.py"
|
|
25
|
+
- "backend/app/api/versioning.py"
|
|
26
|
+
breaking:
|
|
27
|
+
- "Delegated auth (--auth-mode delegated) no longer generates the local credential endpoints: /auth/login, /auth/register, /auth/refresh, /auth/logout and the password-reset and magic-link routes. Only /auth/me remains. Any client calling them against a delegated deployment was receiving tokens that get_current_user rejects."
|
|
28
|
+
- "create_password_reset_token(subject) now requires current_password_hash, and create_magic_link_token(subject) requires magic_link_epoch. Both bind the token to state that changes on redemption, which is what makes the link single-use. Custom callers must pass the new argument."
|
|
29
|
+
- "The slowapi limiter in core/rate_limit.py is gone. It was never attached to a route and enforced nothing. Rate limits now come from services/rate_limit via make_rate_limit_dep / make_anonymous_rate_limit_dep, and slowapi is no longer a dependency."
|
|
30
|
+
manual_steps:
|
|
31
|
+
- "Run `alembic upgrade head` — 0027 adds users.magic_link_epoch, which the single-use magic-link check reads. Without it, sign-in-by-email raises on every attempt."
|
|
32
|
+
- "Rate limiting is now actually enforced on /auth/login, /auth/register and the password-reset and magic-link request endpoints (default: 5 per 15 minutes per IP). Load tests and smoke scripts that hammer login will start seeing 429s. Override per plan via the plan's features.rate_limits, or adjust DEFAULT_RATE_LIMITS in backend/app/services/rate_limit/rules.py."
|
|
33
|
+
- "If you generated with --rate-limiting and no Redis, limits are counted per worker process, so the effective limit is multiplied by your worker count. Enable Redis for a shared window."
|
|
34
|
+
- "Custom routes that need a limit: add `dependencies=[make_rate_limit_dep(RateLimitCategory.X)]` (authenticated) or `make_anonymous_rate_limit_dep` (pre-auth). Nothing is limited by default beyond the auth endpoints."
|
|
35
|
+
- "If you wired app.state.limiter or @limiter.limit from core/rate_limit.py yourself, those imports are now dead — port them to make_rate_limit_dep."
|
|
36
|
+
|
|
21
37
|
- version: "0.2.18"
|
|
22
38
|
manual_steps:
|
|
23
39
|
- "Rebuild the frontend image: `docker compose -f docker-compose.prod.yml build --no-cache frontend`. NEXT_PUBLIC_* is inlined into the browser bundle at build time and now comes from compose build args, so an image built before this upgrade still has the old ws://localhost URL baked in."
|
fastapi_gen/prompts.py
CHANGED
|
@@ -342,7 +342,6 @@ if not enable_caching:
|
|
|
342
342
|
remove_file(os.path.join(backend_app, "core", "cache.py"))
|
|
343
343
|
|
|
344
344
|
if not enable_rate_limiting:
|
|
345
|
-
remove_file(os.path.join(backend_app, "core", "rate_limit.py"))
|
|
346
345
|
remove_dir(os.path.join(backend_app, "services", "rate_limit"))
|
|
347
346
|
|
|
348
347
|
if not enable_oauth:
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
{%- if cookiecutter.enable_email %}
|
|
2
|
+
"""add users.magic_link_epoch
|
|
3
|
+
|
|
4
|
+
Revision ID: 0027_user_magic_link_epoch
|
|
5
|
+
Revises: 0026_create_mcp_connections
|
|
6
|
+
Create Date: {{ cookiecutter.generated_at }}
|
|
7
|
+
|
|
8
|
+
Magic-link sign-in tokens are JWTs, so they cannot be revoked. Each issued
|
|
9
|
+
link carries the epoch in force at issue time; redeeming one bumps the epoch,
|
|
10
|
+
which invalidates that link and every other link outstanding for the user.
|
|
11
|
+
Without this a leaked sign-in link stays usable for its whole TTL, and stays
|
|
12
|
+
usable after the legitimate user has already signed in with it.
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
import sqlalchemy as sa
|
|
16
|
+
|
|
17
|
+
from alembic import op
|
|
18
|
+
|
|
19
|
+
revision = "0027_user_magic_link_epoch"
|
|
20
|
+
down_revision = "0026_create_mcp_connections"
|
|
21
|
+
branch_labels = None
|
|
22
|
+
depends_on = None
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def upgrade() -> None:
|
|
26
|
+
op.add_column(
|
|
27
|
+
"users",
|
|
28
|
+
sa.Column("magic_link_epoch", sa.Integer(), nullable=False, server_default="0"),
|
|
29
|
+
)
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def downgrade() -> None:
|
|
33
|
+
op.drop_column("users", "magic_link_epoch")
|
|
34
|
+
{%- else %}
|
|
35
|
+
"""add users.magic_link_epoch — skipped (enable_email=false)
|
|
36
|
+
|
|
37
|
+
Revision ID: 0027_user_magic_link_epoch
|
|
38
|
+
|
|
39
|
+
No-op placeholder so the revision chain stays linear when email (and therefore
|
|
40
|
+
magic-link sign-in) is disabled.
|
|
41
|
+
"""
|
|
42
|
+
|
|
43
|
+
revision = "0027_user_magic_link_epoch"
|
|
44
|
+
down_revision = "0026_create_mcp_connections"
|
|
45
|
+
branch_labels = None
|
|
46
|
+
depends_on = None
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def upgrade() -> None:
|
|
50
|
+
pass
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
def downgrade() -> None:
|
|
54
|
+
pass
|
|
55
|
+
{%- endif %}
|
|
@@ -301,7 +301,19 @@ def get_sync_engine() -> Engine:
|
|
|
301
301
|
class AdminAuth(AuthenticationBackend):
|
|
302
302
|
"""Admin panel authentication backend.
|
|
303
303
|
|
|
304
|
-
Requires
|
|
304
|
+
Requires app-admin credentials to access the admin panel. Note this is a
|
|
305
|
+
*local* password check — it does not consult any external IdP, so it must
|
|
306
|
+
never be the only thing standing between a self-registered account and the
|
|
307
|
+
database. Both conditions below matter:
|
|
308
|
+
|
|
309
|
+
- ``is_app_admin`` — the explicit admin flag, not just the ``role`` column,
|
|
310
|
+
so a row that acquired ``role=admin`` some other way is not enough.
|
|
311
|
+
{%- if cookiecutter.use_delegated_auth %}
|
|
312
|
+
- ``external_user_id`` — the row must correspond to a real IdP identity.
|
|
313
|
+
Under delegated auth the local ``/auth/register`` endpoint is not
|
|
314
|
+
generated, so no unlinked row should exist; this check makes that
|
|
315
|
+
guarantee local instead of relying on a route elsewhere staying absent.
|
|
316
|
+
{%- endif %}
|
|
305
317
|
"""
|
|
306
318
|
|
|
307
319
|
async def login(self, request: Request) -> bool:
|
|
@@ -321,9 +333,14 @@ class AdminAuth(AuthenticationBackend):
|
|
|
321
333
|
|
|
322
334
|
if (
|
|
323
335
|
user
|
|
336
|
+
and user.is_active
|
|
324
337
|
and user.hashed_password
|
|
325
338
|
and verify_password(password, user.hashed_password)
|
|
326
339
|
and user.has_role(UserRole.ADMIN)
|
|
340
|
+
and getattr(user, "is_app_admin", False)
|
|
341
|
+
{%- if cookiecutter.use_delegated_auth %}
|
|
342
|
+
and user.external_user_id is not None
|
|
343
|
+
{%- endif %}
|
|
327
344
|
):
|
|
328
345
|
request.session["admin_user_id"] = str(user.id)
|
|
329
346
|
request.session["admin_email"] = user.email
|
|
@@ -344,7 +361,12 @@ class AdminAuth(AuthenticationBackend):
|
|
|
344
361
|
|
|
345
362
|
with DBSession(get_sync_engine()) as session:
|
|
346
363
|
user = session.query(User).filter(User.id == admin_user_id).first()
|
|
347
|
-
if
|
|
364
|
+
if (
|
|
365
|
+
user
|
|
366
|
+
and user.is_active
|
|
367
|
+
and user.has_role(UserRole.ADMIN)
|
|
368
|
+
and getattr(user, "is_app_admin", False)
|
|
369
|
+
):
|
|
348
370
|
return True
|
|
349
371
|
|
|
350
372
|
request.session.clear()
|
|
@@ -512,6 +512,11 @@ async def get_current_user_ws(
|
|
|
512
512
|
Tokens in query strings are NOT accepted — they leak into logs and
|
|
513
513
|
Referer headers.
|
|
514
514
|
|
|
515
|
+
The token is validated by the same authority as ``get_current_user``: the
|
|
516
|
+
IdP's keys under delegated auth, this backend's ``SECRET_KEY`` otherwise.
|
|
517
|
+
The two must not diverge — a WebSocket that trusts a different issuer than
|
|
518
|
+
the REST API is an authentication bypass on whichever side is weaker.
|
|
519
|
+
|
|
515
520
|
Raises:
|
|
516
521
|
WebSocketException: If token is invalid or user not found. Raising the
|
|
517
522
|
WebSocket-native exception lets Starlette close the handshake cleanly
|
|
@@ -527,6 +532,35 @@ async def get_current_user_ws(
|
|
|
527
532
|
if not auth_token:
|
|
528
533
|
raise WebSocketException(code=4001, reason="Missing authentication token")
|
|
529
534
|
|
|
535
|
+
{%- if cookiecutter.use_delegated_auth %}
|
|
536
|
+
payload = verify_idp_token(auth_token)
|
|
537
|
+
if payload is None:
|
|
538
|
+
raise WebSocketException(code=4001, reason="Invalid or expired token")
|
|
539
|
+
|
|
540
|
+
# No `type` check here: an external IdP does not mint our access/refresh
|
|
541
|
+
# distinction. The audience and issuer checks in verify_idp_token are what
|
|
542
|
+
# constrain which tokens this API accepts.
|
|
543
|
+
external_id = payload.get(settings.IDP_USER_ID_CLAIM)
|
|
544
|
+
if not external_id:
|
|
545
|
+
raise WebSocketException(code=4001, reason="Invalid token payload")
|
|
546
|
+
|
|
547
|
+
async with get_db_context() as db:
|
|
548
|
+
user_service = UserService(db)
|
|
549
|
+
user = await user_service.get_or_create_from_idp(
|
|
550
|
+
external_user_id=str(external_id),
|
|
551
|
+
email=payload.get(settings.IDP_EMAIL_CLAIM) or f"{external_id}@idp.local",
|
|
552
|
+
full_name=payload.get(settings.IDP_NAME_CLAIM),
|
|
553
|
+
)
|
|
554
|
+
|
|
555
|
+
if not user.is_active:
|
|
556
|
+
raise WebSocketException(code=4001, reason="User account is disabled")
|
|
557
|
+
|
|
558
|
+
# Eagerly load all columns, then detach from session to avoid
|
|
559
|
+
# "instance not bound to a Session" errors after the context manager exits
|
|
560
|
+
await db.refresh(user)
|
|
561
|
+
db.expunge(user)
|
|
562
|
+
return user
|
|
563
|
+
{%- else %}
|
|
530
564
|
payload = verify_token(auth_token)
|
|
531
565
|
if payload is None:
|
|
532
566
|
raise WebSocketException(code=4001, reason="Invalid or expired token")
|
|
@@ -553,6 +587,7 @@ async def get_current_user_ws(
|
|
|
553
587
|
await db.refresh(user)
|
|
554
588
|
db.expunge(user)
|
|
555
589
|
return user
|
|
590
|
+
{%- endif %}
|
|
556
591
|
|
|
557
592
|
|
|
558
593
|
CurrentUserWS = Annotated[User, Depends(get_current_user_ws)]
|
|
@@ -639,18 +674,34 @@ def get_vectorstore(request: Request, embedder: EmbeddingSvc) -> BaseVectorStore
|
|
|
639
674
|
|
|
640
675
|
VectorStoreSvc = Annotated[BaseVectorStore, Depends(get_vectorstore)]
|
|
641
676
|
|
|
642
|
-
|
|
677
|
+
{%- if cookiecutter.enable_reranker %}
|
|
678
|
+
def get_rerank_service(request: Request) -> RerankService:
|
|
679
|
+
"""Get the reranker warmed at startup, or build one if warmup failed.
|
|
680
|
+
|
|
681
|
+
Reusing the lifespan instance is not an optimisation — a cross-encoder
|
|
682
|
+
reranker holds its model on the instance and loads it lazily, so a
|
|
683
|
+
per-request service reloads the model inside the request.
|
|
684
|
+
"""
|
|
685
|
+
if hasattr(request.state, "rerank_service"):
|
|
686
|
+
return request.state.rerank_service # type: ignore[no-any-return]
|
|
687
|
+
return RerankService(settings=settings.rag)
|
|
688
|
+
|
|
689
|
+
RerankSvc = Annotated[RerankService, Depends(get_rerank_service)]
|
|
690
|
+
|
|
691
|
+
def get_retrieval_service(
|
|
692
|
+
vector_store: VectorStoreSvc, rerank_service: RerankSvc
|
|
693
|
+
) -> RetrievalService:
|
|
643
694
|
"""Create RetrievalService instance."""
|
|
644
|
-
{%- if cookiecutter.enable_reranker %}
|
|
645
|
-
rerank_service = RerankService(settings=settings.rag)
|
|
646
695
|
return RetrievalService(
|
|
647
696
|
vector_store=vector_store,
|
|
648
697
|
settings=settings.rag,
|
|
649
698
|
rerank_service=rerank_service,
|
|
650
699
|
)
|
|
651
|
-
|
|
700
|
+
{%- else %}
|
|
701
|
+
def get_retrieval_service(vector_store: VectorStoreSvc) -> RetrievalService:
|
|
702
|
+
"""Create RetrievalService instance."""
|
|
652
703
|
return RetrievalService(vector_store=vector_store, settings=settings.rag)
|
|
653
|
-
|
|
704
|
+
{%- endif %}
|
|
654
705
|
|
|
655
706
|
RetrievalSvc = Annotated[RetrievalService, Depends(get_retrieval_service)]
|
|
656
707
|
|