TLDR: projetos com mais de um runtime independente colocam cada um em modules/<nome>/; nada de módulo solto na raiz. .module/ é para o módulo o que .project/ é para o repo.
Este repo tem dois módulos: modules/frontend (React + Vite) e modules/backend (Rails).
Layout
```
/
├── modules/
│ ├── frontend/
│ │ ├── .module/ # metadados do módulo (análogo ao .project/ do repo)
│ │ │ ├── make/
│ │ │ │ └── main.mk # alvos de make específicos do módulo
│ │ │ └── docker/
│ │ │ └── compose.yml # overrides de docker do módulo (porta, working_dir)
│ │ ├── .infra/ # k8s + terraform do deploy deste módulo
│ │ │ ├── k8s/
│ │ │ │ ├── base/
│ │ │ │ └── overlays/staging/ + production/
│ │ │ └── terraform/
│ │ ├── Makefile # inclui o stack do commons + .module/make/main.mk
│ │ ├── src/
│ │ ├── package.json
│ │ └── ...
│ └── backend/
│ ├── .module/
│ │ ├── make/main.mk
│ │ └── docker/compose.yml
│ ├── .infra/
│ └── Makefile
├── .project/
│ └── docs/ # toda a documentação do repo, centralizada
├── .commons -> ...
├── Makefile # delega: frontend.%, backend.%
├── compose.yml # inclui o stack do commons + .module/docker/ de cada módulo
├── .env.example
└── .gitignore
```
## Por que `modules/` e não `apps/` ou `packages/`
| Nome | Por que não |
|---|---|
| `apps/` | Sugere só aplicação de usuário final — exclui workers, jobs, scripts |
| `packages/` | Sugere pacotes npm / bibliotecas compartilhadas |
| `modules/` | Genérico: cobre qualquer componente executável ou deployável de forma independente, em qualquer stack. E não conflita com o `app/` do Rails quando um back-end Rails entra |
## Regras
- Todo módulo vive dentro de `modules/` — nunca na raiz do projeto.
- Cada módulo é autocontido: manifesto próprio (`package.json`, `mix.exs`, `Gemfile`…), config de
tooling própria, dependências próprias.
- Sem import de código entre módulos no nível da linguagem.
- A raiz do projeto contém apenas: `modules/`, `.project/`, symlink `.commons`, `Makefile`,
`compose.yml`, `.env.example`, `.gitignore`, `.tool-versions`.
- Módulo ainda não implementado (placeholder) tem só `.module/` e `Makefile` — não precisa de
`.gitkeep`.
## A convenção `.module/`
`.module/` é para o módulo o que `.project/` é para o repo: metadados e config de tooling com escopo
daquele módulo.
| Caminho | Para quê |
|---|---|
| `.module/make/main.mk` | Alvos de make específicos do módulo — incluídos pelo `Makefile` dele |
| `.module/docker/compose.yml` | Overrides de docker: `working_dir`, portas expostas, env vars — incluídos pelo `compose.yml` da raiz |
**O que NÃO vai em `.module/`:**
- **Documentação** — toda documentação vive em `.project/docs/` na raiz do repo, centralizada. Não
existe `.module/docs/` nem `.module/specs/`.
- **Infraestrutura** — vai em `.infra/`, dentro do módulo.
## Delegação no Makefile
O `Makefile` da raiz inclui `commons/make/main.makefile` e delega por módulo:
```makefile
frontend.%:
@$(MAKE) -C modules/frontend $*
backend.%:
@$(MAKE) -C modules/backend $*
```
O `Makefile` de cada módulo inclui o stack do commons + o seu próprio `.module/make/main.mk`:
```makefile
include $(COMMONS_DIR)/make/main.makefile
include .module/make/main.mk
```
## compose.yml
O `compose.yml` da raiz inclui o stack do commons de cada módulo + o override de docker do módulo:
```yaml
name: nectar-charges
include:
- path:
- .commons/docker/compose/stacks/react.yml
- modules/frontend/.module/docker/compose.yml
```
O `.module/docker/compose.yml` do módulo define apenas o que é específico dele (porta,
`working_dir`) — nunca duplica o que o commons já fornece.
## Detecção de stack
O Makefile do commons detecta a stack a partir de arquivos na raiz do projeto. Em projeto
multi-módulo, o arquivo de detecção (`package.json`, `mix.exs`, etc.) fica dentro de
`modules//`, não na raiz. Se necessário, informe o caminho do módulo explicitamente em
`.project/make/overrides.mk`.
## Quando criar um módulo novo
Crie um módulo quando o componente tem runtime, pipeline de build ou alvo de deploy próprios:
- `modules/frontend/` — SPA React
- `modules/backend/` — API Elixir/Phoenix, Ruby on Rails ou Node.js
- `modules/worker/` — processador de jobs em background com processo próprio
- `modules/mobile/` — app Expo/React Native
- `modules/jobs/` — scripts de processamento em lote
Não crie módulo para uma biblioteca compartilhada entre dois outros módulos — coloque o código
compartilhado no módulo mais relevante, ou extraia para um repositório separado.
## Referências
- [Camadas do app React](architecture/frontend_layers.md)
- [Camadas do app Rails](architecture/backend_layers.md)
- [Spec: estrutura mono-módulo](specs/20260721163000_mono_module_structure.md)