Skip to content

feat: schemas Maraca revisitados e extendidos - #149

Merged
zoedsoupe merged 4 commits into
mainfrom
feat/maraca-auth
Jan 23, 2026
Merged

zoedsoupe merged 4 commits into
mainfrom
feat/maraca-auth

Conversation

@zoedsoupe

@zoedsoupe zoedsoupe commented Jan 22, 2026

Copy link
Copy Markdown
Member

Problem

O PR adiciona suporte a autenticação (convites, confirmação por email e reset de senha), um modelo explícito de permissões e um fluxo de requisição de acesso, além de tornar o isolamento por organização (RLS) aplicável a novas tabelas. O repositório carecia desses schemas e políticas para gerenciar acesso, segurança e isolamento de dados a nível de tekoa/organização.

Solution

  • Introduz novos schemas e migrations no prefixo "maraca": permissions e access_requests, e estende avas e tekoas com campos para autenticação (password_hash, tokens, invited_at) e quotas em bytes.
  • Adiciona changesets e funções públicas em Taina.Maraca.Ava (invitation, confirmation, password reset) e em Taina.Maraca.Permission/AccessRequest para validações e fluxos esperados.
  • Implementa Taina.Repo.PublicId (tipo Ecto) e utilitários Repo.with_tekoa/2 e Repo.fetch/2 para suportar RLS e lookup conveniente.
  • Cria migration para políticas RLS que aplicam isolamento por current_tekoa_id em várias schemas (maraca., ybira., guara.*).
  • Atualiza docs: novo README do serviço Maraca descrevendo propósito, fluxos e segurança.
  • Adiciona dependência bcrypt_elixir para hash de senhas.

Rationale

  • Centralizar autenticação e convites no schema AvA permite fluxos seguros de convite/confirmação/reset sem mudanças paralelas em serviços externos.
  • Modelo explícito de permissions + registros de granted_by e unique constraint evita duplicidade e facilita auditoria.
  • Uso de PublicId e quotas em bytes melhora interoperabilidade e precisão de armazenamento.
  • RLS combinado com Repo.with_tekoa/2 fornece isolamento de dados por organização de forma consistente e segura, delegando controle ao banco de dados.
  • Migrations e mudanças foram projetadas para preservar integridade referencial e permitir políticas de segurança no nível do banco.

Problema

Maraca não tinha suporte completo para autenticação (convites, confirmação por email, reset de senha), nem um modelo explícito de permissões e falta de isolamento por organização (tekoa) no banco, dificultando segurança, auditoria e multi-tenancy.

Solução

Adiciona autenticação e autorização completas ao Maraca:

  • novos schemas: Permission e AccessRequest (fluxo de requisição de acesso);
  • extensão de Ava com campos de autenticação (password_hash, tokens, invited_at, virtuals e mudançasets para convite/confirm/reset);
  • Tekoa com public_id (PublicId) e quotas em bytes (storage_quota_bytes / storage_used_bytes);
  • utilitários em Taina.Repo: PublicId (Ecto.Type), with_tekoa/2 (configura current_tekoa_id p/ RLS) e fetch/2;
  • migrations: tabelas maraca.permissions e maraca.access_requests, alterações em avas/tekoas;
  • migration de políticas RLS aplicando isolamento por current_tekoa_id para maraca., ybira. e guara.*;
  • README do serviço Maraca e dependência bcrypt_elixir para hashing seguro de senhas.

Explicação

A implementação centraliza autenticação em Ava para fluxos unificados (convite, confirmação, reset), torna permissões explícitas e auditáveis (granted_by + constraint única), adota PublicId e quotas em bytes para interoperabilidade entre serviços, e aplica isolamento robusto combinando RLS no banco com Repo.with_tekoa/2 no app — reduzindo risco de vazamento entre organizações. Tokens são armazenados como hashes e senhas são bcryptadas para minimizar exposição em caso de comprometimento.

@zoedsoupe

Copy link
Copy Markdown
Member Author

@coderabbitai summary

@coderabbitai

coderabbitai Bot commented Jan 23, 2026

Copy link
Copy Markdown
Contributor

Warning

Rate limit exceeded

@zoedsoupe has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 6 minutes and 57 seconds before requesting another review.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

Walkthrough

Este PR adiciona o serviço Maraca com autenticação, autorização e isolamento por Tekoa: novos módulos e tabelas para Permissions e AccessRequests; amplia Taina.Maraca.Ava com campos e fluxos de convite/confirmação/reset (hash de senha, tokens, invited_by); converte public_id para um tipo PublicId autogerado; atualiza Taina.Maraca.Tekoa para cotas em bytes; adiciona Taina.Repo.PublicId, helpers de Repo (with_tekoa/2, fetch/2); cria migração de políticas RLS abrangendo maraca/ybira/guara; inclui dependência bcrypt_elixir e adiciona tipagens públicas em entidades de ybira. Não há alterações em APIs públicas fora dos módulos adicionados/expandidos.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related issues

  • taina-labs/taina#7: trata mudanças no esquema de Ava e introduz lógica de hashing/validação de tokens e senhas, consistente com os campos e fluxos adicionados aqui.

