diff --git a/PLAN.md b/PLAN.md deleted file mode 100644 index d71f59f..0000000 --- a/PLAN.md +++ /dev/null @@ -1,538 +0,0 @@ -# Django Project Architecture Plan - -## Overview - -This project is a modular Django-based project management and business operations platform with: - -- Role-based access control -- Project management -- Private kanban workflows -- Issue tracking -- Ticketing system -- Finance & payroll -- Activity tracking -- HTMX + Alpine.js frontend architecture - ---- - -# Project Structure - -````text -myproject/ -├── config/ # settings, urls, wsgi -├── apps/ -│ ├── accounts/ # CustomUser, role system -│ ├── projects/ # Project, Membership - │ ├── finance/ # Invoice, Payment, Expense, Payroll -│ ├── kanban/ # Board, Column, Card (private per user) - │ ├── issues/ # Issue, Comment, Label, Status - │ ├── tickets/ # Ticket, FeatureRequest - │ └── activity/ # ActivityLog, progress aggregation - ├── templates/ - │ ├── base.html - │ ├── partials/ # HTMX partial templates - │ └── components/ # Alpine.js UI components - └── static/ - ``` - - --- - -# Actors - -## Admin - - Full system access - - Manage users, projects, finance, tickets, and reports - - Read-only access to aggregated kanban progress - -## Client - - View own projects - - Create/view tickets - - View invoices and payments - - Comment on issues - -## Team Member - - Work on assigned issues - - Access own kanban board - - View assigned projects - - Access payroll information - - --- - -# Django Apps Breakdown - -## 1. accounts - -### Responsibilities - - Authentication - - Authorization - - Role management - - Project memberships - -### Main Models - - ```python - class CustomUser(AbstractUser): - ROLE_CHOICES = [ - ("admin", "Admin"), - ("client", "Client"), - ("member", "Team Member"), - ] - - role = models.CharField(max_length=20, choices=ROLE_CHOICES) - ``` - - ```python - class ProjectMembership(models.Model): - user = models.ForeignKey(CustomUser, on_delete=models.CASCADE) - project = models.ForeignKey("projects.Project", on_delete=models.CASCADE) - joined_at = models.DateTimeField(auto_now_add=True) - ``` - - --- - -## 2. projects - -### Responsibilities - - Core project management - - Team assignment - - Project lifecycle - -### Main Models - - ```python - class Project(models.Model): - - class Status(models.TextChoices): - PLANNING = "planning" - ACTIVE = "active" - REVIEW = "review" - DONE = "done" - - name = models.CharField(max_length=255) - client = models.ForeignKey( - "accounts.CustomUser", - on_delete=models.CASCADE, - related_name="client_projects" - ) - -status = models.CharField( - max_length=20, - choices=Status.choices, - default=Status.PLANNING - ) - - members = models.ManyToManyField( - "accounts.CustomUser", - through="accounts.ProjectMembership" - ) - ``` - - --- - -## 3. finance - -### Responsibilities - - Invoices - - Payments - - Expenses - - Payroll management - -### Main Models - -## Invoice - - ```python - class Invoice(models.Model): - - class Status(models.TextChoices): - PENDING = "pending" - PAID = "paid" - OVERDUE = "overdue" - - project = models.ForeignKey("projects.Project", on_delete=models.CASCADE) - client = models.ForeignKey("accounts.CustomUser", on_delete=models.CASCADE) - - amount = models.DecimalField(max_digits=10, decimal_places=2) - due_date = models.DateField() -status = models.CharField(max_length=20, choices=Status.choices) - ``` - -## Payment - - ```python - class Payment(models.Model): - invoice = models.ForeignKey(Invoice, on_delete=models.CASCADE) - paid_at = models.DateTimeField() - method = models.CharField(max_length=100) - ``` - -## Expense - - ```python - class Expense(models.Model): - project = models.ForeignKey("projects.Project", on_delete=models.CASCADE) - raised_by = models.ForeignKey("accounts.CustomUser", on_delete=models.CASCADE) - - amount = models.DecimalField(max_digits=10, decimal_places=2) -category = models.CharField(max_length=100) - ``` - -## TeamPayment - - ```python - class TeamPayment(models.Model): - member = models.ForeignKey("accounts.CustomUser", on_delete=models.CASCADE) - period = models.DateField() - amount = models.DecimalField(max_digits=10, decimal_places=2) - ``` - - --- - -## 4. kanban - -### Responsibilities - - Personal task management - - Progress tracking - - Drag-and-drop workflow - -### Privacy Rules - - Each board belongs to one user - - Members cannot access others' boards - - Admin sees only aggregated progress - -### Main Models - -## Board - - ```python - class Board(models.Model): - owner = models.ForeignKey( - "accounts.CustomUser", - on_delete=models.CASCADE - ) - - project = models.ForeignKey( - "projects.Project", - null=True, - blank=True, - on_delete=models.CASCADE - ) - ``` - -## Column - - ```python - class Column(models.Model): - board = models.ForeignKey(Board, on_delete=models.CASCADE) - name = models.CharField(max_length=100) - order = models.PositiveIntegerField() - ``` - -## Card - - ```python - class Card(models.Model): - column = models.ForeignKey(Column, on_delete=models.CASCADE) - - title = models.CharField(max_length=255) -description = models.TextField(blank=True) - - due_date = models.DateField(null=True, blank=True) -order = models.PositiveIntegerField() - ``` - -### Secure QuerySet Pattern - - ```python - class BoardQuerySet(models.QuerySet): - - def for_user(self, user): - return self.filter(owner=user) - ``` - - --- - -## 5. issues - -### Responsibilities - - Bug tracking - - Feature tracking - - Task assignment - - Internal discussion - -### Main Models - -## Issue - - ```python - class Issue(models.Model): - - class Status(models.TextChoices): - OPEN = "open" - IN_PROGRESS = "in_progress" - RESOLVED = "resolved" - CLOSED = "closed" - - class Priority(models.TextChoices): - LOW = "low" - MEDIUM = "medium" - HIGH = "high" - - project = models.ForeignKey("projects.Project", on_delete=models.CASCADE) - - reporter = models.ForeignKey( - "accounts.CustomUser", - on_delete=models.CASCADE, - related_name="reported_issues" - ) - - assignee = models.ForeignKey( - "accounts.CustomUser", - null=True, - blank=True, - on_delete=models.SET_NULL, - related_name="assigned_issues" - ) - - status = models.CharField(max_length=20, choices=Status.choices) -priority = models.CharField(max_length=20, choices=Priority.choices) - ``` - -## IssueComment - - ```python - class IssueComment(models.Model): - issue = models.ForeignKey(Issue, on_delete=models.CASCADE) - author = models.ForeignKey("accounts.CustomUser", on_delete=models.CASCADE) - body = models.TextField() - ``` - - --- - -## 6. tickets - -### Responsibilities - - Client support - - Feature requests - - Bug reporting - -### Main Models - - ```python - class Ticket(models.Model): - - class TicketType(models.TextChoices): - BUG = "bug" - FEATURE = "feature_request" - SUPPORT = "support" - - class Status(models.TextChoices): - NEW = "new" - ACKNOWLEDGED = "acknowledged" - IN_PROGRESS = "in_progress" - DONE = "done" - REJECTED = "rejected" - - creator = models.ForeignKey( - "accounts.CustomUser", - on_delete=models.CASCADE - ) - - project = models.ForeignKey( - "projects.Project", - null=True, - blank=True, - on_delete=models.CASCADE - ) - - ticket_type = models.CharField(max_length=30, choices=TicketType.choices) -status = models.CharField(max_length=30, choices=Status.choices) - ``` - -### Access Rules - - Only admin and client can create tickets - - Team members can only view assigned tickets - - Tickets may be converted into issues - - --- - -## 7. activity - -### Responsibilities - - Audit logging - - Timeline tracking - - Progress aggregation - -### Main Models - - ```python - class ActivityLog(models.Model): - actor = models.ForeignKey( - "accounts.CustomUser", - on_delete=models.CASCADE - ) - - verb = models.CharField(max_length=255) - -content_type = models.ForeignKey( - ContentType, - on_delete=models.CASCADE - ) - -object_id = models.PositiveIntegerField() - -timestamp = models.DateTimeField(auto_now_add=True) - ``` - -### Rules - - Members cannot view other members' activity logs - - Admin dashboard uses aggregated activity metrics - - --- - -# Frontend Stack - -## HTMX - Use HTMX for: - - Kanban drag-and-drop persistence - - Ticket status updates - - Issue comments - - Live search - - Partial rendering - - Inline updates - -## Alpine.js - Use Alpine.js for: - - Modal state - - Dropdowns - - Tabs - - Confirm dialogs - - Inline edit toggles - -## Suggested Drag-and-Drop Pattern - - - Use Sortable.js for drag UI - - Trigger HTMX POST request on drag end - - Persist new ordering server-side - - --- - -# Permission Pattern - - Instead of Django object permissions, use reusable helper functions and view mixins. - -## Example - - ```python - class ProjectMemberRequired(LoginRequiredMixin): - - def dispatch(self, request, *args, **kwargs): - - project = get_object_or_404( - Project, - pk=kwargs["pk"] - ) - - if not project.members.filter( - pk=request.user.pk - ).exists(): - raise PermissionDenied - - return super().dispatch(request, *args, **kwargs) - ``` - - --- - -# Access Control Matrix - - | Module | Admin | Client | Team Member | - |------------------|----------------|----------------------|---------------------| - | Kanban Board | Progress only | No access | Own board only | - | Issues | Full | View + comment | Assigned only | - | Tickets/Features | Full | Create + view own | View assigned | - | Finance | Full | Own invoices | Own payroll | - | Projects | Full | View own project | Assigned project | - - --- - -# Suggested Folder Layout - - ```text - core/ - ├── accounts - ├── projects - ├── notifications - └── activity - - features/ - ├── kanban - ├── issues - └── tickets - - finance/ - ├── invoices - ├── payments - ├── expenses - └── payroll - - templates/ - ├── base - ├── components - ├── partials - └── pages - ``` - - --- - -# Recommended Tech Stack - -## Backend - - Django -- Django REST Framework (optional API layer) - - PostgreSQL - - Redis - - Celery - -## Frontend - - HTMX - - Alpine.js - - Tailwind CSS - - django-tailwind-cli - -## Infrastructure - - Nginx - - Gunicorn - - Docker - - GitHub Actions CI/CD - - --- - -# Future Improvements - - - Real-time notifications with Django Channels - - WebSocket activity feed - - Time tracking - - Project analytics dashboard - - File attachments - - Email automation - - AI-assisted issue summaries - - Multi-tenant architecture - - --- - -# Final Notes - - This architecture keeps: - - Apps modular - - Permissions predictable - - HTMX interactions clean - - Kanban privacy secure - - Finance isolated - - Features scalable - - The structure is optimized for: - - Long-term maintainability - - Team collaboration - - Incremental feature expansion - - Clear domain separation -```` diff --git a/Procfile b/Procfile deleted file mode 100644 index a36a146..0000000 --- a/Procfile +++ /dev/null @@ -1,20 +0,0 @@ -# Procfile for config -# Used for deploying to PaaS platforms like Heroku, Railway, Render, etc. - -# Web server process (using Gunicorn) -# Adjust workers based on your needs: (2 x CPU cores) + 1 -web: gunicorn config.wsgi:application --bind 0.0.0.0:$PORT --workers 2 --timeout 120 --access-logfile - --error-logfile - --log-level info - -# Alternative web server configurations (uncomment to use): -# web: gunicorn config.wsgi:application --bind 0.0.0.0:$PORT --workers 4 --threads 2 --timeout 120 -# web: gunicorn config.wsgi:application --bind 0.0.0.0:$PORT --workers 2 --worker-class gevent --worker-connections 1000 --timeout 120 - -# Release task (runs migrations before deployment) -release: python manage.py migrate --noinput && python manage.py collectstatic --noinput - -# Uncomment below to run scheduled tasks (if using Celery) -# worker: celery -A config worker --loglevel=info -# beat: celery -A config beat --loglevel=info - -# Development server (for local testing with Foreman/Overmind) -# web: python manage.py runserver 0.0.0.0:$PORT \ No newline at end of file diff --git a/README.md b/README.md deleted file mode 100644 index 002b126..0000000 --- a/README.md +++ /dev/null @@ -1,112 +0,0 @@ -# config - -A Django project folder structure is generated with [djinitx/djinit/dj](https://github.com/S4NKALP/djinit). - -## Features - -- Modern project structure with environment-specific settings -- Pre-configured REST API with JWT authentication -- Essential dependencies and utilities -- Production-ready configuration - -## Setup - -### Using Just (Recommended) - -1. Set environment variables in `.env` file - -2. Run setup (installs dependencies, runs migrations, creates superuser): - ```bash - just setup - ``` - -3. Start development server: - ```bash - just dev - ``` - -### Traditional Method - -1. Install dependencies: - ```bash - pip install -r requirements.txt - ``` - -2. Set environment variables in `.env` file - -3. Run migrations: - ```bash - python manage.py migrate - ``` - -4. Create superuser: - ```bash - python manage.py createsuperuser - ``` - -5. Start development server: - ```bash - python manage.py runserver - ``` - -## Available Commands - -Run `just` to see all available commands, including: - -- `just dev` - Run development server -- `just migrate` - Run migrations -- `just makemigrations` - Create migrations -- `just createsuperuser` - Create superuser -- `just test` - Run tests -- `just lint` - Lint code -- `just format` - Format code -- `just shell` - Django shell -- `just clean` - Clean cache files -- `just install ` - Install package -- `just remove ` - Remove package -- `just server` - Run production server -- `just ci` - Run all linting and checks -- `just test-coverage` - Run tests with coverage - -## Project Structure - -``` -config/ -├── config/ -│ ├── settings/ -│ │ ├── base.py -│ │ ├── development.py -│ │ └── production.py -│ ├── admin/ -│ ├── api/ # API endpoints organized by model -│ │ ├── user/ # Example: if you have a User model -│ │ │ ├── views.py -│ │ │ ├── serializers.py -│ │ │ └── urls.py -│ │ └── urls.py -│ ├── models/ # Django models -│ ├── tests/ -│ ├── urls.py -│ ├── wsgi.py -│ └── asgi.py -├── manage.py -├── requirements.txt -├── pyproject.toml -├── uv.lock -├── .env.sample -└── README.md - -**Note:** For the single folder layout, organize your API endpoints by model name under the `api/` directory. -For example, if you have a `User` model in `models/user.py`, create: -- `api/user/views.py` - API views for User -- `api/user/serializers.py` - Serializers for User -- `api/user/urls.py` - URL patterns for User endpoints - -See the README files in `api/` and `models/` directories for more details. -``` - -## API Documentation - -When running in development mode, API documentation is available at: -- Swagger UI: http://localhost:8000/docs/ -- Schema: http://localhost:8000/schema/ \ No newline at end of file diff --git a/justfile b/justfile deleted file mode 100644 index ab66d62..0000000 --- a/justfile +++ /dev/null @@ -1,229 +0,0 @@ -# Justfile for config -# Task runner for Django development -# Install just: https://github.com/casey/just - -# Default task: show available commands -default: - @just --list - -# Run development server -dev: - uv run python manage.py runserver - -# Run development server with custom host and port -dev-server HOST="0.0.0.0" PORT="8000": - uv run python manage.py runserver {{ HOST }}:{{ PORT }} - -# Create migrations for all apps -makemigrations: - uv run python manage.py makemigrations - -# Create migrations for specific app -makemigrations-app APP: - uv run python manage.py makemigrations {{ APP }} - -# Run all migrations -migrate: - uv run python manage.py migrate - -# Reset database (delete all migrations) -reset-db: - uv run python manage.py flush --noinput - uv run python manage.py migrate - -# Create superuser -createsuperuser: - uv run python manage.py createsuperuser - -# Collect static files -collectstatic: - uv run python manage.py collectstatic --noinput - -# Run Django shell -shell: - uv run python manage.py shell - -# Run Django shell plus (IPython) -shell-plus: - uv run python manage.py shell_plus - -# Run tests -test: - uv run python manage.py test - -# Run tests with coverage -test-coverage: - uv run pytest --cov=. --cov-report=html --cov-report=term - -# Lint code with ruff -lint: - uv run ruff check . - -# Format code with ruff -format: - uv run ruff format . - -# Lint and format code -style: - uv run ruff check . - uv run ruff format . - -# Check security issues -check: - uv run python manage.py check - -# Check security issues (production settings) -check-deploy: - uv run python manage.py check --deploy - -# Show all database migrations status -showmigrations: - uv run python manage.py showmigrations - -# Sync dependencies (uv equivalent of pip freeze) -requirements: - #!/usr/bin/env -S uv run python - import tomllib - from pathlib import Path - pyproject = Path("pyproject.toml") - if not pyproject.exists(): - print("pyproject.toml not found") - raise SystemExit(1) - data = tomllib.loads(pyproject.read_text()) - deps = data.get("project", {}).get("dependencies", []) - Path("requirements.txt").write_text("\n".join(deps) + "\n") - print("Generated requirements.txt from pyproject.toml") - -# Run all linting and checks -ci: - uv run ruff check . - uv run ruff format --check . - uv run python manage.py check - -# Start interactive shell -shell-ipython: - uv run python manage.py shell_plus - -# Clear all cache -clear-cache: - uv run python manage.py clear_cache - -# Show Django version -version: - uv run python manage.py version - -# Run database shell -dbshell: - uv run python manage.py dbshell - -# Start production server with gunicorn -server: - uv run gunicorn config.wsgi:application --bind 0.0.0.0:8000 - -# Start production server with gunicorn workers -server-prod WORKERS="4": - uv run gunicorn config.wsgi:application --bind 0.0.0.0:8000 --workers {{ WORKERS }} - -# Start production server with gunicorn and reload on file changes -server-watch: - uv run gunicorn config.wsgi:application --bind 0.0.0.0:8000 --reload - -# Clean Python cache files -clean: - find . -type d -name "__pycache__" -exec rm -rf {} + - find . -type f -name "*.pyc" -delete - find . -type f -name "*.pyo" -delete - find . -type f -name ".coverage" -delete - find . -type d -name "*.egg-info" -exec rm -rf {} + - rm -rf htmlcov/ - rm -rf .pytest_cache/ - -# Pin dependencies in pyproject.toml using versions from uv.lock, keeping >= and extras -pin-deps: - #!/usr/bin/env -S uv run python - import tomllib, re - from pathlib import Path - - lock = Path("uv.lock") - if not lock.exists(): - print("uv.lock not found — run `uv sync` first") - raise SystemExit(0) - - data = tomllib.loads(lock.read_text()) - packages = {p["name"].lower(): p["version"] for p in data.get("package", [])} - - py = Path("pyproject.toml") - lines = py.read_text().splitlines() - - pattern = re.compile(r'^(\s*)"([^"]+)"(,?)') - - out = [] - for line in lines: - m = pattern.match(line) - if not m: - out.append(line) - continue - - indent, dep, comma = m.groups() - - base = dep - extras = "" - operator = ">=" - version = None - - # extras: django[postgres] - if "[" in base and "]" in base: - before, after = base.split("[", 1) - extras = "[" + after.split("]")[0] + "]" - base = before - - # detect >= or == - if ">=" in dep: - operator = ">=" - base, version = dep.split(">=") - base = base.strip() - elif "==" in dep: - operator = "==" - base, version = dep.split("==") - base = base.strip() - else: - base = dep - - base_lower = base.lower() - new_version = packages.get(base_lower) - - if new_version: - new_dep = f'{base}{extras}{operator}{new_version}' - line = f'{indent}"{new_dep}"{comma}' - - out.append(line) - - py.write_text("\n".join(out) + "\n") - print("Pinned dependencies (>= preserved, extras preserved).") - - -# Setup project for development (using uv) -setup: - uv sync - just pin-deps - uv run python manage.py migrate - uv run python manage.py createsuperuser - -# Complete setup including static files -setup-complete: - uv sync - uv run python manage.py migrate - uv run python manage.py collectstatic --noinput - uv run python manage.py createsuperuser - -# Install a new package -install PACKAGE: - uv add {{ PACKAGE }} - -# Install a dev package -install-dev PACKAGE: - uv add --dev {{ PACKAGE }} - -# Remove a package -remove PACKAGE: - uv remove {{ PACKAGE }} \ No newline at end of file diff --git a/manage.py b/manage.py deleted file mode 100755 index acda5d2..0000000 --- a/manage.py +++ /dev/null @@ -1,32 +0,0 @@ -#!/usr/bin/env python - -"""generated with djinit""" - -"""Django's command-line utility for administrative tasks.""" -import os -import sys - -import environ - - -def main(): - """Run administrative tasks.""" - os.environ.setdefault("DJANGO_SETTINGS_MODULE", os.getenv("DJANGO_SETTINGS_MODULE", "config.settings.production")) - - try: - from django.core.management import execute_from_command_line - except ImportError as exc: - raise ImportError( - "Couldn't import Django. Are you sure it's installed and " - "available on your PYTHONPATH environment variable? Did you " - "forget to activate a virtual environment?" - ) from exc - execute_from_command_line(sys.argv) - - -if __name__ == "__main__": - env = environ.Env() - # Read .env file, if it exists - environ.Env.read_env() - - main() \ No newline at end of file diff --git a/pyproject.toml b/pyproject.toml deleted file mode 100644 index 94d2748..0000000 --- a/pyproject.toml +++ /dev/null @@ -1,40 +0,0 @@ -[project] -name = "backend" -version = "0.1.0" -description = "" -readme = "README.md" -requires-python = ">=3.13" -license = { text = "MIT" } -dependencies = [ - "django>=6.0.5", - "django-environ>=0.13.0", - "django-jazzmin==3.0.1", - "whitenoise>=6.12.0", - "psycopg[binary]", - "dj-database-url>=3.1.2", - "gunicorn>=26.0.0", - "django-tailwind-cli>=4.6.2", - "django-htmx>=1.27.0" -] - -[tool.ruff] -line-length = 88 -target-version = "py313" - -[tool.ruff.lint] -select = [ - "E", # pycodestyle errors - "W", # pycodestyle warnings - "F", # pyflakes - "I", # isort - "B", # flake8-bugbear - "C4", # flake8-comprehensions - "UP", # pyupgrade -] -ignore = [ - "E501", # line too long, handled by formatter - "B008", # do not perform function calls in argument defaults -] - -[tool.ruff.lint.isort] -known-first-party = ["config"] diff --git a/requirements.txt b/requirements.txt deleted file mode 100644 index 2aecf60..0000000 --- a/requirements.txt +++ /dev/null @@ -1,9 +0,0 @@ -django>=6.0.5 -django-environ>=0.13.0 -django-jazzmin==3.0.1 -whitenoise>=6.12.0 -psycopg[binary] -dj-database-url>=3.1.2 -gunicorn>=26.0.0 -django-tailwind-cli>=4.6.2 -django-htmx>=1.27.0 diff --git a/runtime.txt b/runtime.txt deleted file mode 100644 index 3bbfd95..0000000 --- a/runtime.txt +++ /dev/null @@ -1 +0,0 @@ -python-3.13 \ No newline at end of file diff --git a/skills-lock.json b/skills-lock.json deleted file mode 100644 index fd0d0b9..0000000 --- a/skills-lock.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "version": 1, - "skills": { - "frontend-design": { - "source": "anthropics/skills", - "sourceType": "github", - "skillPath": "skills/frontend-design/SKILL.md", - "computedHash": "063a0e6448123cd359ad0044cc46b0e490cc7964d45ef4bb9fd842bd2ffbca67" - }, - "interface-design": { - "source": "Dammyjay93/interface-design", - "sourceType": "github", - "skillPath": ".claude/skills/interface-design/SKILL.md", - "computedHash": "d004c5e5e2e7132e1d64e9c2a339db7f7aaa69053a5c19cddc210dd35dd6fff5" - } - } -} diff --git a/uv.lock b/uv.lock deleted file mode 100644 index 4f38678..0000000 --- a/uv.lock +++ /dev/null @@ -1,329 +0,0 @@ -version = 1 -revision = 3 -requires-python = ">=3.13" - -[[package]] -name = "annotated-doc" -version = "0.0.4" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/57/ba/046ceea27344560984e26a590f90bc7f4a75b06701f653222458922b558c/annotated_doc-0.0.4.tar.gz", hash = "sha256:fbcda96e87e9c92ad167c2e53839e57503ecfda18804ea28102353485033faa4", size = 7288, upload-time = "2025-11-10T22:07:42.062Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/1e/d3/26bf1008eb3d2daa8ef4cacc7f3bfdc11818d111f7e2d0201bc6e3b49d45/annotated_doc-0.0.4-py3-none-any.whl", hash = "sha256:571ac1dc6991c450b25a9c2d84a3705e2ae7a53467b5d111c24fa8baabbed320", size = 5303, upload-time = "2025-11-10T22:07:40.673Z" }, -] - -[[package]] -name = "asgiref" -version = "3.11.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/63/40/f03da1264ae8f7cfdbf9146542e5e7e8100a4c66ab48e791df9a03d3f6c0/asgiref-3.11.1.tar.gz", hash = "sha256:5f184dc43b7e763efe848065441eac62229c9f7b0475f41f80e207a114eda4ce", size = 38550, upload-time = "2026-02-03T13:30:14.33Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/5c/0a/a72d10ed65068e115044937873362e6e32fab1b7dce0046aeb224682c989/asgiref-3.11.1-py3-none-any.whl", hash = "sha256:e8667a091e69529631969fd45dc268fa79b99c92c5fcdda727757e52146ec133", size = 24345, upload-time = "2026-02-03T13:30:13.039Z" }, -] - -[[package]] -name = "backend" -version = "0.1.0" -source = { virtual = "." } -dependencies = [ - { name = "dj-database-url" }, - { name = "django" }, - { name = "django-environ" }, - { name = "django-htmx" }, - { name = "django-jazzmin" }, - { name = "django-tailwind-cli" }, - { name = "gunicorn" }, - { name = "psycopg", extra = ["binary"] }, - { name = "whitenoise" }, -] - -[package.metadata] -requires-dist = [ - { name = "dj-database-url", specifier = ">=3.1.2" }, - { name = "django", specifier = ">=6.0.5" }, - { name = "django-environ", specifier = ">=0.13.0" }, - { name = "django-htmx", specifier = ">=1.27.0" }, - { name = "django-jazzmin", specifier = "==3.0.1" }, - { name = "django-tailwind-cli", specifier = ">=4.6.2" }, - { name = "gunicorn", specifier = ">=26.0.0" }, - { name = "psycopg", extras = ["binary"] }, - { name = "whitenoise", specifier = ">=6.12.0" }, -] - -[[package]] -name = "click" -version = "8.4.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "colorama", marker = "sys_platform == 'win32'" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/9b/98/518d8e5081007684232226f475082b30087d0f585e8457db087298259f49/click-8.4.1.tar.gz", hash = "sha256:918b5633eddf6b41c32d4f454bf0de810065c74e3f7dbf8ee5452f8be88d3e96", size = 353007, upload-time = "2026-05-22T04:08:37.769Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/c7/0d/67e5b4109ea4a837e80daa87c2c696711955e40449a97e8926672534def2/click-8.4.1-py3-none-any.whl", hash = "sha256:482be17c6991b8c19c5429a1e995d9b0efdbb63172824c41f99965dc0ade8ec2", size = 116639, upload-time = "2026-05-22T04:08:35.26Z" }, -] - -[[package]] -name = "colorama" -version = "0.4.6" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/d8/53/6f443c9a4a8358a93a6792e2acffb9d9d5cb0a5cfd8802644b7b1c9a02e4/colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44", size = 27697, upload-time = "2022-10-25T02:36:22.414Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size = 25335, upload-time = "2022-10-25T02:36:20.889Z" }, -] - -[[package]] -name = "dj-database-url" -version = "3.1.2" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "django" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/03/f6/00b625e9d371b980aa261011d0dc906a16444cb688f94215e0dc86996eb5/dj_database_url-3.1.2.tar.gz", hash = "sha256:63c20e4bbaa51690dfd4c8d189521f6bf6bc9da9fcdb23d95d2ee8ee87f9ec62", size = 11490, upload-time = "2026-02-19T15:30:23.638Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/cf/a9/57c66006373381f1d3e5bd94216f1d371228a89f443d3030e010f73dd198/dj_database_url-3.1.2-py3-none-any.whl", hash = "sha256:544e015fee3efa5127a1eb1cca465f4ace578265b3671fe61d0ed7dbafb5ec8a", size = 8953, upload-time = "2026-02-19T15:30:39.37Z" }, -] - -[[package]] -name = "django" -version = "6.0.5" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "asgiref" }, - { name = "sqlparse" }, - { name = "tzdata", marker = "sys_platform == 'win32'" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/5e/f1/bf85f0d29ef76abf901f193fe8fef4769d3da7794197832bc30151c071d8/django-6.0.5.tar.gz", hash = "sha256:bc6d6872e98a2864c836e42edd644b362db311147dd5aa8d5b82ba7a032f5269", size = 10924131, upload-time = "2026-05-05T13:54:39.329Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/94/5b/1328f8b84fce040c404f76822bf8c57d254e368e8cbd8bd67ec2b26d75f5/django-6.0.5-py3-none-any.whl", hash = "sha256:9d58a7cb49244e74c8e161d5e403a46d6209f1009ba40f5a66d6aa0d0786a8f0", size = 8368680, upload-time = "2026-05-05T13:54:33.532Z" }, -] - -[[package]] -name = "django-environ" -version = "0.13.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/18/3c/60983e6ec9b24a8d8588eecebfd21123cba980bce0a905807a27692f0860/django_environ-0.13.0.tar.gz", hash = "sha256:6c401e4c219442c2c4588c2116d5292b5484a6f69163ed09cd41f3943bfb645f", size = 63529, upload-time = "2026-02-18T01:08:08.791Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/c4/00/3767393ece946084e1c6830a33ffb8e39d68642e27ad5ac7d4c8bd5de866/django_environ-0.13.0-py3-none-any.whl", hash = "sha256:37799d14cd78222c6fd8298e48bfe17965ff8e586091ad66a463e52e0e7b799e", size = 20682, upload-time = "2026-02-18T01:08:07.359Z" }, -] - -[[package]] -name = "django-htmx" -version = "1.27.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "asgiref" }, - { name = "django" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/34/f2/8c3e28a5eed8e5226835c762892bfef74eda7e8629c65b49c186098eb303/django_htmx-1.27.0.tar.gz", hash = "sha256:036e5da801bfdf5f1ca815f21592cfb9f004a898f330c842f15e55c70e301a75", size = 65362, upload-time = "2025-11-28T23:18:55.049Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/23/ac/25d28489dc43224e260f4ebee7565f7ef1efe12af0f284a89500c19f75e2/django_htmx-1.27.0-py3-none-any.whl", hash = "sha256:13e1e13b87d39b57f95aae6e4987cb3df056d0b1373a41f4a94504a00298ffd8", size = 62126, upload-time = "2025-11-28T23:18:53.57Z" }, -] - -[[package]] -name = "django-jazzmin" -version = "3.0.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "django" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/84/96/21b6255e90d92a3eb4e93bea9376635d54258e0353ebb913a55e40ae9254/django_jazzmin-3.0.1.tar.gz", hash = "sha256:67ae148bade41267a09ca8e4352ddefa6121795ebbac238bb9a6564ff841eb1b", size = 2053550, upload-time = "2024-10-08T17:40:59.771Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/ad/5b/2f8c4b168e6c41bf1e4b14d787deb23d80f618f0693db913bbe208a4a907/django_jazzmin-3.0.1-py3-none-any.whl", hash = "sha256:12a0a4c1d4fd09c2eef22acf6a1f03112b515ba695c59faa8ea80efc81c1f21b", size = 2125957, upload-time = "2024-10-08T17:40:57.359Z" }, -] - -[[package]] -name = "django-tailwind-cli" -version = "4.6.2" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "django" }, - { name = "django-typer" }, - { name = "semver" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/dd/4e/67143e297e6196f3a7661ab912f888493fb9b40c2f50dd04964a7f22f055/django_tailwind_cli-4.6.2.tar.gz", hash = "sha256:479b82096ed2656c8990f59ae2ee2d1ea2abace7d82ba6013a0861502a906004", size = 122664, upload-time = "2026-05-14T09:12:48.168Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/b6/8b/ed7e4d5757341e7a7daba9d8daa7152c80613208693d1ebb180d579e1428/django_tailwind_cli-4.6.2-py3-none-any.whl", hash = "sha256:5fed9b26c56533fa7c41a92f369ebd41da50b2f520414d5f77b0f2bf9a3caebc", size = 38388, upload-time = "2026-05-14T09:12:46.968Z" }, -] - -[[package]] -name = "django-typer" -version = "3.7.3" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "click" }, - { name = "django" }, - { name = "typer" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/c7/de/8b38b5d7277e70a00adc6328532f174c632facdf99553b904f79e8aad026/django_typer-3.7.3.tar.gz", hash = "sha256:833059b0bddd5a0c68945c4963064ebb0662b54eec803f86b43904ba6038b777", size = 2977182, upload-time = "2026-05-24T14:33:55.391Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/2f/ee/ff00e923a81de3ea95deac71667744079d1e2709249631a5484a57b7baf6/django_typer-3.7.3-py3-none-any.whl", hash = "sha256:2e6591e081117725ef036578ada407dd5882b0213a8aff821d50399854b2c6f1", size = 296863, upload-time = "2026-05-24T14:33:53.502Z" }, -] - -[[package]] -name = "gunicorn" -version = "26.0.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "packaging" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/6d/b7/a4a3f632f823e432ce6bc65f62961b7980c898c77f075a2f7118cb3846fe/gunicorn-26.0.0.tar.gz", hash = "sha256:ca9346f85e3a4aeeb64d491045c16b9a35647abd37ea15efe53080eb8b090baf", size = 727286, upload-time = "2026-05-05T06:38:25.529Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/e6/40/9c2384fc2be4ad25dd4a49decd5ad9ea5a3639814c11bd40ab77cb9f0a14/gunicorn-26.0.0-py3-none-any.whl", hash = "sha256:40233d26a5f0d1872916188c276e21641155111c2853f0c2cd55260aec0d24fc", size = 212009, upload-time = "2026-05-05T06:38:23.007Z" }, -] - -[[package]] -name = "markdown-it-py" -version = "4.2.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "mdurl" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/06/ff/7841249c247aa650a76b9ee4bbaeae59370dc8bfd2f6c01f3630c35eb134/markdown_it_py-4.2.0.tar.gz", hash = "sha256:04a21681d6fbb623de53f6f364d352309d4094dd4194040a10fd51833e418d49", size = 82454, upload-time = "2026-05-07T12:08:28.36Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/b3/81/4da04ced5a082363ecfa159c010d200ecbd959ae410c10c0264a38cac0f5/markdown_it_py-4.2.0-py3-none-any.whl", hash = "sha256:9f7ebbcd14fe59494226453aed97c1070d83f8d24b6fc3a3bcf9a38092641c4a", size = 91687, upload-time = "2026-05-07T12:08:27.182Z" }, -] - -[[package]] -name = "mdurl" -version = "0.1.2" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/d6/54/cfe61301667036ec958cb99bd3efefba235e65cdeb9c84d24a8293ba1d90/mdurl-0.1.2.tar.gz", hash = "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba", size = 8729, upload-time = "2022-08-14T12:40:10.846Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl", hash = "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8", size = 9979, upload-time = "2022-08-14T12:40:09.779Z" }, -] - -[[package]] -name = "packaging" -version = "26.2" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/d7/f1/e7a6dd94a8d4a5626c03e4e99c87f241ba9e350cd9e6d75123f992427270/packaging-26.2.tar.gz", hash = "sha256:ff452ff5a3e828ce110190feff1178bb1f2ea2281fa2075aadb987c2fb221661", size = 228134, upload-time = "2026-04-24T20:15:23.917Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl", hash = "sha256:5fc45236b9446107ff2415ce77c807cee2862cb6fac22b8a73826d0693b0980e", size = 100195, upload-time = "2026-04-24T20:15:22.081Z" }, -] - -[[package]] -name = "psycopg" -version = "3.3.4" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "tzdata", marker = "sys_platform == 'win32'" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/db/2f/cb91e5502ec9de1de6f1b76cfbf69531932725361168bb06963620c77e2e/psycopg-3.3.4.tar.gz", hash = "sha256:e21207764952cff81b6b8bdacad9a3939f2793367fdac2987b3aac36a651b5bc", size = 165799, upload-time = "2026-05-01T23:31:55.179Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/5c/e0/7b3dee031daae7743609ce3c746565d4a3ed7c2c186479eb48e34e838c64/psycopg-3.3.4-py3-none-any.whl", hash = "sha256:b6bbc25ccf05c8fad3b061d9db2ef0909a555171b84b07f29458a447253d679a", size = 213001, upload-time = "2026-05-01T23:20:50.816Z" }, -] - -[package.optional-dependencies] -binary = [ - { name = "psycopg-binary", marker = "implementation_name != 'pypy'" }, -] - -[[package]] -name = "psycopg-binary" -version = "3.3.4" -source = { registry = "https://pypi.org/simple" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/09/43/13e9c406fbbf354580476e248a16b64802a376873ebe6339e30bb655572d/psycopg_binary-3.3.4-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:fbd1d4ed566895ad2d3bf4ddfd8bae90026930ddf29df3b9d91d32c8c47866a7", size = 4590377, upload-time = "2026-05-01T23:29:18.782Z" }, - { url = "https://files.pythonhosted.org/packages/22/be/2923cd7c3683e7afdecf4f10796a18de02f5c5ddc0969aa2ad0a8cdd3bbd/psycopg_binary-3.3.4-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:75a9067e236f9b9ae3535b66fe99bddb33d39c0de10112e49b9ab11eee53dc31", size = 4669023, upload-time = "2026-05-01T23:29:25.884Z" }, - { url = "https://files.pythonhosted.org/packages/96/a0/2c913d6fe13d6a8bd13597d36739bf47af063ad9399e402cfecab16f3c1e/psycopg_binary-3.3.4-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:b56b603ebcea8aa10b46228b8410ba7f13e7c2ee54389d4d9be0927fd8ce2a70", size = 5467423, upload-time = "2026-05-01T23:29:33.416Z" }, - { url = "https://files.pythonhosted.org/packages/e7/38/205d10bc1ad0df4a21c5c51659126bd3ea0ef98fcad1e852f78c249bb9c3/psycopg_binary-3.3.4-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:c677c4ad433cb7150c8cd304a0769ae3bcfbe5ea0676eb53faa7b1443b16d0d3", size = 5151137, upload-time = "2026-05-01T23:29:42.013Z" }, - { url = "https://files.pythonhosted.org/packages/36/fc/f0381ddcd45eff3bb70dbca6823a996048d7f507b2ec3fc92c6fabc0fe87/psycopg_binary-3.3.4-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:26df2717e59c0473e4465a97dfb1b7afebaa479277870fd5784d1436470db47c", size = 6736671, upload-time = "2026-05-01T23:29:51.626Z" }, - { url = "https://files.pythonhosted.org/packages/95/40/fa545ae152c24327651e5624e4902121e808270be36c10b12e9939be09bc/psycopg_binary-3.3.4-cp313-cp313-manylinux_2_38_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:1dc1f79fd16bb1f3f4421417a514607539f17804d95c7ed617265369d1981cae", size = 4979601, upload-time = "2026-05-01T23:29:56.961Z" }, - { url = "https://files.pythonhosted.org/packages/86/e4/2f8a47ee97f90cd2b933d0463081d35631ff419de2b8c984a5f369857de0/psycopg_binary-3.3.4-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:136f199a407b5348b9b857c504aff60c77622a28482e7195839ce1b51238c4cc", size = 4510513, upload-time = "2026-05-01T23:30:07.243Z" }, - { url = "https://files.pythonhosted.org/packages/0e/0e/94e842ff4a7f98ed162580ca2e8b8864b28c1e0350f2443f8ee47f821167/psycopg_binary-3.3.4-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:b6f5a29e9c775b9f12a1a717aa7a2c80f9e1db6f27ba44a5b59c80ac61d2ffcf", size = 4187243, upload-time = "2026-05-01T23:30:15.352Z" }, - { url = "https://files.pythonhosted.org/packages/d0/83/fc6c174b672e29b7de996ea77b6cbddf46c891751c3355f6974292baa6b4/psycopg_binary-3.3.4-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:ee17a2cf4943cde261adfad1bbc5bf38d6b3776d7afff74c7cabcbeaeb08c260", size = 3927347, upload-time = "2026-05-01T23:30:21.186Z" }, - { url = "https://files.pythonhosted.org/packages/e9/65/768364d4a97a15b1a7f47ba52688c1686f22941d8332a8398cefc468e25f/psycopg_binary-3.3.4-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:5c4ab71be17bdca30cb34c34c4e1496e2f5d6f20c199c12bad226070b22ef9bf", size = 4236393, upload-time = "2026-05-01T23:30:26.211Z" }, - { url = "https://files.pythonhosted.org/packages/bd/3b/218efbc9e645becd80cdf651acda05f85cfe546b7a9c0458c7cbc8fe1f74/psycopg_binary-3.3.4-cp313-cp313-win_amd64.whl", hash = "sha256:dbfdb9b6cc79f31104a7b162a2b921b765fcc62af6c00540a167a8de47e4ed38", size = 3564592, upload-time = "2026-05-01T23:30:31.764Z" }, - { url = "https://files.pythonhosted.org/packages/48/a6/828c9185701dab71b234c2a76c38a08b098ebfec5020716b4e93807492b5/psycopg_binary-3.3.4-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:28b7398fdd19db3232c884fb24550bdfe951221f510e195e233299e4c9b78f97", size = 4607292, upload-time = "2026-05-01T23:30:38.962Z" }, - { url = "https://files.pythonhosted.org/packages/92/58/5b40dbc9d839045c9dae956960e4fb6d20bcabe6c59a2aa34fc3a371913f/psycopg_binary-3.3.4-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:1fbaa292a3c8bb61b45df1ad3da1908ccee7cb889db9425e3557d9e34e2a4829", size = 4687023, upload-time = "2026-05-01T23:30:47.227Z" }, - { url = "https://files.pythonhosted.org/packages/85/a9/793f0ac107a9003b48441d0d1f9f616d96e0f37458dd8dc12528ceff55fb/psycopg_binary-3.3.4-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:94596f9e7633ee3f6440711d43bb70aa31cc0a46a900ab8b4201a366ace5c9e7", size = 5486985, upload-time = "2026-05-01T23:30:55.517Z" }, - { url = "https://files.pythonhosted.org/packages/8f/26/42e8533497e2592334f68ec529cf5f840f7fa4e99575a4bb61aa184dbfbf/psycopg_binary-3.3.4-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:8c0056529e68dbe9184cd4019a1f3d8f3a4ead2f6fc7a5afcf27d3314edd1277", size = 5168745, upload-time = "2026-05-01T23:31:01.904Z" }, - { url = "https://files.pythonhosted.org/packages/15/af/b7151776cc08d5935d45c833ec818a9beb417cf7c08239af1aafbdae78ee/psycopg_binary-3.3.4-cp314-cp314-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:2c09aad7051326e7603c14e50636db9c01f78272dc54b3accff03d46370461e6", size = 6761486, upload-time = "2026-05-01T23:31:14.511Z" }, - { url = "https://files.pythonhosted.org/packages/d0/ed/c92533b9124712d592cbf1cd6c76da933a2e0acea81dfe1fbe7e735f0cff/psycopg_binary-3.3.4-cp314-cp314-manylinux_2_38_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:514404ed543efd620c85602b747df2a23cf1241b4067199e1a66f2d2757aaa41", size = 4997427, upload-time = "2026-05-01T23:31:20.901Z" }, - { url = "https://files.pythonhosted.org/packages/a2/23/ccadfd0de416aa188356daa199453af24087b042e296088706d190ae0295/psycopg_binary-3.3.4-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:46893c26858be12cc49ca4226ed6a60b4bfccadd946b3bebb783a60b38788228", size = 4533549, upload-time = "2026-05-01T23:31:26.204Z" }, - { url = "https://files.pythonhosted.org/packages/fd/a0/c8f43cee36386f7bc891ab41a9d31ea07cf9826038e732da79f26b1e5f34/psycopg_binary-3.3.4-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:df1d567fc430f6df15c9fcf67d87685fc49bdb325adc0db5af1adfb2f44eb5c9", size = 4210256, upload-time = "2026-05-01T23:31:33.884Z" }, - { url = "https://files.pythonhosted.org/packages/4e/2c/c1547871be3790676e8868b38655496422f94f0978dfb66b74bdba2f1676/psycopg_binary-3.3.4-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:6b9016b1714da4dd5ecaaa75b82098aa5a0b87854ce9b092e21c27c4ae23e014", size = 3946204, upload-time = "2026-05-01T23:31:39.626Z" }, - { url = "https://files.pythonhosted.org/packages/c4/b1/f6670f00fa7ea601584623f6c11602ab92117d83eaff885e0210f6de7418/psycopg_binary-3.3.4-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:47c656a8a7ba6eb0cff1801a4caaa9c8bdc12d03080e273aff1c8ac39971a77e", size = 4255811, upload-time = "2026-05-01T23:31:44.986Z" }, - { url = "https://files.pythonhosted.org/packages/eb/e6/5fff07a70d1f945ed90ae131c3bd76cab32beff7c58c6db15ad5820b6d1f/psycopg_binary-3.3.4-cp314-cp314-win_amd64.whl", hash = "sha256:c37e024c07308cd06cf3ec51bfd0e7f6157585a4d84d1bce4a7f5f7913719bf8", size = 3666849, upload-time = "2026-05-01T23:31:51.165Z" }, -] - -[[package]] -name = "pygments" -version = "2.20.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/c3/b2/bc9c9196916376152d655522fdcebac55e66de6603a76a02bca1b6414f6c/pygments-2.20.0.tar.gz", hash = "sha256:6757cd03768053ff99f3039c1a36d6c0aa0b263438fcab17520b30a303a82b5f", size = 4955991, upload-time = "2026-03-29T13:29:33.898Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl", hash = "sha256:81a9e26dd42fd28a23a2d169d86d7ac03b46e2f8b59ed4698fb4785f946d0176", size = 1231151, upload-time = "2026-03-29T13:29:30.038Z" }, -] - -[[package]] -name = "rich" -version = "15.0.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "markdown-it-py" }, - { name = "pygments" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/c0/8f/0722ca900cc807c13a6a0c696dacf35430f72e0ec571c4275d2371fca3e9/rich-15.0.0.tar.gz", hash = "sha256:edd07a4824c6b40189fb7ac9bc4c52536e9780fbbfbddf6f1e2502c31b068c36", size = 230680, upload-time = "2026-04-12T08:24:00.75Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/82/3b/64d4899d73f91ba49a8c18a8ff3f0ea8f1c1d75481760df8c68ef5235bf5/rich-15.0.0-py3-none-any.whl", hash = "sha256:33bd4ef74232fb73fe9279a257718407f169c09b78a87ad3d296f548e27de0bb", size = 310654, upload-time = "2026-04-12T08:24:02.83Z" }, -] - -[[package]] -name = "semver" -version = "3.0.4" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/72/d1/d3159231aec234a59dd7d601e9dd9fe96f3afff15efd33c1070019b26132/semver-3.0.4.tar.gz", hash = "sha256:afc7d8c584a5ed0a11033af086e8af226a9c0b206f313e0301f8dd7b6b589602", size = 269730, upload-time = "2025-01-24T13:19:27.617Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/a6/24/4d91e05817e92e3a61c8a21e08fd0f390f5301f1c448b137c57c4bc6e543/semver-3.0.4-py3-none-any.whl", hash = "sha256:9c824d87ba7f7ab4a1890799cec8596f15c1241cb473404ea1cb0c55e4b04746", size = 17912, upload-time = "2025-01-24T13:19:24.949Z" }, -] - -[[package]] -name = "shellingham" -version = "1.5.4" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/58/15/8b3609fd3830ef7b27b655beb4b4e9c62313a4e8da8c676e142cc210d58e/shellingham-1.5.4.tar.gz", hash = "sha256:8dbca0739d487e5bd35ab3ca4b36e11c4078f3a234bfce294b0a0291363404de", size = 10310, upload-time = "2023-10-24T04:13:40.426Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/e0/f9/0595336914c5619e5f28a1fb793285925a8cd4b432c9da0a987836c7f822/shellingham-1.5.4-py2.py3-none-any.whl", hash = "sha256:7ecfff8f2fd72616f7481040475a65b2bf8af90a56c89140852d1120324e8686", size = 9755, upload-time = "2023-10-24T04:13:38.866Z" }, -] - -[[package]] -name = "sqlparse" -version = "0.5.5" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/90/76/437d71068094df0726366574cf3432a4ed754217b436eb7429415cf2d480/sqlparse-0.5.5.tar.gz", hash = "sha256:e20d4a9b0b8585fdf63b10d30066c7c94c5d7a7ec47c889a2d83a3caa93ff28e", size = 120815, upload-time = "2025-12-19T07:17:45.073Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/49/4b/359f28a903c13438ef59ebeee215fb25da53066db67b305c125f1c6d2a25/sqlparse-0.5.5-py3-none-any.whl", hash = "sha256:12a08b3bf3eec877c519589833aed092e2444e68240a3577e8e26148acc7b1ba", size = 46138, upload-time = "2025-12-19T07:17:46.573Z" }, -] - -[[package]] -name = "typer" -version = "0.25.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "annotated-doc" }, - { name = "click" }, - { name = "rich" }, - { name = "shellingham" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/e4/51/9aed62104cea109b820bbd6c14245af756112017d309da813ef107d42e7e/typer-0.25.1.tar.gz", hash = "sha256:9616eb8853a09ffeabab1698952f33c6f29ffdbceb4eaeecf571880e8d7664cc", size = 122276, upload-time = "2026-04-30T19:32:16.964Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/3f/f9/2b3ff4e56e5fa7debfaf9eb135d0da96f3e9a1d5b27222223c7296336e5f/typer-0.25.1-py3-none-any.whl", hash = "sha256:75caa44ed46a03fb2dab8808753ffacdbfea88495e74c85a28c5eefcf5f39c89", size = 58409, upload-time = "2026-04-30T19:32:18.271Z" }, -] - -[[package]] -name = "tzdata" -version = "2026.2" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/ba/19/1b9b0e29f30c6d35cb345486df41110984ea67ae69dddbc0e8a100999493/tzdata-2026.2.tar.gz", hash = "sha256:9173fde7d80d9018e02a662e168e5a2d04f87c41ea174b139fbef642eda62d10", size = 198254, upload-time = "2026-04-24T15:22:08.651Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/ce/e4/dccd7f47c4b64213ac01ef921a1337ee6e30e8c6466046018326977efd95/tzdata-2026.2-py2.py3-none-any.whl", hash = "sha256:bbe9af844f658da81a5f95019480da3a89415801f6cc966806612cc7169bffe7", size = 349321, upload-time = "2026-04-24T15:22:05.876Z" }, -] - -[[package]] -name = "whitenoise" -version = "6.12.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/cb/2a/55b3f3a4ec326cd077c1c3defeee656b9298372a69229134d930151acd01/whitenoise-6.12.0.tar.gz", hash = "sha256:f723ebb76a112e98816ff80fcea0a6c9b8ecde835f8ddda25df7a30a3c2db6ad", size = 26841, upload-time = "2026-02-27T00:05:42.028Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/db/eb/d5583a11486211f3ebd4b385545ae787f32363d453c19fffd81106c9c138/whitenoise-6.12.0-py3-none-any.whl", hash = "sha256:fc5e8c572e33ebf24795b47b6a7da8da3c00cff2349f5b04c02f28d0cc5a3cc2", size = 20302, upload-time = "2026-02-27T00:05:40.086Z" }, -]