{"id":51544968,"url":"https://github.com/robertolima-dev/django_rust_libs","last_synced_at":"2026-07-09T17:01:52.284Z","repository":{"id":367168838,"uuid":"1279570643","full_name":"robertolima-dev/django_rust_libs","owner":"robertolima-dev","description":null,"archived":false,"fork":false,"pushed_at":"2026-06-24T20:20:24.000Z","size":22,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-06-24T22:08:52.948Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/robertolima-dev.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-06-24T20:14:11.000Z","updated_at":"2026-06-24T20:20:28.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/robertolima-dev/django_rust_libs","commit_stats":null,"previous_names":["robertolima-dev/django_rust_libs"],"tags_count":null,"template":false,"template_full_name":null,"purl":"pkg:github/robertolima-dev/django_rust_libs","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/robertolima-dev%2Fdjango_rust_libs","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/robertolima-dev%2Fdjango_rust_libs/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/robertolima-dev%2Fdjango_rust_libs/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/robertolima-dev%2Fdjango_rust_libs/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/robertolima-dev","download_url":"https://codeload.github.com/robertolima-dev/django_rust_libs/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/robertolima-dev%2Fdjango_rust_libs/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":35306717,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-07-09T02:00:07.329Z","response_time":57,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2026-07-09T17:01:51.270Z","updated_at":"2026-07-09T17:01:52.272Z","avatar_url":"https://github.com/robertolima-dev.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# api_django_reference\n\nAPI REST em **Django 5.1 + Django REST Framework** com autenticação **JWT** (SimpleJWT)\ne banco de dados **PostgreSQL**. O domínio de usuários vive em `apps/users`.\n\n## Stack\n\n- Django 5.1 / Django REST Framework\n- djangorestframework-simplejwt (JWT)\n- PostgreSQL (driver psycopg 3)\n- python-decouple (config via `.env`)\n- django-cors-headers\n- **Integrações em Rust** (wheels nativas): `rust-py-audit`, `rust-py-rate-limit`,\n  `rust-py-monitor`, `rust-py-scheduler`, `rust-py-cache` — ver\n  [Integrações Rust](#integrações-rust)\n\n## Estrutura\n\n```\napi_django_reference/\n├── config/                 # projeto Django (settings, urls, wsgi, asgi)\n│   ├── settings.py\n│   ├── settings_test.py    # usa SQLite em memória para os testes\n│   └── urls.py\n├── apps/\n│   ├── core/              # integrações Rust compartilhadas\n│   │   ├── services.py    # singletons: cache, audit, rate limiters\n│   │   ├── throttle.py    # ponte rate-limit -\u003e DRF (HTTP 429)\n│   │   ├── scheduler.py   # jobs recorrentes (cleanup, verify)\n│   │   └── apps.py        # inicia o scheduler junto com o servidor\n│   └── users/              # app de usuários\n│       ├── models.py       # User customizado (login por email, UUID pk)\n│       ├── managers.py\n│       ├── serializers.py\n│       ├── views.py\n│       ├── urls.py\n│       ├── tokens.py       # tokens de confirmação de email e reset de senha\n│       ├── emails.py\n│       ├── admin.py\n│       └── tests.py\n├── manage.py\n├── requirements.txt\n└── .env.example\n```\n\n## Setup\n\n```bash\npython3 -m venv .venv\nsource .venv/bin/activate\npip install -r requirements.txt\n\ncp .env.example .env        # ajuste as credenciais do Postgres\n\n# Crie o banco no PostgreSQL (exemplo)\ncreatedb api_django_reference\n\npython manage.py migrate\npython manage.py createsuperuser\npython manage.py runserver\n```\n\n## Testes\n\nRodam em SQLite em memória, sem precisar de Postgres:\n\n```bash\npython manage.py test apps.users --settings=config.settings_test\n```\n\n## Endpoints\n\nBase: `/api/v1/users/`\n\n| Método | Rota                  | Auth | Descrição                                       |\n|--------|-----------------------|------|-------------------------------------------------|\n| POST   | `register/`           | —    | Cria conta e envia email de confirmação         |\n| POST   | `login/`              | —    | Autentica por email/senha, retorna JWT + user   |\n| POST   | `login/refresh/`      | —    | Renova o access token a partir do refresh       |\n| GET    | `me/`                 | JWT  | Dados do usuário autenticado                     |\n| PATCH  | `me/`                 | JWT  | Atualiza dados do usuário autenticado            |\n| POST   | `change-password/`    | JWT  | Troca a senha (exige a senha atual)             |\n| POST   | `forgot-password/`    | —    | Envia link de reset (resposta sempre genérica)  |\n| POST   | `reset-password/`     | —    | Conclui o reset usando `uid` + `token`          |\n| POST   | `confirm-email/`      | —    | Confirma o email usando `uid` + `token`         |\n\n### Exemplos\n\n**Register**\n```bash\ncurl -X POST http://localhost:8000/api/v1/users/register/ \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"email\":\"john@example.com\",\"first_name\":\"John\",\"password\":\"Str0ng-Pass!23\",\"password_confirm\":\"Str0ng-Pass!23\"}'\n```\n\n**Login**\n```bash\ncurl -X POST http://localhost:8000/api/v1/users/login/ \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"email\":\"john@example.com\",\"password\":\"Str0ng-Pass!23\"}'\n# =\u003e { \"access\": \"...\", \"refresh\": \"...\", \"user\": { ... } }\n```\n\n**Me** (use o access token)\n```bash\ncurl http://localhost:8000/api/v1/users/me/ \\\n  -H \"Authorization: Bearer \u003cACCESS_TOKEN\u003e\"\n```\n\n**Change password**\n```bash\ncurl -X POST http://localhost:8000/api/v1/users/change-password/ \\\n  -H \"Authorization: Bearer \u003cACCESS_TOKEN\u003e\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"old_password\":\"Str0ng-Pass!23\",\"new_password\":\"Nova-Senha!99\",\"new_password_confirm\":\"Nova-Senha!99\"}'\n```\n\n**Forgot password**\n```bash\ncurl -X POST http://localhost:8000/api/v1/users/forgot-password/ \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"email\":\"john@example.com\"}'\n```\n\n**Reset password** (uid + token vêm no link do email)\n```bash\ncurl -X POST http://localhost:8000/api/v1/users/reset-password/ \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"uid\":\"\u003cUID\u003e\",\"token\":\"\u003cTOKEN\u003e\",\"new_password\":\"Nova!2024\",\"new_password_confirm\":\"Nova!2024\"}'\n```\n\n**Confirm email** (uid + token vêm no link do email)\n```bash\ncurl -X POST http://localhost:8000/api/v1/users/confirm-email/ \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"uid\":\"\u003cUID\u003e\",\"token\":\"\u003cTOKEN\u003e\"}'\n```\n\n## Integrações Rust\n\nCinco bibliotecas Python implementadas em Rust (alto desempenho, sem overhead de\nserviços externos como Redis). Tudo fica centralizado em `apps/core` e é plugado no\nciclo de vida das views/projeto.\n\n| Lib | Papel no projeto | Onde está |\n|-----|------------------|-----------|\n| `rust-py-monitor` | Métricas de latência/status por request + processo | Middleware global + rota `/metrics/` |\n| `rust-py-rate-limit` | Proteção contra brute-force nos endpoints sensíveis | `apps/core/throttle.py`, aplicado em login/register/forgot |\n| `rust-py-audit` | Log de auditoria encadeado por hash (à prova de adulteração) | `apps/core/services.py`, eventos em `apps/users/views.py` |\n| `rust-py-cache` | Cache in-process do `GET /me` | `apps/core/services.py`, usado em `MeView` |\n| `rust-py-scheduler` | Jobs recorrentes de manutenção | `apps/core/scheduler.py`, iniciado em `CoreConfig.ready()` |\n\nConfiguração relevante em `settings.py`: `RATE_LIMITS`, `USER_CACHE_TTL`,\n`AUDIT_APP_NAME`, `AUDIT_FILE_PATH`, `SCHEDULER_AUTOSTART`.\n\n### 1. rust-py-monitor — métricas Prometheus\n\nO `MonitorMiddleware` mede toda requisição; a rota `/metrics/` expõe no formato\nPrometheus (latências p50/p95/p99, total de requests/erros, CPU/memória do processo).\n\n```bash\ncurl http://localhost:8000/metrics/\n```\n\n**Caso de uso:** apontar o Prometheus para `/metrics/` e montar dashboards de\nlatência/erro no Grafana, ou disparar alertas quando `p95_latency_ms` ou\n`error_rate` passarem de um limite — sem instrumentar cada view na mão.\n\n### 2. rust-py-rate-limit — limite por endpoint\n\nBuckets de janela deslizante definidos em `settings.RATE_LIMITS` (limite por\n`window_seconds`, por IP). Os endpoints sensíveis chamam `enforce()`, que levanta\n`Throttled` do DRF (HTTP 429 + header `Retry-After`).\n\n```python\n# apps/users/views.py\nfrom apps.core.throttle import client_ip, enforce\n\nclass LoginView(TokenObtainPairView):\n    def post(self, request, *args, **kwargs):\n        enforce(\"login\", client_ip(request))   # 429 se estourar o limite\n        return super().post(request, *args, **kwargs)\n```\n\nDefaults: `login` 10/min, `register` e `forgot_password` 5/hora por IP.\n\n**Caso de uso:** travar ataques de força-bruta de senha no `/login` e abuso do\n`/forgot-password` (spam de email) sem precisar de Redis/nginx na frente.\n\n### 3. rust-py-audit — trilha de auditoria encadeada\n\nCada evento de negócio é gravado num log append-only encadeado por SHA-256\n(o hash de cada evento inclui o hash do anterior). Adulterar uma linha quebra a\ncadeia, detectável via `audit.verify()`.\n\nEventos registrados: `USER_REGISTERED`, `USER_LOGIN`, `PROFILE_UPDATED`,\n`PASSWORD_CHANGED`, `PASSWORD_RESET_REQUESTED`, `PASSWORD_RESET`, `EMAIL_CONFIRMED`.\n\n```python\n# apps/core/services.py\naudit = AuditLogger(app_name=\"api_django_reference\", file_path=\"./audit.jsonl\")\n\n# apps/users/views.py — ao trocar a senha\naudit.log(actor_id=str(user.id), action=\"PASSWORD_CHANGED\",\n          resource=\"user\", resource_id=str(user.id), metadata={\"ip\": ip})\n```\n\n```python\n# Verificar a integridade da trilha\n\u003e\u003e\u003e from apps.core.services import audit\n\u003e\u003e\u003e audit.verify()\n{'valid': True, 'total_events': 42, 'last_hash': '...'}\n```\n\n**Caso de uso:** conformidade/forense — provar \"quem fez o quê e quando\" de forma\nauditável (LGPD/SOC2), com garantia criptográfica de que registros não foram\nalterados. O job diário do scheduler revalida a cadeia automaticamente.\n\n### 4. rust-py-cache — cache do `GET /me`\n\n`MeView` serve `/me` a partir do cache (TTL `USER_CACHE_TTL`, 30s) e invalida a\nentrada quando o usuário muda (`PATCH /me`, troca/reset de senha, confirmação de email).\n\n```python\n# apps/users/views.py\ndef retrieve(self, request, *args, **kwargs):\n    key = user_cache_key(request.user.id)\n    cached = cache.get(key)\n    if cached is not None:\n        return Response(cached)             # hit: não toca no banco\n    data = self.get_serializer(request.user).data\n    cache.set(key, data, ttl=settings.USER_CACHE_TTL)\n    return Response(data)\n```\n\nTambém há o decorator de memoização para funções puras/custosas:\n\n```python\nfrom apps.core.services import cache\n\n@cache.cached(ttl=300, key=lambda user_id: f\"perms:{user_id}\")\ndef compute_permissions(user_id):\n    ...\n```\n\n**Caso de uso:** o `/me` costuma ser chamado em quase toda navegação do frontend;\ncachear por poucos segundos derruba a carga no Postgres mantendo os dados frescos.\n\n### 5. rust-py-scheduler — jobs em background\n\nUm `Scheduler` roda numa thread dedicada (Rust), iniciado em `CoreConfig.ready()`\nquando o servidor sobe (`SCHEDULER_AUTOSTART=True`; desligado em testes e comandos\ncomo `migrate`).\n\n```python\n# apps/core/scheduler.py\nscheduler.every(\"10m\", cleanup_expired, max_retries=2)   # limpa cache + rate-limit\nscheduler.cron(\"0 3 * * *\", verify_audit_chain)          # revalida a auditoria às 3h\n```\n\n**Caso de uso:** manutenção periódica sem Celery/cron externo — expurgar chaves\nexpiradas de cache/rate-limit e checar a integridade da trilha de auditoria todo dia.\n\n\u003e O scheduler **não** inicia durante a suíte de testes nem em comandos de gestão; o\n\u003e guard fica em `apps/core/apps.py` (evita também o duplo start do autoreload do\n\u003e `runserver`).\n\n## Notas\n\n- O envio de email usa o backend de **console** em desenvolvimento (os links de\n  confirmação/reset aparecem no terminal do `runserver`). Configure SMTP em produção\n  via `EMAIL_BACKEND` e variáveis relacionadas.\n- `forgot-password` sempre responde da mesma forma, mesmo para emails inexistentes,\n  para não vazar quais contas existem.\n- Os tokens de confirmação de email e reset de senha são assinados e expiram, usando o\n  framework de tokens do Django (sem armazenar tokens no banco).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frobertolima-dev%2Fdjango_rust_libs","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Frobertolima-dev%2Fdjango_rust_libs","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frobertolima-dev%2Fdjango_rust_libs/lists"}