Possibly related PRs

  • feat: schemas mvp respeitanto rfc #1: altera os mesmos arquivos do domínio Maraca (ex.: lib/taina/maraca/ava.ex, tekoa.ex) e migrações relacionadas — forte conexão em nível de código.

Poem

🌱 Maraca brota com IDs e chaves,
🔐 Senhas e tokens em passos de segurança,
🏷️ Permissões e pedidos alinhados por tekoa,
🔁 RLS sussurra limites em silêncio,
🤝 Comunidades se reúnem — mais perto, mais livre.

🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 72.73% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed O título descreve claramente a mudança principal: revisão e extensão dos schemas Maraca com foco em autenticação, permissões e RLS.
Description check ✅ Passed A descrição segue o template, incluindo Problem, Solution e Rationale bem estruturados, descrevendo detalhadamente o que foi implementado e por quê.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/maraca-auth

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 10

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
lib/taina/maraca/tekoa.ex (1)

11-15: Docs e exemplo ainda referem storage_quota_gb

A documentação e o exemplo seguem no formato antigo. Que tal atualizar para storage_quota_bytes para manter o contexto limpo?

✏️ Sugestão de ajuste
-    * `storage_quota_gb` - Limite de armazenamento em gigabytes
+    * `storage_quota_bytes` - Limite de armazenamento em bytes

-      iex> changeset(%Tekoa{}, %{name: "Minha Comunidade", storage_quota: 500})
+      iex> changeset(%Tekoa{}, %{name: "Minha Comunidade", storage_quota_bytes: 500 * 1024 * 1024 * 1024})

Also applies to: 45-45

priv/repo/migrations/20251007182041_create_maraca_schema.exs (1)

7-13: Quotas sem default/NOT NULL

Como o changeset exige storage_quota_bytes e storage_used_bytes assume 0, o DB aceitar NULLs pode gerar inconsistências em consultas e políticas. Faz sentido alinhar o schema?

🧩 Sugestão de ajuste
-      add :storage_quota_bytes, :bigint
-      add :storage_used_bytes, :bigint
+      add :storage_quota_bytes, :bigint, null: false
+      add :storage_used_bytes, :bigint, null: false, default: 0
🤖 Fix all issues with AI agents
In `@lib/taina/maraca/access_request.ex`:
- Around line 118-123: O atual changeset(%__MODULE__{} = request, %{} = attrs)
permite que o requester forneça :status; add um novo creation-specific changeset
(e.g., create_changeset/2) that does not cast or validate :status and instead
sets status to :pending via put_change(request, :status, "pending") (or :pending
atom if code uses atoms), reuse the same
cast/validate_length/validate_different_avas logic, and keep the existing
changeset/2 for updates/decisions where :status may be allowed; update callers
that create requests to use create_changeset/2.

In `@lib/taina/maraca/ava.ex`:
- Around line 154-163: The invitation_changeset (and the other places that set
reset_token/email_confirmation_token) currently store raw tokens in the DB;
instead generate a random raw token (using generate_token()), compute a secure
hash (e.g., SHA256 or bcrypt) of that raw token, store only the hash in the DB
(use a field like email_confirmation_token_hash or reset_token_hash via
put_change), and return or pass the raw token only to the caller that sends the
email; update the corresponding reset token generation sites (the code around
the other token puts at the referenced locations) to follow the same pattern and
update any verification logic to compare the hash of the presented token to the
stored hash (using a constant-time compare).

In `@lib/taina/maraca/permission.ex`:
- Around line 104-108: Remova granted_by_id e tekoa_id dos campos aceitos pelo
cast/validate_required dentro da função changeset/2 (evitando que fields
derivados de contexto sejam settados via params) e deixe apenas [:resource_id,
:resource_type, :action, :ava_id] ali; em vez disso, garanta que o service que
chama Permission.changeset (ou a função que cria a permission) atribua
explicitamente permission.granted_by_id e permission.tekoa_id antes de persistir
para evitar spoofing e preservar rastreabilidade.
- Around line 84-88: The changeset currently documents uniqueness of (ava_id,
resource_type, resource_id, action) but doesn't call unique_constraint; update
the changeset function (changeset/2) in permission.ex to add a
unique_constraint/3 for that DB constraint (pick a relevant field like :action
or :resource_id as the target) with name set to the actual DB constraint/index
name from your migration and an appropriate message option; ensure the
constraint name matches the migration so the changeset returns a friendly error
when the combination already exists.

