src/provision — a rotina que cria uma organização

Não é um módulo de API: é a rotina única chamada pelo mod-signup e pela linha de comando. Faz os 6 passos do flx-onboarding e é idempotente por etapa — reexecutar completa o que faltou, porque cada passo checa antes de agir.

Como se usa pela linha de comando

docker exec appstock-dev-api python -m src.provision \
  --slug santonio --name "Santo Antonio" \
  --admin-name "Fulano" --admin-email fulano@santonio.com.br \
  --admin-password '...' [--default]

Imprime um JSON com org_id, slug, app_db, sync_db, admin_email e o sync_token em claro — a única vez que ele aparece. A plataforma guarda só o SHA-256.

--default marca a organização como is_default: é ela que atende rota pública sem ?org= (hoje, a demo). Ver flx-resolucao-tenant.

O que cada peça faz

FunçãoResponsabilidade
bootstrap()Garante que o appstock_core existe (CREATE DATABASE + create_all do metadata).
_ensure_database()CREATE DATABASE via engine em AUTOCOMMIT no banco postgres. Devolve False se já existia.
_run_app_migrations()alembic upgrade head por subprocess, em /app, com ALEMBIC_URL apontando para o DSN da organização. É como o mesmo histórico Alembic serve N bancos.
_apply_sync_template()Aplica db/sync_template.sql só se o schema public estiver vazio. Usa cursor bruto porque o arquivo tem múltiplos statements.
_seed_app_db()Dentro de org_context: linha da organização (mesmo UUID do core), sync_resources, perfil Administrador com todos os grants, usuário admin superusuário.
_log_step()Grava provisioning_log (OK/ERROR) a cada passo.

O usuário admin nasce com local_username = "<slug>-admin", auth_type = "LOCAL", status = "ACTIVE" e is_superuser = True.

Detalhes que economizam tempo depois

  • O UUID da organização é o mesmo no core e no app_<org>. Não há de-para. Isso é o que permite org_context(org_id) funcionar em scripts.
  • tenants.invalidate(org_id) é chamado depois de registrar os DSNs — sem isso a engine da organização recém-criada não seria encontrada no mesmo processo.
  • A checagem de e-mail duplicado só roda quando a organização é nova. Numa reexecução (org já existe) o e-mail não é reconferido.
  • Os 11 módulos de MODULES_V1 são gravados em org_modules: stock, commercial, clients, offers, opportunities, orders, dashboards, dictionary_studio, ai_assistant, reports, media.

Estado real

Funciona e é a única forma suportada de criar organização. As duas orgs atuais nasceram daqui. Buracos:

1. org_modules é gravado e nunca lido [M]

Nenhum código consulta essa tabela. Os módulos não gateiam nada — não há como vender plano por módulo nem suspender inadimplente. Ver mod-organizations.

2. O appstock_core não tem migrations [P]

bootstrap() usa create_all. Qualquer evolução do plano de controle (plano, cobrança, domínio por organização, usuário multi-org) não tem caminho seguro de aplicação nem rollback.

3. Sem console de operador [M]

Listar organizações, ver status, bancos, uso e o provisioning_log só por SQL. Um provisionamento que falhou pela metade é invisível.

4. decommission_legacy.py está quebrado [P]

SF_DB_USER/SF_DB_PASSWORD, variáveis que não existem mais — estoura com KeyError. Pior: já executou um DROP DATABASE antes de estourar. Falha no meio. Além disso reintroduz a nomenclatura SF_, proibida no projeto. O rewipe_orgs.py, ao lado, está íntegro.

Lacunas

Rastreadas na fase-1-onboarding.