---
name: novo-app
description: >
  Cria a estrutura completa de um novo Django app no padrão SurveyHub: diretório em apps/,
  registro em INSTALLED_APPS, AppConfig com ready() e signals, models.py, views.py, forms.py,
  urls.py, admin.py, managers.py, services/, templates/, tests/. Segue exatamente as regras
  de .claude/rules/setup-novo-app.md e naming-conventions.md.
  Use quando o usuário disser "criar novo app", "novo app django", "novo módulo", "adicionar app",
  "criar app surveys", "criar app notifications", "estruturar novo app", "scaffold app",
  "novo domínio de negócio", "preciso de um app para X".
  DO NOT USE para criar um model dentro de um app existente — use /novo-modelo.
  DO NOT USE para criar views em app existente — use /novas-views.
argument-hint: "<nome_do_app>"
---

# /novo-app $ARGUMENTS

Cria a estrutura completa de um novo Django app no padrão SurveyHub.

## Informações Necessárias

Se `$ARGUMENTS` estiver incompleto, perguntar:

| Pergunta | Exemplo |
|----------|---------|
| Nome do app (`$1`) | `notifications`, `exports`, `reports` |
| Qual entidade principal gerenciará? | `Notification`, `Export` |
| Precisa de models próprios? | Sim/Não |
| Precisa de templates? | Sim/Não |

**Derivar automaticamente:**
- `{app}` = `$1` em snake_case (ex: `notifications`)
- `{App}` = PascalCase do app (ex: `Notifications`)
- `{Entidade}` = model principal em PascalCase (ex: `Notification`)

---

## Fase 1 — Criar a Estrutura de Arquivos

```bash
mkdir -p apps/{app}
python manage.py startapp {app} apps/{app}
mkdir -p apps/{app}/services apps/{app}/utils
mkdir -p apps/{app}/templates/{app}/partials
mkdir -p apps/{app}/tests
touch apps/{app}/services/__init__.py apps/{app}/utils/__init__.py
touch apps/{app}/tests/__init__.py apps/{app}/tests/conftest.py
touch apps/{app}/tests/factories.py apps/{app}/tests/test_models.py apps/{app}/tests/test_views.py
touch apps/{app}/managers.py apps/{app}/signals.py apps/{app}/decorators.py
```

---

## Fase 2 — AppConfig com signals

Editar `apps/{app}/apps.py`:

```python
from django.apps import AppConfig


class {App}Config(AppConfig):
    default_auto_field = "django.db.models.BigAutoField"
    name = "apps.{app}"
    verbose_name = "{Nome Legível do App}"

    def ready(self) -> None:
        import apps.{app}.signals  # noqa: F401  — conecta os @receiver
```

> **Crítico:** sem `ready()` importando signals, nenhum `@receiver` será conectado.

---

## Fase 3 — Registrar em INSTALLED_APPS

Editar `surveyhub/settings/base.py`:

```python
INSTALLED_APPS = [
    # ...apps existentes...
    "apps.{app}",  # adicionar aqui
]
```

---

## Fase 4 — Model Inicial (Fat Model)

Em `apps/{app}/models.py`:

```python
import uuid
from django.db import models
from apps.{app}.managers import {Entidade}Manager


class {Entidade}(models.Model):
    """{Entidade} — [descrição do domínio]."""

    class Status(models.TextChoices):
        DRAFT = "draft", "Rascunho"
        ACTIVE = "active", "Ativo"
        CLOSED = "closed", "Encerrado"

    id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
    status = models.CharField(
        max_length=20, choices=Status.choices, default=Status.DRAFT, db_index=True
    )
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)
    deleted_at = models.DateTimeField(null=True, blank=True, db_index=True)

    objects = {Entidade}Manager()

    class Meta:
        ordering = ["-created_at"]
        indexes = [models.Index(fields=["status", "deleted_at"])]

    def __str__(self) -> str:
        return f"{Entidade} {self.pk}"
```

---

## Fase 5 — Manager

Em `apps/{app}/managers.py`:

```python
from django.db import models


class {Entidade}QuerySet(models.QuerySet):
    def ativos(self):
        return self.filter(status="active", deleted_at__isnull=True)

    def nao_deletados(self):
        return self.filter(deleted_at__isnull=True)


class {Entidade}Manager(models.Manager):
    def get_queryset(self):
        return {Entidade}QuerySet(self.model, using=self._db)

    def ativos(self):
        return self.get_queryset().ativos()

    def nao_deletados(self):
        return self.get_queryset().nao_deletados()
```

---

## Fase 6 — URLs

Em `apps/{app}/urls.py`:

```python
from django.urls import path
from . import views

app_name = "{app}"

urlpatterns = [
    path("", views.{entidade}_list, name="{entidade}_list"),
    path("create/", views.{entidade}_create, name="{entidade}_create"),
    path("<uuid:pk>/", views.{entidade}_detail, name="{entidade}_detail"),
]
```

Em `surveyhub/urls.py`:

```python
path("{app}/", include("apps.{app}.urls")),
```

---

## Fase 7 — Admin + Migration

```python
# apps/{app}/admin.py
from django.contrib import admin
from .models import {Entidade}

@admin.register({Entidade})
class {Entidade}Admin(admin.ModelAdmin):
    list_display = ["__str__", "status", "created_at"]
    list_filter = ["status"]
    readonly_fields = ["id", "created_at", "updated_at"]
```

```bash
python manage.py makemigrations {app}
python manage.py migrate
```

---

## Checklist de Completude

- [ ] App registrado em `INSTALLED_APPS` como `"apps.{app}"`
- [ ] `AppConfig` com `ready()` importando signals
- [ ] Model: UUID PK, `__str__`, soft delete, `Meta.indexes`
- [ ] Manager: `ativos()`, `nao_deletados()` em português
- [ ] `urls.py` com `app_name` (namespace)
- [ ] URLs incluídas em `surveyhub/urls.py`
- [ ] Admin com `@admin.register`
- [ ] `signals.py` criado
- [ ] `templates/{app}/partials/` criado
- [ ] `tests/` com `__init__.py`, `conftest.py`, `factories.py`
- [ ] Migration gerada e aplicada

## Referências

- `.claude/rules/setup-novo-app.md`
- `.claude/rules/naming-conventions.md`
- `.claude/rules/architecture/django-models.md`