In `@lib/taina/maraca/README.md`:
- Line 55: The README links for "Guia de Contribuição" and "Código de Conduta"
currently point to the tekoa repository; confirm whether this is intentional
and, if not, update the two URLs in lib/taina/maraca/README.md so they reference
the corresponding CONTRIBUTING.md and CODE_OF_CONDUCT.md in the Tainá repository
(replace the existing https://github.com/taina-labs/tekoa/... links with the
correct Tainá repo URLs or local relative paths), ensuring link text remains the
same.

In `@lib/taina/repo.ex`:
- Around line 124-202: The Taina.Repo.PublicId module is declared alongside
other modules in the same file; move it to its own file to follow the
single-module-per-file guideline by creating lib/taina/repo/public_id.ex
containing the defmodule Taina.Repo.PublicId with its use Ecto.Type, callbacks
(type/0, cast/1, load/1, dump/1, autogenerate/0) and Nanoid.generate(12) logic;
update any references/imports if necessary and remove the duplicated module
definition from the original file so only one module definition remains per
file.
- Around line 64-73: O uso de transact/1 em with_tekoa/2 não existe em Ecto.Repo
e quebrará a compilação; replace ou implement wrapper: change the call in
with_tekoa (the transact(fn -> ... end) block that runs SQL.query! and cb.()) to
Ecto's transaction/1 (i.e., transaction(fn -> ... end)) or add a private
transact/1 that delegates to transaction/1 to preserve existing API — update the
call site in with_tekoa to use that chosen approach.
- Around line 36-52: The docs and behavior mismatch: with_tekoa/2 sets
app.current_tekoa_id (used by RLS) so it must receive the Tekoa.public_id
(string), not the numeric database id; update the examples to call
Repo.with_tekoa(tekoa.public_id, ...) and clarify the docs that the function
expects the public_id (String.Chars). Optionally harden Repo.with_tekoa/2: if
the first arg is an integer or a Tekoa struct, resolve the public_id (e.g.,
fetch Tekoa by id or read struct.public_id) before setting the context so
callers can pass id/structs transparently; keep the function name with_tekoa/2
and ensure it always assigns the public_id to the current_setting used by RLS.

In `@lib/taina/ybira.ex`:
- Line 11: Remova o código comentado e as declarações não utilizadas para
reduzir ruído: elimine a atribuição comentada `@root_path` e remova o
cálculo/atributo relacionado a mime_type (ou converta em
configuração/funcionalidade real se necessário) dentro do módulo Ybira para
evitar código morto; se o valor for necessário, mova para
Application.get_env/uma função pública (por exemplo mantendo nome
mime_type/@root_path) para uso explícito, caso contrário delete-os completamente
e rode mix compile para garantir que não restem warnings de variável não usada.

In `@priv/repo/migrations/20251007182041_create_maraca_schema.exs`:
- Around line 79-84: The access_requests table defines the :status column
without a default or NOT NULL, while business logic assumes a default of
"pending"; update the migration that creates table(:access_requests, prefix:
"maraca") so the add :status column includes null: false and a default of
"pending" (e.g., add :status, :string, null: false, default: "pending") to
enforce the domain rule at the DB level and keep multi‑tenancy behavior
deterministic.

Comment thread lib/taina/maraca/access_request.ex
Comment thread lib/taina/maraca/ava.ex Outdated
Comment thread lib/taina/maraca/permission.ex
Comment thread lib/taina/maraca/README.md
Comment thread lib/taina/repo.ex
Comment thread lib/taina/repo.ex
Comment thread lib/taina/repo.ex
Comment thread lib/taina/ybira.ex
Comment thread priv/repo/migrations/20251007182041_create_maraca_schema.exs
@coderabbitai

coderabbitai Bot commented Jan 23, 2026

Copy link
Copy Markdown
Contributor
✅ Actions performed

Summary regeneration triggered.

@zoedsoupe

Copy link
Copy Markdown
Member Author

@coderabbitai summary

@coderabbitai

coderabbitai Bot commented Jan 23, 2026

Copy link
Copy Markdown
Contributor
✅ Actions performed

Summary regeneration triggered.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
lib/taina/ybira/file.ex (1)

117-126: Typo crítico: :filehash deveria ser :file_hash

Parece que há um erro de digitação na linha 121: o campo declarado no schema é :file_hash (linha 59), mas no validate_required está :filehash. Isso fará com que o changeset sempre seja inválido, pois o Ecto não encontrará o campo esperado.

🐛 Correção sugerida
     |> validate_required([
       :filename,
       :original_filename,
       :filepath,
-      :filehash,
+      :file_hash,
       :mime_type,
       :file_size_bytes,
       :ava_id,
       :tekoa_id
     ])
lib/taina/ybira/folder.ex (1)

67-76: Inconsistência entre schema e changeset: :parent_id vs :folder_id

