vibetuner 2.7.0__py3-none-any.whl → 2.18.1__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.
Potentially problematic release.
This version of vibetuner might be problematic. Click here for more details.
- vibetuner/cli/__init__.py +13 -2
- vibetuner/cli/run.py +0 -1
- vibetuner/cli/scaffold.py +187 -0
- vibetuner/config.py +27 -11
- vibetuner/context.py +3 -0
- vibetuner/frontend/__init__.py +7 -2
- vibetuner/frontend/lifespan.py +12 -7
- vibetuner/frontend/middleware.py +3 -3
- vibetuner/frontend/routes/auth.py +19 -13
- vibetuner/frontend/routes/debug.py +1 -1
- vibetuner/frontend/routes/health.py +4 -0
- vibetuner/frontend/routes/user.py +1 -1
- vibetuner/mongo.py +1 -1
- vibetuner/paths.py +197 -80
- vibetuner/tasks/worker.py +1 -1
- vibetuner/templates/email/{default/magic_link.html.jinja → magic_link.html.jinja} +2 -1
- vibetuner/templates/frontend/base/favicons.html.jinja +1 -1
- vibetuner/templates/frontend/base/skeleton.html.jinja +5 -2
- vibetuner/templates/frontend/debug/collections.html.jinja +2 -0
- vibetuner/templates/frontend/debug/components/debug_nav.html.jinja +6 -6
- vibetuner/templates/frontend/debug/index.html.jinja +6 -4
- vibetuner/templates/frontend/debug/info.html.jinja +2 -0
- vibetuner/templates/frontend/debug/users.html.jinja +4 -2
- vibetuner/templates/frontend/debug/version.html.jinja +2 -0
- vibetuner/templates/frontend/email_sent.html.jinja +2 -1
- vibetuner/templates/frontend/index.html.jinja +1 -0
- vibetuner/templates/frontend/login.html.jinja +8 -3
- vibetuner/templates/frontend/user/edit.html.jinja +3 -2
- vibetuner/templates/frontend/user/profile.html.jinja +2 -1
- vibetuner/templates.py +9 -15
- vibetuner/versioning.py +1 -1
- vibetuner-2.18.1.dist-info/METADATA +241 -0
- vibetuner-2.18.1.dist-info/RECORD +72 -0
- {vibetuner-2.7.0.dist-info → vibetuner-2.18.1.dist-info}/WHEEL +1 -1
- vibetuner-2.18.1.dist-info/entry_points.txt +3 -0
- vibetuner/frontend/AGENTS.md +0 -113
- vibetuner/frontend/CLAUDE.md +0 -113
- vibetuner/models/AGENTS.md +0 -165
- vibetuner/models/CLAUDE.md +0 -165
- vibetuner/services/AGENTS.md +0 -104
- vibetuner/services/CLAUDE.md +0 -104
- vibetuner/tasks/AGENTS.md +0 -98
- vibetuner/tasks/CLAUDE.md +0 -98
- vibetuner/templates/email/AGENTS.md +0 -48
- vibetuner/templates/email/CLAUDE.md +0 -48
- vibetuner/templates/frontend/AGENTS.md +0 -74
- vibetuner/templates/frontend/CLAUDE.md +0 -74
- vibetuner/templates/markdown/AGENTS.md +0 -29
- vibetuner/templates/markdown/CLAUDE.md +0 -29
- vibetuner-2.7.0.dist-info/METADATA +0 -48
- vibetuner-2.7.0.dist-info/RECORD +0 -84
- /vibetuner/templates/email/{default/magic_link.txt.jinja → magic_link.txt.jinja} +0 -0
vibetuner/models/AGENTS.md
DELETED
|
@@ -1,165 +0,0 @@
|
|
|
1
|
-
# Core Models Module
|
|
2
|
-
|
|
3
|
-
**IMMUTABLE SCAFFOLDING CODE** - These are the framework's core models that provide essential functionality.
|
|
4
|
-
|
|
5
|
-
## What's Here
|
|
6
|
-
|
|
7
|
-
This module contains the scaffolding's core models:
|
|
8
|
-
|
|
9
|
-
- **UserModel** - Base user model with authentication support
|
|
10
|
-
- **OAuthAccountModel** - OAuth provider account linking
|
|
11
|
-
- **EmailVerificationTokenModel** - Magic link authentication tokens
|
|
12
|
-
- **BlobModel** - File storage and blob management
|
|
13
|
-
- **Mixins** - Reusable model behaviors (TimeStampMixin, etc.)
|
|
14
|
-
- **Types** - Common field types and validators
|
|
15
|
-
|
|
16
|
-
## Important Rules
|
|
17
|
-
|
|
18
|
-
⚠️ **DO NOT MODIFY** these core models directly.
|
|
19
|
-
|
|
20
|
-
**For changes to core models:**
|
|
21
|
-
|
|
22
|
-
- File an issue at `https://github.com/alltuner/scaffolding`
|
|
23
|
-
- Core changes benefit all projects using the scaffolding
|
|
24
|
-
|
|
25
|
-
**For your application models:**
|
|
26
|
-
|
|
27
|
-
- Create them in `src/app/models/` instead
|
|
28
|
-
- Import core models when needed: `from vibetuner.models import UserModel`
|
|
29
|
-
- Use mixins from here: `from vibetuner.models.mixins import TimeStampMixin`
|
|
30
|
-
|
|
31
|
-
## User Model Pattern (for reference)
|
|
32
|
-
|
|
33
|
-
Your application models in `src/app/models/` should follow this pattern:
|
|
34
|
-
|
|
35
|
-
```python
|
|
36
|
-
from beanie import Document
|
|
37
|
-
from pydantic import Field
|
|
38
|
-
from vibetuner.models.mixins import TimeStampMixin
|
|
39
|
-
|
|
40
|
-
class Product(Document, TimeStampMixin):
|
|
41
|
-
name: str
|
|
42
|
-
price: float = Field(gt=0)
|
|
43
|
-
stock: int = Field(ge=0)
|
|
44
|
-
|
|
45
|
-
class Settings:
|
|
46
|
-
name = "products"
|
|
47
|
-
indexes = ["name"]
|
|
48
|
-
```
|
|
49
|
-
|
|
50
|
-
## Available Mixins
|
|
51
|
-
|
|
52
|
-
### TimeStampMixin
|
|
53
|
-
|
|
54
|
-
Automatic timestamps for all models:
|
|
55
|
-
|
|
56
|
-
- `db_insert_dt` - Created at (UTC)
|
|
57
|
-
- `db_update_dt` - Updated at (UTC)
|
|
58
|
-
- Methods: `age()`, `age_in()`, `is_older_than()`
|
|
59
|
-
|
|
60
|
-
Import in your app models:
|
|
61
|
-
|
|
62
|
-
```python
|
|
63
|
-
from vibetuner.models.mixins import TimeStampMixin
|
|
64
|
-
```
|
|
65
|
-
|
|
66
|
-
## Queries
|
|
67
|
-
|
|
68
|
-
### Finding Documents
|
|
69
|
-
|
|
70
|
-
```python
|
|
71
|
-
from beanie.operators import Eq, In, Gt, Lt
|
|
72
|
-
|
|
73
|
-
# By ID (preferred method)
|
|
74
|
-
product = await Product.get(product_id)
|
|
75
|
-
|
|
76
|
-
# By field (use Beanie operators)
|
|
77
|
-
product = await Product.find_one(Eq(Product.name, "Widget"))
|
|
78
|
-
products = await Product.find(Lt(Product.price, 100)).to_list()
|
|
79
|
-
|
|
80
|
-
# Multiple conditions
|
|
81
|
-
results = await Product.find(
|
|
82
|
-
Eq(Product.category, "electronics"),
|
|
83
|
-
Gt(Product.price, 50)
|
|
84
|
-
).to_list()
|
|
85
|
-
|
|
86
|
-
# With In operator
|
|
87
|
-
products = await Product.find(
|
|
88
|
-
In(Product.category, ["electronics", "gadgets"])
|
|
89
|
-
).to_list()
|
|
90
|
-
```
|
|
91
|
-
|
|
92
|
-
### Save/Delete
|
|
93
|
-
|
|
94
|
-
```python
|
|
95
|
-
# Create
|
|
96
|
-
product = Product(name="Widget", price=9.99, stock=100)
|
|
97
|
-
await product.insert()
|
|
98
|
-
|
|
99
|
-
# Update
|
|
100
|
-
product.price = 19.99
|
|
101
|
-
await product.save()
|
|
102
|
-
|
|
103
|
-
# Delete
|
|
104
|
-
await product.delete()
|
|
105
|
-
```
|
|
106
|
-
|
|
107
|
-
### Aggregation
|
|
108
|
-
|
|
109
|
-
```python
|
|
110
|
-
results = await Product.aggregate([
|
|
111
|
-
{"$match": {"price": {"$gt": 50}}},
|
|
112
|
-
{"$group": {"_id": "$category", "total": {"$sum": 1}}}
|
|
113
|
-
]).to_list()
|
|
114
|
-
```
|
|
115
|
-
|
|
116
|
-
## Indexes
|
|
117
|
-
|
|
118
|
-
```python
|
|
119
|
-
from pymongo import IndexModel, TEXT
|
|
120
|
-
|
|
121
|
-
class Settings:
|
|
122
|
-
indexes = [
|
|
123
|
-
"field_name", # Simple index
|
|
124
|
-
[("field1", 1), ("field2", -1)], # Compound index
|
|
125
|
-
IndexModel([("text_field", TEXT)]) # Text search
|
|
126
|
-
]
|
|
127
|
-
```
|
|
128
|
-
|
|
129
|
-
## Relationships
|
|
130
|
-
|
|
131
|
-
```python
|
|
132
|
-
from beanie import Link
|
|
133
|
-
|
|
134
|
-
class Order(Document):
|
|
135
|
-
user: Link[User]
|
|
136
|
-
products: list[Link[Product]]
|
|
137
|
-
|
|
138
|
-
# Fetch with relations
|
|
139
|
-
order = await Order.get(order_id, fetch_links=True)
|
|
140
|
-
print(order.user.email) # Automatically loaded
|
|
141
|
-
```
|
|
142
|
-
|
|
143
|
-
## Extending Core Models
|
|
144
|
-
|
|
145
|
-
If you need to add fields to User or other core models:
|
|
146
|
-
|
|
147
|
-
1. **Option A**: File an issue at `https://github.com/alltuner/scaffolding` for widely useful fields
|
|
148
|
-
2. **Option B**: Create a related model in `src/app/models/` that links to the core model:
|
|
149
|
-
|
|
150
|
-
```python
|
|
151
|
-
from beanie import Document, Link
|
|
152
|
-
from vibetuner.models import UserModel
|
|
153
|
-
|
|
154
|
-
class UserProfile(Document):
|
|
155
|
-
user: Link[UserModel]
|
|
156
|
-
bio: str
|
|
157
|
-
avatar_url: str
|
|
158
|
-
|
|
159
|
-
class Settings:
|
|
160
|
-
name = "user_profiles"
|
|
161
|
-
```
|
|
162
|
-
|
|
163
|
-
## MongoDB MCP
|
|
164
|
-
|
|
165
|
-
Claude Code has MongoDB MCP access for database operations, queries, and debugging.
|
vibetuner/models/CLAUDE.md
DELETED
|
@@ -1,165 +0,0 @@
|
|
|
1
|
-
# Core Models Module
|
|
2
|
-
|
|
3
|
-
**IMMUTABLE SCAFFOLDING CODE** - These are the framework's core models that provide essential functionality.
|
|
4
|
-
|
|
5
|
-
## What's Here
|
|
6
|
-
|
|
7
|
-
This module contains the scaffolding's core models:
|
|
8
|
-
|
|
9
|
-
- **UserModel** - Base user model with authentication support
|
|
10
|
-
- **OAuthAccountModel** - OAuth provider account linking
|
|
11
|
-
- **EmailVerificationTokenModel** - Magic link authentication tokens
|
|
12
|
-
- **BlobModel** - File storage and blob management
|
|
13
|
-
- **Mixins** - Reusable model behaviors (TimeStampMixin, etc.)
|
|
14
|
-
- **Types** - Common field types and validators
|
|
15
|
-
|
|
16
|
-
## Important Rules
|
|
17
|
-
|
|
18
|
-
⚠️ **DO NOT MODIFY** these core models directly.
|
|
19
|
-
|
|
20
|
-
**For changes to core models:**
|
|
21
|
-
|
|
22
|
-
- File an issue at `https://github.com/alltuner/scaffolding`
|
|
23
|
-
- Core changes benefit all projects using the scaffolding
|
|
24
|
-
|
|
25
|
-
**For your application models:**
|
|
26
|
-
|
|
27
|
-
- Create them in `src/app/models/` instead
|
|
28
|
-
- Import core models when needed: `from vibetuner.models import UserModel`
|
|
29
|
-
- Use mixins from here: `from vibetuner.models.mixins import TimeStampMixin`
|
|
30
|
-
|
|
31
|
-
## User Model Pattern (for reference)
|
|
32
|
-
|
|
33
|
-
Your application models in `src/app/models/` should follow this pattern:
|
|
34
|
-
|
|
35
|
-
```python
|
|
36
|
-
from beanie import Document
|
|
37
|
-
from pydantic import Field
|
|
38
|
-
from vibetuner.models.mixins import TimeStampMixin
|
|
39
|
-
|
|
40
|
-
class Product(Document, TimeStampMixin):
|
|
41
|
-
name: str
|
|
42
|
-
price: float = Field(gt=0)
|
|
43
|
-
stock: int = Field(ge=0)
|
|
44
|
-
|
|
45
|
-
class Settings:
|
|
46
|
-
name = "products"
|
|
47
|
-
indexes = ["name"]
|
|
48
|
-
```
|
|
49
|
-
|
|
50
|
-
## Available Mixins
|
|
51
|
-
|
|
52
|
-
### TimeStampMixin
|
|
53
|
-
|
|
54
|
-
Automatic timestamps for all models:
|
|
55
|
-
|
|
56
|
-
- `db_insert_dt` - Created at (UTC)
|
|
57
|
-
- `db_update_dt` - Updated at (UTC)
|
|
58
|
-
- Methods: `age()`, `age_in()`, `is_older_than()`
|
|
59
|
-
|
|
60
|
-
Import in your app models:
|
|
61
|
-
|
|
62
|
-
```python
|
|
63
|
-
from vibetuner.models.mixins import TimeStampMixin
|
|
64
|
-
```
|
|
65
|
-
|
|
66
|
-
## Queries
|
|
67
|
-
|
|
68
|
-
### Finding Documents
|
|
69
|
-
|
|
70
|
-
```python
|
|
71
|
-
from beanie.operators import Eq, In, Gt, Lt
|
|
72
|
-
|
|
73
|
-
# By ID (preferred method)
|
|
74
|
-
product = await Product.get(product_id)
|
|
75
|
-
|
|
76
|
-
# By field (use Beanie operators)
|
|
77
|
-
product = await Product.find_one(Eq(Product.name, "Widget"))
|
|
78
|
-
products = await Product.find(Lt(Product.price, 100)).to_list()
|
|
79
|
-
|
|
80
|
-
# Multiple conditions
|
|
81
|
-
results = await Product.find(
|
|
82
|
-
Eq(Product.category, "electronics"),
|
|
83
|
-
Gt(Product.price, 50)
|
|
84
|
-
).to_list()
|
|
85
|
-
|
|
86
|
-
# With In operator
|
|
87
|
-
products = await Product.find(
|
|
88
|
-
In(Product.category, ["electronics", "gadgets"])
|
|
89
|
-
).to_list()
|
|
90
|
-
```
|
|
91
|
-
|
|
92
|
-
### Save/Delete
|
|
93
|
-
|
|
94
|
-
```python
|
|
95
|
-
# Create
|
|
96
|
-
product = Product(name="Widget", price=9.99, stock=100)
|
|
97
|
-
await product.insert()
|
|
98
|
-
|
|
99
|
-
# Update
|
|
100
|
-
product.price = 19.99
|
|
101
|
-
await product.save()
|
|
102
|
-
|
|
103
|
-
# Delete
|
|
104
|
-
await product.delete()
|
|
105
|
-
```
|
|
106
|
-
|
|
107
|
-
### Aggregation
|
|
108
|
-
|
|
109
|
-
```python
|
|
110
|
-
results = await Product.aggregate([
|
|
111
|
-
{"$match": {"price": {"$gt": 50}}},
|
|
112
|
-
{"$group": {"_id": "$category", "total": {"$sum": 1}}}
|
|
113
|
-
]).to_list()
|
|
114
|
-
```
|
|
115
|
-
|
|
116
|
-
## Indexes
|
|
117
|
-
|
|
118
|
-
```python
|
|
119
|
-
from pymongo import IndexModel, TEXT
|
|
120
|
-
|
|
121
|
-
class Settings:
|
|
122
|
-
indexes = [
|
|
123
|
-
"field_name", # Simple index
|
|
124
|
-
[("field1", 1), ("field2", -1)], # Compound index
|
|
125
|
-
IndexModel([("text_field", TEXT)]) # Text search
|
|
126
|
-
]
|
|
127
|
-
```
|
|
128
|
-
|
|
129
|
-
## Relationships
|
|
130
|
-
|
|
131
|
-
```python
|
|
132
|
-
from beanie import Link
|
|
133
|
-
|
|
134
|
-
class Order(Document):
|
|
135
|
-
user: Link[User]
|
|
136
|
-
products: list[Link[Product]]
|
|
137
|
-
|
|
138
|
-
# Fetch with relations
|
|
139
|
-
order = await Order.get(order_id, fetch_links=True)
|
|
140
|
-
print(order.user.email) # Automatically loaded
|
|
141
|
-
```
|
|
142
|
-
|
|
143
|
-
## Extending Core Models
|
|
144
|
-
|
|
145
|
-
If you need to add fields to User or other core models:
|
|
146
|
-
|
|
147
|
-
1. **Option A**: File an issue at `https://github.com/alltuner/scaffolding` for widely useful fields
|
|
148
|
-
2. **Option B**: Create a related model in `src/app/models/` that links to the core model:
|
|
149
|
-
|
|
150
|
-
```python
|
|
151
|
-
from beanie import Document, Link
|
|
152
|
-
from vibetuner.models import UserModel
|
|
153
|
-
|
|
154
|
-
class UserProfile(Document):
|
|
155
|
-
user: Link[UserModel]
|
|
156
|
-
bio: str
|
|
157
|
-
avatar_url: str
|
|
158
|
-
|
|
159
|
-
class Settings:
|
|
160
|
-
name = "user_profiles"
|
|
161
|
-
```
|
|
162
|
-
|
|
163
|
-
## MongoDB MCP
|
|
164
|
-
|
|
165
|
-
Claude Code has MongoDB MCP access for database operations, queries, and debugging.
|
vibetuner/services/AGENTS.md
DELETED
|
@@ -1,104 +0,0 @@
|
|
|
1
|
-
# Core Services Module
|
|
2
|
-
|
|
3
|
-
**IMMUTABLE SCAFFOLDING CODE** - These are the framework's core services that provide essential functionality.
|
|
4
|
-
|
|
5
|
-
## What's Here
|
|
6
|
-
|
|
7
|
-
This module contains the scaffolding's core services:
|
|
8
|
-
|
|
9
|
-
- **email.py** - Email sending via AWS SES
|
|
10
|
-
- **blob.py** - File storage and blob management
|
|
11
|
-
|
|
12
|
-
## Important Rules
|
|
13
|
-
|
|
14
|
-
⚠️ **DO NOT MODIFY** these core services directly.
|
|
15
|
-
|
|
16
|
-
**For changes to core services:**
|
|
17
|
-
|
|
18
|
-
- File an issue at `https://github.com/alltuner/scaffolding`
|
|
19
|
-
- Core changes benefit all projects using the scaffolding
|
|
20
|
-
|
|
21
|
-
**For your application services:**
|
|
22
|
-
|
|
23
|
-
- Create them in `src/app/services/` instead
|
|
24
|
-
- Import core services when needed: `from vibetuner.services.email import send_email`
|
|
25
|
-
|
|
26
|
-
## User Service Pattern (for reference)
|
|
27
|
-
|
|
28
|
-
Your application services in `src/app/services/` should follow this pattern:
|
|
29
|
-
|
|
30
|
-
```python
|
|
31
|
-
from vibetuner.models import UserModel
|
|
32
|
-
|
|
33
|
-
class NotificationService:
|
|
34
|
-
async def send_notification(
|
|
35
|
-
self,
|
|
36
|
-
user: UserModel,
|
|
37
|
-
message: str,
|
|
38
|
-
priority: str = "normal"
|
|
39
|
-
) -> bool:
|
|
40
|
-
# Implementation
|
|
41
|
-
return True
|
|
42
|
-
|
|
43
|
-
# Singleton
|
|
44
|
-
notification_service = NotificationService()
|
|
45
|
-
```
|
|
46
|
-
|
|
47
|
-
## Using Core Services
|
|
48
|
-
|
|
49
|
-
### Email Service
|
|
50
|
-
|
|
51
|
-
```python
|
|
52
|
-
from vibetuner.services.email import send_email
|
|
53
|
-
|
|
54
|
-
await send_email(
|
|
55
|
-
to_email="user@example.com",
|
|
56
|
-
subject="Welcome",
|
|
57
|
-
html_content="<h1>Welcome!</h1>",
|
|
58
|
-
text_content="Welcome!"
|
|
59
|
-
)
|
|
60
|
-
```
|
|
61
|
-
|
|
62
|
-
### Blob Service
|
|
63
|
-
|
|
64
|
-
```python
|
|
65
|
-
from vibetuner.services.blob import blob_service
|
|
66
|
-
|
|
67
|
-
# Upload file
|
|
68
|
-
blob = await blob_service.upload(file_data, "image.png")
|
|
69
|
-
|
|
70
|
-
# Get file URL
|
|
71
|
-
url = await blob_service.get_url(blob.id)
|
|
72
|
-
```
|
|
73
|
-
|
|
74
|
-
## Creating Your Own Services
|
|
75
|
-
|
|
76
|
-
Place your application services in `src/app/services/`:
|
|
77
|
-
|
|
78
|
-
```python
|
|
79
|
-
# src/app/services/external_api.py
|
|
80
|
-
import httpx
|
|
81
|
-
|
|
82
|
-
async def call_api(api_url: str, api_key: str, data: dict) -> dict:
|
|
83
|
-
async with httpx.AsyncClient() as client:
|
|
84
|
-
response = await client.post(
|
|
85
|
-
api_url,
|
|
86
|
-
json=data,
|
|
87
|
-
headers={"Authorization": f"Bearer {api_key}"}
|
|
88
|
-
)
|
|
89
|
-
response.raise_for_status()
|
|
90
|
-
return response.json()
|
|
91
|
-
```
|
|
92
|
-
|
|
93
|
-
## Dependency Injection
|
|
94
|
-
|
|
95
|
-
```python
|
|
96
|
-
from fastapi import Depends
|
|
97
|
-
|
|
98
|
-
@router.post("/notify")
|
|
99
|
-
async def notify(
|
|
100
|
-
message: str,
|
|
101
|
-
service=Depends(lambda: notification_service)
|
|
102
|
-
):
|
|
103
|
-
await service.send_notification(user, message)
|
|
104
|
-
```
|
vibetuner/services/CLAUDE.md
DELETED
|
@@ -1,104 +0,0 @@
|
|
|
1
|
-
# Core Services Module
|
|
2
|
-
|
|
3
|
-
**IMMUTABLE SCAFFOLDING CODE** - These are the framework's core services that provide essential functionality.
|
|
4
|
-
|
|
5
|
-
## What's Here
|
|
6
|
-
|
|
7
|
-
This module contains the scaffolding's core services:
|
|
8
|
-
|
|
9
|
-
- **email.py** - Email sending via AWS SES
|
|
10
|
-
- **blob.py** - File storage and blob management
|
|
11
|
-
|
|
12
|
-
## Important Rules
|
|
13
|
-
|
|
14
|
-
⚠️ **DO NOT MODIFY** these core services directly.
|
|
15
|
-
|
|
16
|
-
**For changes to core services:**
|
|
17
|
-
|
|
18
|
-
- File an issue at `https://github.com/alltuner/scaffolding`
|
|
19
|
-
- Core changes benefit all projects using the scaffolding
|
|
20
|
-
|
|
21
|
-
**For your application services:**
|
|
22
|
-
|
|
23
|
-
- Create them in `src/app/services/` instead
|
|
24
|
-
- Import core services when needed: `from vibetuner.services.email import send_email`
|
|
25
|
-
|
|
26
|
-
## User Service Pattern (for reference)
|
|
27
|
-
|
|
28
|
-
Your application services in `src/app/services/` should follow this pattern:
|
|
29
|
-
|
|
30
|
-
```python
|
|
31
|
-
from vibetuner.models import UserModel
|
|
32
|
-
|
|
33
|
-
class NotificationService:
|
|
34
|
-
async def send_notification(
|
|
35
|
-
self,
|
|
36
|
-
user: UserModel,
|
|
37
|
-
message: str,
|
|
38
|
-
priority: str = "normal"
|
|
39
|
-
) -> bool:
|
|
40
|
-
# Implementation
|
|
41
|
-
return True
|
|
42
|
-
|
|
43
|
-
# Singleton
|
|
44
|
-
notification_service = NotificationService()
|
|
45
|
-
```
|
|
46
|
-
|
|
47
|
-
## Using Core Services
|
|
48
|
-
|
|
49
|
-
### Email Service
|
|
50
|
-
|
|
51
|
-
```python
|
|
52
|
-
from vibetuner.services.email import send_email
|
|
53
|
-
|
|
54
|
-
await send_email(
|
|
55
|
-
to_email="user@example.com",
|
|
56
|
-
subject="Welcome",
|
|
57
|
-
html_content="<h1>Welcome!</h1>",
|
|
58
|
-
text_content="Welcome!"
|
|
59
|
-
)
|
|
60
|
-
```
|
|
61
|
-
|
|
62
|
-
### Blob Service
|
|
63
|
-
|
|
64
|
-
```python
|
|
65
|
-
from vibetuner.services.blob import blob_service
|
|
66
|
-
|
|
67
|
-
# Upload file
|
|
68
|
-
blob = await blob_service.upload(file_data, "image.png")
|
|
69
|
-
|
|
70
|
-
# Get file URL
|
|
71
|
-
url = await blob_service.get_url(blob.id)
|
|
72
|
-
```
|
|
73
|
-
|
|
74
|
-
## Creating Your Own Services
|
|
75
|
-
|
|
76
|
-
Place your application services in `src/app/services/`:
|
|
77
|
-
|
|
78
|
-
```python
|
|
79
|
-
# src/app/services/external_api.py
|
|
80
|
-
import httpx
|
|
81
|
-
|
|
82
|
-
async def call_api(api_url: str, api_key: str, data: dict) -> dict:
|
|
83
|
-
async with httpx.AsyncClient() as client:
|
|
84
|
-
response = await client.post(
|
|
85
|
-
api_url,
|
|
86
|
-
json=data,
|
|
87
|
-
headers={"Authorization": f"Bearer {api_key}"}
|
|
88
|
-
)
|
|
89
|
-
response.raise_for_status()
|
|
90
|
-
return response.json()
|
|
91
|
-
```
|
|
92
|
-
|
|
93
|
-
## Dependency Injection
|
|
94
|
-
|
|
95
|
-
```python
|
|
96
|
-
from fastapi import Depends
|
|
97
|
-
|
|
98
|
-
@router.post("/notify")
|
|
99
|
-
async def notify(
|
|
100
|
-
message: str,
|
|
101
|
-
service=Depends(lambda: notification_service)
|
|
102
|
-
):
|
|
103
|
-
await service.send_notification(user, message)
|
|
104
|
-
```
|
vibetuner/tasks/AGENTS.md
DELETED
|
@@ -1,98 +0,0 @@
|
|
|
1
|
-
# Core Tasks Module
|
|
2
|
-
|
|
3
|
-
**IMMUTABLE SCAFFOLDING CODE** - This is the framework's core background task infrastructure.
|
|
4
|
-
|
|
5
|
-
## What's Here
|
|
6
|
-
|
|
7
|
-
This module contains the scaffolding's core task components:
|
|
8
|
-
|
|
9
|
-
- **worker.py** - Streaq worker setup and configuration
|
|
10
|
-
- **context.py** - Task context management (DB, HTTP client, etc.)
|
|
11
|
-
- ****init**.py** - Task infrastructure exports
|
|
12
|
-
|
|
13
|
-
## Important Rules
|
|
14
|
-
|
|
15
|
-
⚠️ **DO NOT MODIFY** these core task components directly.
|
|
16
|
-
|
|
17
|
-
**For changes to core tasks:**
|
|
18
|
-
|
|
19
|
-
- File an issue at `https://github.com/alltuner/scaffolding`
|
|
20
|
-
- Core changes benefit all projects using the scaffolding
|
|
21
|
-
|
|
22
|
-
**For your application tasks:**
|
|
23
|
-
|
|
24
|
-
- Create them in `src/app/tasks/` instead
|
|
25
|
-
- Import the worker from vibetuner: `from vibetuner.tasks.worker import worker`
|
|
26
|
-
|
|
27
|
-
## Quick Reference
|
|
28
|
-
|
|
29
|
-
Tasks are only available if job queue was enabled during scaffolding.
|
|
30
|
-
|
|
31
|
-
The worker is defined in `src/vibetuner/tasks/worker.py` and should be imported from there in your app tasks.
|
|
32
|
-
|
|
33
|
-
## User Task Pattern (for reference)
|
|
34
|
-
|
|
35
|
-
Your application tasks in `src/app/tasks/` should follow this pattern:
|
|
36
|
-
|
|
37
|
-
```python
|
|
38
|
-
# src/app/tasks/emails.py
|
|
39
|
-
from vibetuner.models import UserModel
|
|
40
|
-
from vibetuner.tasks.worker import worker
|
|
41
|
-
|
|
42
|
-
@worker.task()
|
|
43
|
-
async def send_welcome_email(user_id: str) -> dict[str, str]:
|
|
44
|
-
"""Example background job."""
|
|
45
|
-
|
|
46
|
-
# Access context
|
|
47
|
-
res = await worker.context.http_client.get(url)
|
|
48
|
-
|
|
49
|
-
if user := await UserModel.get(user_id):
|
|
50
|
-
# Perform side effects
|
|
51
|
-
return {"status": "sent", "user": user.email}
|
|
52
|
-
return {"status": "skipped"}
|
|
53
|
-
```
|
|
54
|
-
|
|
55
|
-
## Queueing Tasks
|
|
56
|
-
|
|
57
|
-
```python
|
|
58
|
-
# In your routes: src/app/frontend/routes/auth.py
|
|
59
|
-
from app.tasks.emails import send_welcome_email
|
|
60
|
-
|
|
61
|
-
@router.post("/signup")
|
|
62
|
-
async def signup(email: str):
|
|
63
|
-
user = await create_user(email)
|
|
64
|
-
|
|
65
|
-
task = await send_welcome_email.enqueue(user.id)
|
|
66
|
-
# Optional: await task.result() or check task.id
|
|
67
|
-
|
|
68
|
-
return {"status": "registered", "job_id": task.id}
|
|
69
|
-
```
|
|
70
|
-
|
|
71
|
-
Note: Import your task functions from `src/app/tasks/` but the worker itself comes from `vibetuner.tasks.worker`.
|
|
72
|
-
|
|
73
|
-
## Worker Management
|
|
74
|
-
|
|
75
|
-
```bash
|
|
76
|
-
just worker-dev # Run worker locally with auto-reload
|
|
77
|
-
```
|
|
78
|
-
|
|
79
|
-
## Task Registration
|
|
80
|
-
|
|
81
|
-
Add new task modules at the end of `src/app/tasks/__init__.py`:
|
|
82
|
-
|
|
83
|
-
```python
|
|
84
|
-
# src/app/tasks/__init__.py
|
|
85
|
-
# Import your task modules so decorators register with worker
|
|
86
|
-
from . import emails # noqa: F401
|
|
87
|
-
from . import new_tasks # noqa: F401
|
|
88
|
-
```
|
|
89
|
-
|
|
90
|
-
## Monitoring
|
|
91
|
-
|
|
92
|
-
```python
|
|
93
|
-
task = await send_digest_email.enqueue(account_id)
|
|
94
|
-
|
|
95
|
-
status = await task.status()
|
|
96
|
-
result = await task.result(timeout=30)
|
|
97
|
-
await task.abort() # Cancel if needed
|
|
98
|
-
```
|