@stackguide/mcp-server 1.0.0
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.
- package/LICENSE +674 -0
- package/README.md +453 -0
- package/data/knowledge/python-django/architecture/architecture-patterns.md +201 -0
- package/data/knowledge/python-django/common-issues/common-issues.md +181 -0
- package/data/knowledge/python-django/patterns/drf-patterns.md +133 -0
- package/data/knowledge/react-node/architecture/node-architecture.md +257 -0
- package/data/knowledge/react-node/common-issues/common-issues.md +262 -0
- package/data/knowledge/react-node/patterns/react-patterns.md +244 -0
- package/data/rules/python-django/best-practices/django-best-practices.md +120 -0
- package/data/rules/python-django/coding-standards/django-standards.md +104 -0
- package/data/rules/python-django/security/security-guidelines.md +146 -0
- package/data/rules/react-node/best-practices/react-best-practices.md +195 -0
- package/data/rules/react-node/coding-standards/node-standards.md +192 -0
- package/data/rules/react-node/coding-standards/react-standards.md +155 -0
- package/data/rules/react-node/security/security-guidelines.md +228 -0
- package/dist/config/persistence.d.ts +15 -0
- package/dist/config/persistence.d.ts.map +1 -0
- package/dist/config/persistence.js +171 -0
- package/dist/config/persistence.js.map +1 -0
- package/dist/config/types.d.ts +47 -0
- package/dist/config/types.d.ts.map +1 -0
- package/dist/config/types.js +116 -0
- package/dist/config/types.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +1799 -0
- package/dist/index.js.map +1 -0
- package/dist/resources/knowledgeProvider.d.ts +10 -0
- package/dist/resources/knowledgeProvider.d.ts.map +1 -0
- package/dist/resources/knowledgeProvider.js +130 -0
- package/dist/resources/knowledgeProvider.js.map +1 -0
- package/dist/resources/rulesProvider.d.ts +10 -0
- package/dist/resources/rulesProvider.d.ts.map +1 -0
- package/dist/resources/rulesProvider.js +135 -0
- package/dist/resources/rulesProvider.js.map +1 -0
- package/dist/services/cursorDirectory.d.ts +55 -0
- package/dist/services/cursorDirectory.d.ts.map +1 -0
- package/dist/services/cursorDirectory.js +367 -0
- package/dist/services/cursorDirectory.js.map +1 -0
- package/dist/services/ruleManager.d.ts +18 -0
- package/dist/services/ruleManager.d.ts.map +1 -0
- package/dist/services/ruleManager.js +382 -0
- package/dist/services/ruleManager.js.map +1 -0
- package/dist/services/webDocumentation.d.ts +41 -0
- package/dist/services/webDocumentation.d.ts.map +1 -0
- package/dist/services/webDocumentation.js +237 -0
- package/dist/services/webDocumentation.js.map +1 -0
- package/package.json +46 -0
package/README.md
ADDED
|
@@ -0,0 +1,453 @@
|
|
|
1
|
+
# StackGuide MCP Server
|
|
2
|
+
|
|
3
|
+
A Model Context Protocol (MCP) server that provides dynamic language and framework context for AI coding assistants. Compatible with **Cursor** and **GitHub Copilot**.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- 🎯 **Dynamic Context Loading**: Load context based on your project type (Python/Django, React/Node, etc.)
|
|
8
|
+
- 📋 **Rules Management**: Select and apply coding standards, best practices, and security guidelines
|
|
9
|
+
- 📚 **Knowledge Base**: Access architecture patterns, common issues solutions, and code snippets
|
|
10
|
+
- 💾 **Configuration Persistence**: Save and load your preferred configurations
|
|
11
|
+
- 🔄 **Compatible**: Works with both Cursor and GitHub Copilot
|
|
12
|
+
- ✨ **Dynamic Rule Management**: Create, edit, and delete rules at runtime using tools
|
|
13
|
+
- 🌐 **Web Documentation**: Fetch and cache documentation from any URL
|
|
14
|
+
- 📝 **Rule Templates**: Quick-start templates for common rule types (coding-standard, best-practice, security, architecture, testing)
|
|
15
|
+
- 🔗 **Cursor Directory Integration**: Browse, search, and import rules from [cursor.directory](https://cursor.directory/rules/) - a community-driven repository of AI coding rules
|
|
16
|
+
|
|
17
|
+
## Supported Project Types
|
|
18
|
+
|
|
19
|
+
| Type | Languages | Frameworks |
|
|
20
|
+
|------|-----------|------------|
|
|
21
|
+
| `python-django` | Python | Django, DRF |
|
|
22
|
+
| `python-fastapi` | Python | FastAPI |
|
|
23
|
+
| `python-flask` | Python | Flask |
|
|
24
|
+
| `react-node` | JavaScript, TypeScript | React, Node.js, Express |
|
|
25
|
+
| `react-typescript` | TypeScript | React |
|
|
26
|
+
| `vue-node` | JavaScript, TypeScript | Vue.js, Node.js |
|
|
27
|
+
| `nextjs` | JavaScript, TypeScript | Next.js, React |
|
|
28
|
+
| `express` | JavaScript, TypeScript | Express.js |
|
|
29
|
+
| `nestjs` | TypeScript | NestJS |
|
|
30
|
+
| `laravel` | PHP | Laravel |
|
|
31
|
+
| `rails` | Ruby | Ruby on Rails |
|
|
32
|
+
| `golang` | Go | - |
|
|
33
|
+
| `rust` | Rust | - |
|
|
34
|
+
|
|
35
|
+
## Installation
|
|
36
|
+
|
|
37
|
+
### From npm (Recommended)
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
npm install -g @stackguide/mcp-server
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
### From Source
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
git clone https://github.com/taimiralain/StackGuide-MCP.git
|
|
47
|
+
cd StackGuide-MCP
|
|
48
|
+
npm install
|
|
49
|
+
npm run build
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
## Configuration
|
|
53
|
+
|
|
54
|
+
### For Cursor
|
|
55
|
+
|
|
56
|
+
Add to your Cursor settings (`.cursor/mcp.json`):
|
|
57
|
+
|
|
58
|
+
```json
|
|
59
|
+
{
|
|
60
|
+
"mcpServers": {
|
|
61
|
+
"stackguide": {
|
|
62
|
+
"command": "npx",
|
|
63
|
+
"args": ["-y", "@stackguide/mcp-server"]
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
Or if installed from source:
|
|
70
|
+
|
|
71
|
+
```json
|
|
72
|
+
{
|
|
73
|
+
"mcpServers": {
|
|
74
|
+
"stackguide": {
|
|
75
|
+
"command": "node",
|
|
76
|
+
"args": ["/path/to/StackGuide-MCP/dist/index.js"]
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
### For VS Code with GitHub Copilot
|
|
83
|
+
|
|
84
|
+
Add to `.vscode/mcp.json` in your workspace:
|
|
85
|
+
|
|
86
|
+
```json
|
|
87
|
+
{
|
|
88
|
+
"mcpServers": {
|
|
89
|
+
"stackguide": {
|
|
90
|
+
"command": "npx",
|
|
91
|
+
"args": ["-y", "@stackguide/mcp-server"]
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
Or add to your user settings (`settings.json`):
|
|
98
|
+
|
|
99
|
+
```json
|
|
100
|
+
{
|
|
101
|
+
"github.copilot.chat.mcpServers": {
|
|
102
|
+
"stackguide": {
|
|
103
|
+
"command": "npx",
|
|
104
|
+
"args": ["-y", "@stackguide/mcp-server"]
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
## Usage
|
|
111
|
+
|
|
112
|
+
### Available Tools
|
|
113
|
+
|
|
114
|
+
#### Project Type Management
|
|
115
|
+
- `list_project_types` - List all supported project types
|
|
116
|
+
- `select_project_type` - Activate a project type context
|
|
117
|
+
- `get_current_context` - Get the currently active context
|
|
118
|
+
|
|
119
|
+
#### Rules Management
|
|
120
|
+
- `list_rules` - List available rules for current project
|
|
121
|
+
- `get_rule` - Get full content of a specific rule
|
|
122
|
+
- `select_rules` - Select which rules to include in context
|
|
123
|
+
- `search_rules` - Search rules by keyword
|
|
124
|
+
|
|
125
|
+
#### Knowledge Base
|
|
126
|
+
- `list_knowledge` - List knowledge base files
|
|
127
|
+
- `get_knowledge` - Get content of a knowledge file
|
|
128
|
+
- `select_knowledge` - Select knowledge to include
|
|
129
|
+
- `search_knowledge` - Search knowledge base
|
|
130
|
+
|
|
131
|
+
#### Configuration
|
|
132
|
+
- `save_configuration` - Save current context setup
|
|
133
|
+
- `load_configuration` - Load a saved configuration
|
|
134
|
+
- `list_configurations` - List all saved configurations
|
|
135
|
+
- `delete_configuration` - Delete a configuration
|
|
136
|
+
- `export_configuration` - Export config as JSON
|
|
137
|
+
- `import_configuration` - Import config from JSON
|
|
138
|
+
|
|
139
|
+
#### Dynamic Rule Management (NEW!)
|
|
140
|
+
- `create_rule` - Create a new custom rule from scratch
|
|
141
|
+
- `create_rule_from_template` - Create a rule using a template
|
|
142
|
+
- `list_rule_templates` - List available rule templates
|
|
143
|
+
- `update_rule` - Update an existing user rule
|
|
144
|
+
- `delete_rule` - Delete a user rule
|
|
145
|
+
- `list_user_rules` - List all user-created rules
|
|
146
|
+
- `export_user_rules` - Export all user rules as JSON
|
|
147
|
+
- `import_user_rules` - Import user rules from JSON
|
|
148
|
+
|
|
149
|
+
#### Web Documentation (NEW!)
|
|
150
|
+
- `fetch_web_docs` - Fetch documentation from any URL
|
|
151
|
+
- `fetch_multiple_docs` - Fetch multiple URLs at once
|
|
152
|
+
- `get_web_doc` - Get a cached web document
|
|
153
|
+
- `search_web_docs` - Search cached documentation
|
|
154
|
+
- `list_web_docs` - List all cached documents
|
|
155
|
+
- `get_suggested_docs` - Get suggested docs for a project type
|
|
156
|
+
- `remove_web_doc` - Remove a cached document
|
|
157
|
+
|
|
158
|
+
#### Cursor Directory Integration (NEW!)
|
|
159
|
+
- `browse_cursor_directory` - Browse rules by category from cursor.directory
|
|
160
|
+
- `search_cursor_directory` - Search for rules on cursor.directory
|
|
161
|
+
- `get_cursor_directory_rule` - Get a specific rule by slug
|
|
162
|
+
- `list_cursor_directory_categories` - List all available categories
|
|
163
|
+
- `get_popular_cursor_rules` - Get popular/featured rules
|
|
164
|
+
- `import_cursor_directory_rule` - Import a rule into your local collection
|
|
165
|
+
|
|
166
|
+
#### Context
|
|
167
|
+
- `get_full_context` - Get complete active context
|
|
168
|
+
- `add_custom_rule` - Add a custom rule
|
|
169
|
+
|
|
170
|
+
### Example Workflow
|
|
171
|
+
|
|
172
|
+
1. **Select your project type:**
|
|
173
|
+
```
|
|
174
|
+
Use select_project_type with "react-node"
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
2. **View available rules:**
|
|
178
|
+
```
|
|
179
|
+
Use list_rules to see all available rules
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
3. **Select specific rules:**
|
|
183
|
+
```
|
|
184
|
+
Use select_rules with the IDs of rules you want
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
4. **Save your configuration:**
|
|
188
|
+
```
|
|
189
|
+
Use save_configuration with a name like "My React Setup"
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
5. **Get full context for AI:**
|
|
193
|
+
```
|
|
194
|
+
Use get_full_context to get all selected rules and knowledge
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
### Available Resources
|
|
198
|
+
|
|
199
|
+
- `rules://{project_type}/all` - All rules for a project type
|
|
200
|
+
- `knowledge://{project_type}/all` - All knowledge for a project type
|
|
201
|
+
- `context://active` - Currently active context (includes rules, user rules, knowledge, and web docs)
|
|
202
|
+
- `user-rules://{project_type}/all` - All user-created rules for a project type
|
|
203
|
+
- `web-doc://{doc_id}` - Specific cached web document
|
|
204
|
+
- `templates://rules` - Available rule templates
|
|
205
|
+
|
|
206
|
+
### Available Prompts
|
|
207
|
+
|
|
208
|
+
- `setup_project` - Initialize context for a new project
|
|
209
|
+
- `code_review` - Review code with active rules
|
|
210
|
+
- `apply_patterns` - Apply architecture patterns
|
|
211
|
+
|
|
212
|
+
## Adding Custom Rules
|
|
213
|
+
|
|
214
|
+
### Via Tool
|
|
215
|
+
Use the `add_custom_rule` tool with:
|
|
216
|
+
- `name`: Rule name
|
|
217
|
+
- `category`: One of `coding-standards`, `best-practices`, `security`, `performance`, `architecture`, `testing`, `documentation`, `naming-conventions`
|
|
218
|
+
- `content`: Rule content in Markdown
|
|
219
|
+
- `description`: Brief description
|
|
220
|
+
|
|
221
|
+
### Via Files
|
|
222
|
+
Add Markdown files to the `data/rules/{project-type}/{category}/` directory:
|
|
223
|
+
|
|
224
|
+
```markdown
|
|
225
|
+
# Rule Title
|
|
226
|
+
|
|
227
|
+
Description of the rule.
|
|
228
|
+
|
|
229
|
+
## Guidelines
|
|
230
|
+
|
|
231
|
+
- Guideline 1
|
|
232
|
+
- Guideline 2
|
|
233
|
+
|
|
234
|
+
## Examples
|
|
235
|
+
|
|
236
|
+
```python
|
|
237
|
+
# Code example
|
|
238
|
+
```
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
## Configuration Storage
|
|
242
|
+
|
|
243
|
+
User configurations are stored in `~/.stackguide/`:
|
|
244
|
+
- `configurations.json` - All saved configurations
|
|
245
|
+
- `rules/{project-type}/*.json` - User-created rules
|
|
246
|
+
- `web-docs/cache.json` - Cached web documentation
|
|
247
|
+
|
|
248
|
+
## Development
|
|
249
|
+
|
|
250
|
+
### Build
|
|
251
|
+
|
|
252
|
+
```bash
|
|
253
|
+
npm run build
|
|
254
|
+
```
|
|
255
|
+
|
|
256
|
+
### Run in Development
|
|
257
|
+
|
|
258
|
+
```bash
|
|
259
|
+
npm run dev
|
|
260
|
+
```
|
|
261
|
+
|
|
262
|
+
### Project Structure
|
|
263
|
+
|
|
264
|
+
```
|
|
265
|
+
StackGuide-MCP/
|
|
266
|
+
├── src/
|
|
267
|
+
│ ├── index.ts # Main entry point
|
|
268
|
+
│ ├── config/
|
|
269
|
+
│ │ ├── types.ts # TypeScript types
|
|
270
|
+
│ │ └── persistence.ts # Configuration storage
|
|
271
|
+
│ ├── resources/
|
|
272
|
+
│ │ ├── rulesProvider.ts # Rules management
|
|
273
|
+
│ │ └── knowledgeProvider.ts # Knowledge base
|
|
274
|
+
│ └── services/
|
|
275
|
+
│ ├── ruleManager.ts # Dynamic rule CRUD
|
|
276
|
+
│ └── webDocumentation.ts # Web docs fetcher
|
|
277
|
+
├── data/
|
|
278
|
+
│ ├── rules/ # Rule files by project type
|
|
279
|
+
│ │ ├── python-django/
|
|
280
|
+
│ │ └── react-node/
|
|
281
|
+
│ └── knowledge/ # Knowledge files by project type
|
|
282
|
+
│ ├── python-django/
|
|
283
|
+
│ └── react-node/
|
|
284
|
+
├── docs/
|
|
285
|
+
│ └── ADDING_CUSTOM_RULES.md # Guide for adding rules
|
|
286
|
+
├── package.json
|
|
287
|
+
├── tsconfig.json
|
|
288
|
+
└── README.md
|
|
289
|
+
```
|
|
290
|
+
|
|
291
|
+
## Dynamic Rule Management
|
|
292
|
+
|
|
293
|
+
### Creating Rules from Templates
|
|
294
|
+
|
|
295
|
+
1. **List available templates:**
|
|
296
|
+
```
|
|
297
|
+
Use list_rule_templates
|
|
298
|
+
```
|
|
299
|
+
|
|
300
|
+
2. **Create a rule from template:**
|
|
301
|
+
```
|
|
302
|
+
Use create_rule_from_template with:
|
|
303
|
+
- templateId: "coding-standard"
|
|
304
|
+
- projectType: "react-node"
|
|
305
|
+
- name: "My Team Standards"
|
|
306
|
+
```
|
|
307
|
+
|
|
308
|
+
3. **Edit the rule:**
|
|
309
|
+
```
|
|
310
|
+
Use update_rule with the rule ID and new content
|
|
311
|
+
```
|
|
312
|
+
|
|
313
|
+
### Creating Rules from Scratch
|
|
314
|
+
|
|
315
|
+
```
|
|
316
|
+
Use create_rule with:
|
|
317
|
+
- projectType: "python-django"
|
|
318
|
+
- name: "API Versioning"
|
|
319
|
+
- category: "best-practices"
|
|
320
|
+
- content: "# API Versioning\n\nAlways version your APIs..."
|
|
321
|
+
- description: "Guidelines for API versioning"
|
|
322
|
+
```
|
|
323
|
+
|
|
324
|
+
## Web Documentation
|
|
325
|
+
|
|
326
|
+
### Fetching Documentation
|
|
327
|
+
|
|
328
|
+
```
|
|
329
|
+
Use fetch_web_docs with:
|
|
330
|
+
- url: "https://react.dev/reference/react/useState"
|
|
331
|
+
- projectType: "react-node"
|
|
332
|
+
- title: "useState Hook"
|
|
333
|
+
```
|
|
334
|
+
|
|
335
|
+
### Getting Suggestions
|
|
336
|
+
|
|
337
|
+
```
|
|
338
|
+
Use get_suggested_docs with projectType: "react-node"
|
|
339
|
+
```
|
|
340
|
+
|
|
341
|
+
This returns popular documentation URLs for the framework.
|
|
342
|
+
|
|
343
|
+
## Cursor Directory Integration
|
|
344
|
+
|
|
345
|
+
[cursor.directory](https://cursor.directory/rules/) is a community-driven repository of cursor rules for various technologies. StackGuide-MCP integrates with it to let you:
|
|
346
|
+
|
|
347
|
+
### Browse Rules by Category
|
|
348
|
+
|
|
349
|
+
```
|
|
350
|
+
Use browse_cursor_directory with category: "typescript"
|
|
351
|
+
```
|
|
352
|
+
|
|
353
|
+
Available categories include: typescript, python, react, next.js, vue, django, fastapi, nestjs, prisma, tailwindcss, and many more.
|
|
354
|
+
|
|
355
|
+
### Search for Rules
|
|
356
|
+
|
|
357
|
+
```
|
|
358
|
+
Use search_cursor_directory with query: "react hooks best practices"
|
|
359
|
+
```
|
|
360
|
+
|
|
361
|
+
### Get Popular Rules
|
|
362
|
+
|
|
363
|
+
```
|
|
364
|
+
Use get_popular_cursor_rules
|
|
365
|
+
```
|
|
366
|
+
|
|
367
|
+
Returns featured rules from popular frameworks.
|
|
368
|
+
|
|
369
|
+
### Import Rules
|
|
370
|
+
|
|
371
|
+
```
|
|
372
|
+
Use import_cursor_directory_rule with:
|
|
373
|
+
- slug: "nextjs-react-typescript-cursor-rules"
|
|
374
|
+
- projectType: "react-typescript"
|
|
375
|
+
- category: "best-practices"
|
|
376
|
+
```
|
|
377
|
+
|
|
378
|
+
This fetches the rule from cursor.directory and saves it to your local rules collection.
|
|
379
|
+
|
|
380
|
+
## Publishing to npm
|
|
381
|
+
|
|
382
|
+
### Prerequisites
|
|
383
|
+
|
|
384
|
+
1. Create an npm account at [npmjs.com](https://www.npmjs.com/)
|
|
385
|
+
2. Login to npm:
|
|
386
|
+
```bash
|
|
387
|
+
npm login
|
|
388
|
+
```
|
|
389
|
+
|
|
390
|
+
### Steps to Publish
|
|
391
|
+
|
|
392
|
+
1. **Update version** in `package.json`:
|
|
393
|
+
```bash
|
|
394
|
+
npm version patch # or minor, major
|
|
395
|
+
```
|
|
396
|
+
|
|
397
|
+
2. **Build the project**:
|
|
398
|
+
```bash
|
|
399
|
+
npm run build
|
|
400
|
+
```
|
|
401
|
+
|
|
402
|
+
3. **Test locally** (optional):
|
|
403
|
+
```bash
|
|
404
|
+
npm link
|
|
405
|
+
stackguide-mcp # Test the command
|
|
406
|
+
npm unlink
|
|
407
|
+
```
|
|
408
|
+
|
|
409
|
+
4. **Publish to npm**:
|
|
410
|
+
```bash
|
|
411
|
+
npm publish --access public
|
|
412
|
+
```
|
|
413
|
+
|
|
414
|
+
Note: The package is scoped (`@stackguide/mcp-server`), so you need `--access public` for the first publish.
|
|
415
|
+
|
|
416
|
+
5. **Verify publication**:
|
|
417
|
+
```bash
|
|
418
|
+
npm view @stackguide/mcp-server
|
|
419
|
+
```
|
|
420
|
+
|
|
421
|
+
### Updating the Published Package
|
|
422
|
+
|
|
423
|
+
```bash
|
|
424
|
+
npm version patch # Bump version
|
|
425
|
+
npm run build
|
|
426
|
+
npm publish
|
|
427
|
+
```
|
|
428
|
+
|
|
429
|
+
### Publishing Checklist
|
|
430
|
+
|
|
431
|
+
- [ ] All tests pass
|
|
432
|
+
- [ ] README is up to date
|
|
433
|
+
- [ ] Version is bumped
|
|
434
|
+
- [ ] Build succeeds
|
|
435
|
+
- [ ] `main` and `bin` fields in package.json point to correct files
|
|
436
|
+
- [ ] Keywords and description are accurate
|
|
437
|
+
|
|
438
|
+
## Contributing
|
|
439
|
+
|
|
440
|
+
1. Fork the repository
|
|
441
|
+
2. Create a feature branch
|
|
442
|
+
3. Add your rules/knowledge files or enhance the server
|
|
443
|
+
4. Submit a pull request
|
|
444
|
+
|
|
445
|
+
### Adding Support for New Frameworks
|
|
446
|
+
|
|
447
|
+
1. Add project type to `src/config/types.ts`
|
|
448
|
+
2. Create rule files in `data/rules/{new-type}/`
|
|
449
|
+
3. Create knowledge files in `data/knowledge/{new-type}/`
|
|
450
|
+
|
|
451
|
+
## License
|
|
452
|
+
|
|
453
|
+
GPL-3.0 - See [LICENSE](LICENSE) for details.
|
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
# Django Project Architecture
|
|
2
|
+
|
|
3
|
+
Recommended architecture patterns for scalable Django applications.
|
|
4
|
+
|
|
5
|
+
## Layered Architecture
|
|
6
|
+
|
|
7
|
+
```
|
|
8
|
+
┌─────────────────────────────────────┐
|
|
9
|
+
│ Presentation │
|
|
10
|
+
│ (Views, Templates, Serializers) │
|
|
11
|
+
├─────────────────────────────────────┤
|
|
12
|
+
│ Application │
|
|
13
|
+
│ (Services, Use Cases) │
|
|
14
|
+
├─────────────────────────────────────┤
|
|
15
|
+
│ Domain │
|
|
16
|
+
│ (Models, Business Logic) │
|
|
17
|
+
├─────────────────────────────────────┤
|
|
18
|
+
│ Infrastructure │
|
|
19
|
+
│ (Database, External APIs, Cache) │
|
|
20
|
+
└─────────────────────────────────────┘
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
## Service Layer Pattern
|
|
24
|
+
|
|
25
|
+
Separate business logic from views:
|
|
26
|
+
|
|
27
|
+
```python
|
|
28
|
+
# services/article_service.py
|
|
29
|
+
from django.db import transaction
|
|
30
|
+
from typing import Optional
|
|
31
|
+
|
|
32
|
+
class ArticleService:
|
|
33
|
+
def __init__(self):
|
|
34
|
+
self.notification_service = NotificationService()
|
|
35
|
+
|
|
36
|
+
@transaction.atomic
|
|
37
|
+
def create_article(
|
|
38
|
+
self,
|
|
39
|
+
author_id: int,
|
|
40
|
+
title: str,
|
|
41
|
+
content: str,
|
|
42
|
+
tags: list[str] = None
|
|
43
|
+
) -> Article:
|
|
44
|
+
"""Create article with full business logic."""
|
|
45
|
+
author = User.objects.get(id=author_id)
|
|
46
|
+
|
|
47
|
+
article = Article.objects.create(
|
|
48
|
+
author=author,
|
|
49
|
+
title=title,
|
|
50
|
+
content=content,
|
|
51
|
+
slug=slugify(title)
|
|
52
|
+
)
|
|
53
|
+
|
|
54
|
+
if tags:
|
|
55
|
+
article.tags.set(Tag.objects.filter(name__in=tags))
|
|
56
|
+
|
|
57
|
+
# Side effects
|
|
58
|
+
self.notification_service.notify_followers(author, article)
|
|
59
|
+
|
|
60
|
+
return article
|
|
61
|
+
|
|
62
|
+
def publish_article(self, article_id: int) -> Article:
|
|
63
|
+
"""Publish an article with validation."""
|
|
64
|
+
article = Article.objects.get(id=article_id)
|
|
65
|
+
|
|
66
|
+
if article.status == "published":
|
|
67
|
+
raise ValueError("Article already published")
|
|
68
|
+
|
|
69
|
+
if not article.content:
|
|
70
|
+
raise ValueError("Cannot publish empty article")
|
|
71
|
+
|
|
72
|
+
article.status = "published"
|
|
73
|
+
article.published_at = timezone.now()
|
|
74
|
+
article.save()
|
|
75
|
+
|
|
76
|
+
return article
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
## Repository Pattern
|
|
80
|
+
|
|
81
|
+
Abstract database operations:
|
|
82
|
+
|
|
83
|
+
```python
|
|
84
|
+
# repositories/article_repository.py
|
|
85
|
+
from abc import ABC, abstractmethod
|
|
86
|
+
from typing import List, Optional
|
|
87
|
+
|
|
88
|
+
class ArticleRepositoryInterface(ABC):
|
|
89
|
+
@abstractmethod
|
|
90
|
+
def get_by_id(self, id: int) -> Optional[Article]:
|
|
91
|
+
pass
|
|
92
|
+
|
|
93
|
+
@abstractmethod
|
|
94
|
+
def get_published(self) -> List[Article]:
|
|
95
|
+
pass
|
|
96
|
+
|
|
97
|
+
@abstractmethod
|
|
98
|
+
def save(self, article: Article) -> Article:
|
|
99
|
+
pass
|
|
100
|
+
|
|
101
|
+
class DjangoArticleRepository(ArticleRepositoryInterface):
|
|
102
|
+
def get_by_id(self, id: int) -> Optional[Article]:
|
|
103
|
+
try:
|
|
104
|
+
return Article.objects.select_related("author").get(id=id)
|
|
105
|
+
except Article.DoesNotExist:
|
|
106
|
+
return None
|
|
107
|
+
|
|
108
|
+
def get_published(self) -> List[Article]:
|
|
109
|
+
return list(
|
|
110
|
+
Article.objects
|
|
111
|
+
.filter(status="published")
|
|
112
|
+
.select_related("author")
|
|
113
|
+
.prefetch_related("tags")
|
|
114
|
+
.order_by("-published_at")
|
|
115
|
+
)
|
|
116
|
+
|
|
117
|
+
def save(self, article: Article) -> Article:
|
|
118
|
+
article.save()
|
|
119
|
+
return article
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
## Domain Events
|
|
123
|
+
|
|
124
|
+
Decouple components with events:
|
|
125
|
+
|
|
126
|
+
```python
|
|
127
|
+
# events/article_events.py
|
|
128
|
+
from dataclasses import dataclass
|
|
129
|
+
from datetime import datetime
|
|
130
|
+
|
|
131
|
+
@dataclass
|
|
132
|
+
class ArticlePublishedEvent:
|
|
133
|
+
article_id: int
|
|
134
|
+
author_id: int
|
|
135
|
+
published_at: datetime
|
|
136
|
+
|
|
137
|
+
# events/handlers.py
|
|
138
|
+
from django.dispatch import receiver
|
|
139
|
+
from .signals import article_published
|
|
140
|
+
|
|
141
|
+
@receiver(article_published)
|
|
142
|
+
def send_notifications(sender, event: ArticlePublishedEvent, **kwargs):
|
|
143
|
+
NotificationService().notify_subscribers(event)
|
|
144
|
+
|
|
145
|
+
@receiver(article_published)
|
|
146
|
+
def update_search_index(sender, event: ArticlePublishedEvent, **kwargs):
|
|
147
|
+
SearchService().index_article(event.article_id)
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
## Module Structure for Large Apps
|
|
151
|
+
|
|
152
|
+
```
|
|
153
|
+
apps/
|
|
154
|
+
├── articles/
|
|
155
|
+
│ ├── __init__.py
|
|
156
|
+
│ ├── admin.py
|
|
157
|
+
│ ├── apps.py
|
|
158
|
+
│ ├── models/
|
|
159
|
+
│ │ ├── __init__.py
|
|
160
|
+
│ │ ├── article.py
|
|
161
|
+
│ │ └── tag.py
|
|
162
|
+
│ ├── services/
|
|
163
|
+
│ │ ├── __init__.py
|
|
164
|
+
│ │ └── article_service.py
|
|
165
|
+
│ ├── repositories/
|
|
166
|
+
│ │ ├── __init__.py
|
|
167
|
+
│ │ └── article_repository.py
|
|
168
|
+
│ ├── api/
|
|
169
|
+
│ │ ├── __init__.py
|
|
170
|
+
│ │ ├── views.py
|
|
171
|
+
│ │ ├── serializers.py
|
|
172
|
+
│ │ └── urls.py
|
|
173
|
+
│ ├── tests/
|
|
174
|
+
│ │ ├── __init__.py
|
|
175
|
+
│ │ ├── test_models.py
|
|
176
|
+
│ │ ├── test_services.py
|
|
177
|
+
│ │ └── test_api.py
|
|
178
|
+
│ └── migrations/
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
## Dependency Injection
|
|
182
|
+
|
|
183
|
+
```python
|
|
184
|
+
# container.py
|
|
185
|
+
class Container:
|
|
186
|
+
_instances = {}
|
|
187
|
+
|
|
188
|
+
@classmethod
|
|
189
|
+
def get_article_service(cls) -> ArticleService:
|
|
190
|
+
if "article_service" not in cls._instances:
|
|
191
|
+
repo = DjangoArticleRepository()
|
|
192
|
+
notification = NotificationService()
|
|
193
|
+
cls._instances["article_service"] = ArticleService(repo, notification)
|
|
194
|
+
return cls._instances["article_service"]
|
|
195
|
+
|
|
196
|
+
# views.py
|
|
197
|
+
class ArticleViewSet(viewsets.ViewSet):
|
|
198
|
+
def __init__(self, **kwargs):
|
|
199
|
+
super().__init__(**kwargs)
|
|
200
|
+
self.service = Container.get_article_service()
|
|
201
|
+
```
|