O schema na linha 45 define belongs_to :folder, __MODULE__, que gera automaticamente o campo :folder_id. Porém, o changeset usa :parent_id no cast (linha 69) e no foreign_key_constraint (linha 74). Isso causará problemas, pois o campo :parent_id não existe no schema.

Será que a intenção era usar :folder_id consistentemente, ou seria interessante renomear a associação para belongs_to :parent, __MODULE__?

🐛 Opção 1: Usar :folder_id (alinhado ao schema atual)
   def changeset(folder, attrs) do
     folder
-    |> cast(attrs, [:name, :public_id, :ava_id, :tekoa_id, :parent_id])
+    |> cast(attrs, [:name, :public_id, :ava_id, :tekoa_id, :folder_id])
     |> validate_required([:name, :ava_id, :tekoa_id])
     |> validate_length(:name, min: 1, max: 255)
     |> foreign_key_constraint(:ava_id)
     |> foreign_key_constraint(:tekoa_id)
-    |> foreign_key_constraint(:parent_id)
+    |> foreign_key_constraint(:folder_id)
     |> unique_constraint(:public_id)
   end
🐛 Opção 2: Renomear associação para :parent (semântica mais clara)
-    belongs_to :folder, __MODULE__
+    belongs_to :parent, __MODULE__

E atualizar o tipo t() para usar :parent_id e :parent ao invés de :folder_id e :folder.

🤖 Fix all issues with AI agents
In `@lib/taina/maraca/permission.ex`:
- Around line 161-169: Add a helper in the Permission module named
prepare_for_insert(changeset) that validates the context fields not present in
cast/params (validate_required for :granted_by_id and :tekoa_id) and document
it; keep the existing changeset/2 as-is, and update callers to call
Permission.changeset(attrs) → Ecto.Changeset.put_change(:granted_by_id, ...) /
put_change(:tekoa_id, ...) → Permission.prepare_for_insert() before Repo.insert
so the presence of granted_by_id and tekoa_id is enforced.

In `@lib/taina/maraca/tekoa.ex`:
- Around line 56-62: Update the documentation examples in the Tekoa module so
they use the new storage_quota_bytes field instead of storage_quota: change the
sample call to changeset(%Tekoa{}, %{name: "Minha Comunidade",
storage_quota_bytes: 5_368_709_120}) (or another appropriate byte value like
5_000_000_000) and keep the invalid-name example as-is; this touches the
examples around the changeset/0 usage in the Tekoa module.

In `@priv/repo/migrations/20251007182041_create_maraca_schema.exs`:
- Around line 69-72: Add a database index on the permissions.tekoa_id column to
speed up RLS-filtered queries: after the permissions table definition where you
add :tekoa_id, add a create index for :permissions on [:tekoa_id] using the same
schema prefix "maraca" (i.e., create index(:permissions, [:tekoa_id], prefix:
"maraca")). This ensures queries filtering by current_tekoa_id under RLS use the
index for better performance.
- Around line 86-89: Add a B-tree index on access_requests.tekoa_id to speed up
RLS/organization filtering: inside the migration where access_requests is
created (after the add :tekoa_id line and before or after timestamps()), add
create index(:access_requests, [:tekoa_id], prefix: "maraca") to create the
index in the maraca schema; ensure the name/arguments match other indices in
this migration if you need consistent naming.
- Around line 60-77: O esquema da tabela permissions define resource_type,
resource_id e action como nullable apesar de fazerem parte do índice único
permissions_unique_grant; atualize a migração alterando as definições em create
table(:permissions, ...) para adicionar null: false em resource_type,
resource_id e action (ou, se desejar permitir NULLs deliberadamente, documente e
use um índice parcial), garantindo que a constraint única em
permissions_unique_grant funcione como esperado; localize as chamadas add
:resource_type, :resource_id, :action na definição da tabela e torne-as
non-null.
♻️ Duplicate comments (1)
priv/repo/migrations/20251007182041_create_maraca_schema.exs (1)

83-83: status ainda sem null: false

O campo status aparece sem a constraint null: false que foi discutida anteriormente. Conforme o alinhamento no review passado (default :pending no changeset, restrição estrutural no banco), a migração deveria ter:

add :status, :string, null: false

Comment thread lib/taina/maraca/permission.ex
Comment thread lib/taina/maraca/tekoa.ex
Comment thread priv/repo/migrations/20251007182041_create_maraca_schema.exs
Comment thread priv/repo/migrations/20251007182041_create_maraca_schema.exs
Comment thread priv/repo/migrations/20251007182041_create_maraca_schema.exs
@zoedsoupe
zoedsoupe merged commit e50afd6 into main Jan 23, 2026
3 of 4 checks passed
@zoedsoupe
zoedsoupe deleted the feat/maraca-auth branch January 23, 2026 00:47
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant