diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md new file mode 100644 index 0000000..4fa9ec2 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -0,0 +1,48 @@ +--- +name: Bug Report +about: Report a bug or issue with the template +title: '[BUG] ' +labels: bug +assignees: '' +--- + +## Bug Description + + +## Steps to Reproduce +1. +2. +3. + +## Expected Behavior + + +## Actual Behavior + + +## Environment +- OS: [e.g., Ubuntu 22.04, macOS 13, Windows 11] +- Python Version: [e.g., 3.12] +- Docker Version: [e.g., 24.0.0] +- Cookiecutter Version: [e.g., 2.5.0] +- JST-Django CLI Version: [e.g., 1.2.2] + +## Cookiecutter Configuration +```json +{ + "project_name": "", + "celery": "", + "silk": "", + "channels": "", + ... +} +``` + +## Screenshots + + +## Additional Context + + +## Possible Solution + diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md new file mode 100644 index 0000000..50d53d1 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -0,0 +1,35 @@ +--- +name: Feature Request +about: Suggest a new feature or improvement +title: '[FEATURE] ' +labels: enhancement +assignees: '' +--- + +## Feature Description + + +## Problem Statement + + +## Proposed Solution + + +## Alternative Solutions + + +## Use Case + + +## Example + + +```python +# Example usage +``` + +## Additional Context + + +## Benefits + diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md new file mode 100644 index 0000000..959e966 --- /dev/null +++ b/.github/pull_request_template.md @@ -0,0 +1,51 @@ +## Description + + +## Type of Change + +- [ ] Bug fix (non-breaking change that fixes an issue) +- [ ] New feature (non-breaking change that adds functionality) +- [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected) +- [ ] Documentation update +- [ ] Code refactoring +- [ ] Security fix + +## Related Issue + + +## Changes Made + +- +- +- + +## Testing + + +### Test Configuration +- OS: +- Python Version: +- Docker Version: + +### Tests Performed +- [ ] Template generation with default options +- [ ] Template generation with various package combinations +- [ ] Generated project builds successfully +- [ ] Generated project tests pass +- [ ] Documentation is up to date + +## Screenshots + + +## Checklist +- [ ] My code follows the project's style guidelines +- [ ] I have performed a self-review of my code +- [ ] I have commented my code where necessary +- [ ] I have updated the documentation (both Uzbek and English if applicable) +- [ ] My changes generate no new warnings +- [ ] I have tested the changes with different cookiecutter options +- [ ] All existing tests pass +- [ ] I have checked for security issues + +## Additional Notes + diff --git a/README.MD b/README.MD index 1ce6dd3..62bc4dd 100644 --- a/README.MD +++ b/README.MD @@ -1,5 +1,7 @@ # jst-django docs +**Til / Language:** O'zbek | [English]({{cookiecutter.project_slug}}/README.EN.md) + Assalomu Alaykum bu dasturni o’rganishdan avval bu dastur haqida biroz aytib bermoqchiman bu dastur nega kerak kimlar uchun shu haqida birlib olishingiz muhum. bu dastur ikkita bo’lakga bo’lingan biri cli dastur ikkinchisi asosiy arxitiktura. diff --git a/cookiecutter.json b/cookiecutter.json index c4e1f74..bab208f 100644 --- a/cookiecutter.json +++ b/cookiecutter.json @@ -21,10 +21,10 @@ "entrypoint.sh", "entrypoint-server.sh" ], - "key": "key", + "key": "django-insecure-change-this-key-in-production", "port": "8081", - "phone": "998888112309", - "password": "2309", + "phone": "998901234567", + "password": "changeme123", "max_line_length": "120", "silk": [ false, diff --git a/hooks/post_gen_project.py b/hooks/post_gen_project.py index 504d3c2..7c2ec28 100644 --- a/hooks/post_gen_project.py +++ b/hooks/post_gen_project.py @@ -1,4 +1,6 @@ import shutil +import sys +from pathlib import Path class Hook: @@ -7,8 +9,18 @@ def __init__(self) -> None: self.copy_files = {".env.example": ".env"} def copy(self): - for key, value in self.copy_files.items(): - shutil.copy(key, value) + """Copy files with error handling""" + for source, destination in self.copy_files.items(): + try: + source_path = Path(source) + if not source_path.exists(): + print(f"Warning: Source file '{source}' does not exist. Skipping.") + continue + shutil.copy(source, destination) + print(f"Successfully copied {source} to {destination}") + except Exception as e: + print(f"Error copying {source} to {destination}: {e}", file=sys.stderr) + sys.exit(1) def run(self): self.copy() diff --git a/{{cookiecutter.project_slug}}/.env.example b/{{cookiecutter.project_slug}}/.env.example index 9d524c5..4cf56a3 100644 --- a/{{cookiecutter.project_slug}}/.env.example +++ b/{{cookiecutter.project_slug}}/.env.example @@ -1,4 +1,5 @@ # Django configs +# WARNING: Change DJANGO_SECRET_KEY in production! Use a long, random string. DJANGO_SECRET_KEY={{cookiecutter.key}} DEBUG=True DJANGO_SETTINGS_MODULE={{cookiecutter.settings_module}} @@ -14,8 +15,9 @@ OTP_SIZE=4 OTP_PROD=false OTP_DEFAULT=1111 -# Databse configs +# Database configs # https://docs.djangoproject.com/en/4.2/ref/settings/#databases +# WARNING: Change DB_PASSWORD in production! Use a strong, unique password. DB_ENGINE=django.db.backends.postgresql_psycopg2 DB_NAME=django DB_USER=postgres diff --git a/{{cookiecutter.project_slug}}/Makefile b/{{cookiecutter.project_slug}}/Makefile index 4559c0d..2e4f5b1 100644 --- a/{{cookiecutter.project_slug}}/Makefile +++ b/{{cookiecutter.project_slug}}/Makefile @@ -12,7 +12,7 @@ build: rebuild: down build up -deploy: down build up makemigrate +deploy: down build up migrations deploy-prod: docker compose -f docker-compose.prod.yml down @@ -23,7 +23,7 @@ deploy-prod: logs: docker compose logs -f -makemigration: +makemigrations: docker compose exec web python manage.py makemigrations --noinput migrate: @@ -35,9 +35,9 @@ seed: reset_db: docker compose exec web python manage.py reset_db --no-input -makemigrate: makemigration migrate +migrations: makemigrations migrate -fresh: reset_db makemigrate seed +fresh: reset_db migrations seed test: docker compose exec web pytest -v diff --git a/{{cookiecutter.project_slug}}/README.EN.md b/{{cookiecutter.project_slug}}/README.EN.md new file mode 100644 index 0000000..887e642 --- /dev/null +++ b/{{cookiecutter.project_slug}}/README.EN.md @@ -0,0 +1,245 @@ +# JST-Django Template Documentation + +**Language:** [O'zbek](README.MD) | English + +Welcome! This is a comprehensive Django project template designed to streamline Django application development with pre-configured architecture, best practices, and powerful CLI tools. + +## Overview + +This template consists of two main components: + +1. **CLI Tool** - Command-line interface for generating Django apps and modules +2. **Architecture Template** - Production-ready Django project structure with Docker, pre-configured packages, and best practices + +> **Note:** While these components can be used independently, using them together provides the best development experience. + +## Key Features + +- πŸš€ Production-ready Django project structure +- 🐳 Docker & Docker Compose configuration +- πŸ“¦ Pre-configured popular packages (DRF, Celery, Redis, etc.) +- πŸ”§ CLI tool for rapid app/module generation +- 🌐 Multi-language support (modeltranslation/parler) +- πŸ”’ Security best practices included +- πŸ“ API documentation with Swagger/ReDoc +- βœ… Testing setup with pytest + +## Installation + +Install the CLI tool via pip: + +```bash +pip install -U jst-django +``` + +> **Important:** Always use the latest version of the CLI tool for compatibility with the template. + +## Quick Start + +### 1. Create a New Project + +```bash +jst create +``` + +You will be prompted for: + +- **Template**: Choose "django" (default) +- **Project Name**: Your project name (used throughout the project) +- **Settings File**: Keep default +- **Packages**: Select additional packages you need: + - modeltranslation or parler (choose one for translations) + - silk (performance profiling) + - channels (WebSocket support) + - ckeditor (rich text editor) + - and more... +- **Runner**: wsgi or asgi (choose asgi for WebSocket/async features) +- **Django Secret Key**: Change in production! +- **Port**: Default 8081 +- **Admin Password**: Set a strong password +- **Flake8**: Code style enforcement (recommended) + +### 2. Start the Project + +**Requirements:** Docker must be installed on your system. + +Navigate to your project directory: + +```bash +cd your_project_name +``` + +Start the project using Make: + +```bash +make up +``` + +Or manually: + +```bash +docker compose up -d +docker compose exec web python manage.py seed +``` + +The project will be available at `http://localhost:8081` + +### 3. Run Tests + +```bash +make test +``` + +## Creating Applications + +### Create a New App + +```bash +jst make:app +``` + +Choose a module type: +- **default**: Empty app structure +- **bot**: Telegram bot integration +- **authbot**: Telegram authentication +- **authv2**: New authentication system +- **websocket**: WebSocket support + +The app will be automatically created and registered. + +## Generating Modules + +The most powerful feature of JST-Django is module generation: + +```bash +jst make:module +``` + +You will be prompted for: + +1. **File Name**: Basename for generated files (e.g., "post") +2. **Module Names**: List of models to generate (e.g., "post, tag, category") +3. **App**: Target application +4. **Components**: Select what to generate: + - Model + - Serializer + - View (ViewSet) + - Admin + - Permissions + - Filters + - Tests + - URLs + +This generates complete CRUD APIs with all selected components! + +## Project Structure + +``` +β”œβ”€β”€ config/ # Configuration files +β”‚ β”œβ”€β”€ settings/ # Environment-specific settings +β”‚ β”‚ β”œβ”€β”€ common.py # Shared settings +β”‚ β”‚ β”œβ”€β”€ local.py # Development settings +β”‚ β”‚ β”œβ”€β”€ production.py # Production settings +β”‚ β”‚ └── test.py # Test settings +β”‚ β”œβ”€β”€ conf/ # Package configurations +β”‚ β”œβ”€β”€ urls.py +β”‚ └── wsgi.py / asgi.py +β”œβ”€β”€ core/ +β”‚ β”œβ”€β”€ apps/ # Django applications +β”‚ β”‚ β”œβ”€β”€ accounts/ # Pre-configured auth system +β”‚ β”‚ └── shared/ # Shared utilities +β”‚ β”œβ”€β”€ services/ # Business logic services +β”‚ └── utils/ # Utility functions +β”œβ”€β”€ docker/ # Docker configurations +β”œβ”€β”€ resources/ # Static resources, scripts +β”œβ”€β”€ Makefile # Convenience commands +β”œβ”€β”€ docker-compose.yml # Docker Compose config +β”œβ”€β”€ requirements.txt # Python dependencies +└── manage.py +``` + +## Available Make Commands + +```bash +make up # Start containers +make down # Stop containers +make build # Build containers +make rebuild # Rebuild and restart +make logs # View logs +make makemigrations # Create migrations +make migrate # Apply migrations +make migrations # Make and apply migrations +make seed # Seed database with initial data +make fresh # Reset DB, migrate, and seed +make test # Run tests +make deploy # Deploy (local) +make deploy-prod # Deploy (production) +``` + +## Security Considerations + +⚠️ **Important:** See [SECURITY.md](SECURITY.md) for detailed security guidelines. + +**Quick checklist:** +- βœ… Change `DJANGO_SECRET_KEY` in production +- βœ… Change default admin password +- βœ… Set `DEBUG=False` in production +- βœ… Configure proper `ALLOWED_HOSTS` +- βœ… Use HTTPS (`PROTOCOL_HTTPS=True`) +- βœ… Change database password +- βœ… Never commit `.env` file + +## Environment Variables + +Key environment variables in `.env`: + +- `DJANGO_SECRET_KEY`: Django secret key (change in production!) +- `DEBUG`: Debug mode (False in production) +- `DB_PASSWORD`: Database password (change in production!) +- `DJANGO_SETTINGS_MODULE`: Settings module to use +- `PROJECT_ENV`: debug | prod +- `SILK_ENABLED`: Enable Silk profiling (optional) + +See `.env.example` for all available options. + +## Additional Packages + +The template supports optional packages: + +- **modeltranslation**: Model field translation +- **parler**: Alternative translation solution +- **silk**: Performance profiling +- **channels**: WebSocket/async support +- **ckeditor**: Rich text editor +- **rosetta**: Translation management +- **cacheops**: Advanced caching + +## Testing + +Tests are written using pytest-django: + +```bash +# Run all tests +make test + +# Run specific tests +docker compose exec web pytest path/to/test.py -v +``` + +## Contributing + +Contributions are welcome! Please feel free to submit issues and pull requests. + +## License + +See [LICENSE](LICENSE) file for details. + +## Support + +For issues and questions: +- Create an issue on GitHub +- Check existing documentation + +--- + +**Happy Coding! πŸš€** diff --git a/{{cookiecutter.project_slug}}/SECURITY.md b/{{cookiecutter.project_slug}}/SECURITY.md new file mode 100644 index 0000000..b0db5e2 --- /dev/null +++ b/{{cookiecutter.project_slug}}/SECURITY.md @@ -0,0 +1,79 @@ +# Security Best Practices / Xavfsizlik bo'yicha eng yaxshi amaliyotlar + +## English + +### Important Security Notes + +1. **Change Default Credentials** + - Never use the default password `2309` in production + - Change the admin phone number from the default value + - Generate a strong SECRET_KEY for production + +2. **Environment Variables** + - Never commit `.env` file to version control + - Keep production credentials secure and separate from development + - Use strong passwords for database and admin accounts + +3. **Database Security** + - Change default database password in production + - Use strong passwords for PostgreSQL + - Restrict database access to specific IP addresses + +4. **Django Security Settings** + - Set `DEBUG=False` in production + - Configure proper `ALLOWED_HOSTS` + - Use HTTPS in production (`PROTOCOL_HTTPS=True`) + - Keep `SECRET_KEY` secret and unique per environment + +5. **API Security** + - Configure proper CORS settings + - Use CSRF protection + - Implement rate limiting + - Use JWT tokens with appropriate expiration times + +6. **Docker Security** + - Don't expose unnecessary ports + - Use docker secrets for sensitive data + - Keep Docker images updated + +## O'zbekcha + +### Muhim xavfsizlik eslatmalari + +1. **Standart parollarni o'zgartiring** + - Production muhitida hech qachon standart parol `2309` dan foydalanmang + - Admin telefon raqamini standart qiymatdan o'zgartiring + - Production uchun kuchli SECRET_KEY yarating + +2. **Environment o'zgaruvchilari** + - Hech qachon `.env` faylini git repozitoriyasiga commit qilmang + - Production ma'lumotlarini xavfsiz va developmentdan alohida saqlang + - Ma'lumotlar bazasi va admin akkountlari uchun kuchli parollar ishlating + +3. **Ma'lumotlar bazasi xavfsizligi** + - Production muhitida standart parolni o'zgartiring + - PostgreSQL uchun kuchli parollar ishlating + - Ma'lumotlar bazasiga kirishni muayyan IP manzillarga cheklang + +4. **Django xavfsizlik sozlamalari** + - Production muhitida `DEBUG=False` qiling + - To'g'ri `ALLOWED_HOSTS` sozlang + - Production muhitida HTTPS dan foydalaning (`PROTOCOL_HTTPS=True`) + - `SECRET_KEY` ni maxfiy va har bir muhitda noyob qiling + +5. **API xavfsizligi** + - To'g'ri CORS sozlamalarini o'rnating + - CSRF himoyasidan foydalaning + - Rate limiting ni amalga oshiring + - JWT tokenlarni to'g'ri muddatda ishlating + +6. **Docker xavfsizligi** + - Keraksiz portlarni ochib qo'ymang + - Maxfiy ma'lumotlar uchun docker secrets dan foydalaning + - Docker imagelarni yangilab turing + +## Reporting Security Issues / Xavfsizlik muammolarini xabar qilish + +If you discover a security vulnerability, please email the maintainers directly instead of using the issue tracker. + +Agar xavfsizlik zaifligini topsangiz, iltimos issue tracker o'rniga to'g'ridan-to'g'ri maintainerlar ga email yuboring. diff --git a/{{cookiecutter.project_slug}}/config/conf/apps.py b/{{cookiecutter.project_slug}}/config/conf/apps.py index a55b972..1940350 100644 --- a/{{cookiecutter.project_slug}}/config/conf/apps.py +++ b/{{cookiecutter.project_slug}}/config/conf/apps.py @@ -16,7 +16,7 @@ "core.apps.accounts.apps.AccountsConfig", ] -if env.bool("SILK_ENEBLED", False): +if env.bool("SILK_ENABLED", False): APPS += [ {% if cookiecutter.silk %}"silk",{% endif %} ] diff --git a/{{cookiecutter.project_slug}}/config/env.py b/{{cookiecutter.project_slug}}/config/env.py index 8665829..d9236a1 100644 --- a/{{cookiecutter.project_slug}}/config/env.py +++ b/{{cookiecutter.project_slug}}/config/env.py @@ -25,5 +25,5 @@ OTP_MODULE="core.services.otp", OTP_SERVICE="EskizService", PROJECT_ENV=(str, "prod"), - SILK_ENEBLED=(bool, False), + SILK_ENABLED=(bool, False), ) diff --git a/{{cookiecutter.project_slug}}/config/settings/common.py b/{{cookiecutter.project_slug}}/config/settings/common.py index 60e6144..87ee5de 100644 --- a/{{cookiecutter.project_slug}}/config/settings/common.py +++ b/{{cookiecutter.project_slug}}/config/settings/common.py @@ -66,7 +66,7 @@ "django.contrib.messages.middleware.MessageMiddleware", "django.middleware.clickjacking.XFrameOptionsMiddleware", ] -if env.bool("SILK_ENEBLED", False): +if env.bool("SILK_ENABLED", False): MIDDLEWARE += [ {% if cookiecutter.silk %}"silk.middleware.SilkyMiddleware",{% endif %} ] diff --git a/{{cookiecutter.project_slug}}/config/urls.py b/{{cookiecutter.project_slug}}/config/urls.py index 72c8321..2ea362d 100644 --- a/{{cookiecutter.project_slug}}/config/urls.py +++ b/{{cookiecutter.project_slug}}/config/urls.py @@ -39,7 +39,7 @@ def home(request): ################ # Project env debug mode ################ -if env.bool("SILK_ENEBLED", False): +if env.bool("SILK_ENABLED", False): urlpatterns += [ {% if cookiecutter.silk %}path('silk/', include('silk.urls', namespace='silk')){% endif %} ] diff --git a/{{cookiecutter.project_slug}}/docker-compose.prod.yml b/{{cookiecutter.project_slug}}/docker-compose.prod.yml index d863d1f..19f1e38 100644 --- a/{{cookiecutter.project_slug}}/docker-compose.prod.yml +++ b/{{cookiecutter.project_slug}}/docker-compose.prod.yml @@ -46,9 +46,9 @@ services: image: postgres:16 restart: always environment: - POSTGRES_DB: django - POSTGRES_USER: postgres - POSTGRES_PASSWORD: '2309' + POSTGRES_DB: ${DB_NAME:-django} + POSTGRES_USER: ${DB_USER:-postgres} + POSTGRES_PASSWORD: ${DB_PASSWORD:?Database password must be set in .env file} volumes: - pg_data:/var/lib/postgresql/data redis: diff --git a/{{cookiecutter.project_slug}}/docker-compose.test.yml b/{{cookiecutter.project_slug}}/docker-compose.test.yml index dbf743d..73d08dc 100644 --- a/{{cookiecutter.project_slug}}/docker-compose.test.yml +++ b/{{cookiecutter.project_slug}}/docker-compose.test.yml @@ -30,9 +30,9 @@ services: restart: always container_name: test_db environment: - POSTGRES_DB: django - POSTGRES_USER: postgres - POSTGRES_PASSWORD: '2309' + POSTGRES_DB: ${DB_NAME:-django} + POSTGRES_USER: ${DB_USER:-postgres} + POSTGRES_PASSWORD: ${DB_PASSWORD:-2309} volumes: - pg_data:/var/lib/postgresql/data redis: diff --git a/{{cookiecutter.project_slug}}/docker-compose.yml b/{{cookiecutter.project_slug}}/docker-compose.yml index c3b6c95..92ea931 100644 --- a/{{cookiecutter.project_slug}}/docker-compose.yml +++ b/{{cookiecutter.project_slug}}/docker-compose.yml @@ -42,9 +42,9 @@ services: image: postgres:16 restart: always environment: - POSTGRES_DB: django - POSTGRES_USER: postgres - POSTGRES_PASSWORD: '2309' + POSTGRES_DB: ${DB_NAME:-django} + POSTGRES_USER: ${DB_USER:-postgres} + POSTGRES_PASSWORD: ${DB_PASSWORD:-2309} volumes: - pg_data:/var/lib/postgresql/data redis: