Project Layout
code specs/code/project-layout.kmd
Layout intra-módulo per linguagem: source root, tests location, fixtures/testdata, resources/assets, build artifacts (gitignored), generated code, config files, docs, examples. Tabela canônica per linguagem. Distinto de RFC-006 que cobre layout inter-módulo (sector → backend/app/engine/landing).
When this spec applies
Primary triggers
- Estruturar diretórios de um módulo novo
All triggers
- Criar novo módulo Koder em qualquer linguagem
- Decidir onde colocar testes/fixtures/resources/scripts
- Refatorar módulo legacy com layout inconsistente
- Configurar .gitignore canônico
Specification body
Spec — Project Layout
Facet Code do Koder Design.
Cobre layout intra-módulo (dentro de um Sector). Layout inter-módulo (
<domain>/<area>/<sector>/) é RFC-006.
Princípio cross-cutting
Cada linguagem tem o seu idiom estabelecido (Go cmd/+internal/,
Rust src/+tests/, Dart lib/+test/, etc.). A Koder respeita o
idiom — não inventa layout próprio que confunde tooling oficial.
Onde uniformizar entre todas:
README.kmdna raiz do módulo (perreadmes/products.kmd)koder.tomlna raiz (perkoder-toml/format.kmd).editorconfigna raiz (percode/indentation.kmd)LICENSEna raizdocs/pra documentação intra-módulo (KMD/MD)backlog/pra tickets do módulo (perpolicies/backlog.kmd)dist/,build/,target/,out/sempre gitignored
Tabela canônica per linguagem
Go
<module>/
├── README.kmd
├── koder.toml
├── .editorconfig
├── LICENSE
├── go.mod
├── go.sum
├── cmd/
│ └── <bin-name>/main.go ← um dir por binário
├── internal/ ← código não-exportável
│ ├── <pkg>/
│ └── ...
├── pkg/ ← código exportável (se library)
├── api/ ← spec proto/openapi (se relevante)
├── testdata/ ← fixtures pra _test.go
├── docs/
├── backlog/
├── examples/ ← se library
├── scripts/ ← bash auxiliares
└── dist/ ← gitignored: build outputs
- Tests: arquivo
_test.gonext-to-source (idiom Go) - Fixtures:
testdata/(Go ignora por convenção)
Rust
<module>/
├── README.kmd
├── koder.toml
├── .editorconfig
├── LICENSE
├── Cargo.toml
├── Cargo.lock ← commit em binary; gitignore em library
├── src/
│ ├── lib.rs ← biblioteca
│ ├── main.rs ← binário
│ └── bin/<name>.rs ← múltiplos binários
├── tests/ ← integration tests (cada arquivo = crate)
├── benches/ ← benchmarks
├── examples/ ← idiom Cargo
├── docs/
├── backlog/
└── target/ ← gitignored
- Unit tests:
#[cfg(test)] mod testsno mesmo arquivo (idiom Rust) - Integration:
tests/
Dart / Flutter
<module>/
├── README.kmd
├── koder.toml
├── .editorconfig
├── LICENSE
├── pubspec.yaml
├── pubspec.lock ← commit em app; gitignore em library
├── lib/
│ ├── <module>.dart ← entry público
│ └── src/ ← implementação (não exportada)
├── test/
├── integration_test/ ← Flutter integration tests
├── example/ ← se library
├── android/, ios/, ... ← se Flutter app
├── assets/ ← se Flutter app
├── docs/
├── backlog/
└── build/ ← gitignored
Python
<module>/
├── README.kmd
├── koder.toml
├── .editorconfig
├── LICENSE
├── pyproject.toml ← PEP 518; preferred sobre setup.py
├── <package_name>/ ← snake_case; src layout opcional (recomendado pra evitar import shadowing)
│ ├── __init__.py
│ └── ...
├── tests/ ← preferred sobre next-to-source
│ ├── conftest.py
│ └── test_*.py
├── docs/
├── examples/
├── backlog/
└── dist/, build/, .venv/ ← gitignored
- src layout (
src/<package_name>/) recomendado pra projetos publicados — evita import shadowing.
Koda
<module>/
├── README.kmd
├── koder.toml
├── .editorconfig
├── LICENSE
├── lib/ ← código fonte
│ ├── <module>.kd
│ └── ...
├── test/
│ └── *_test.kd
├── docs/
├── examples/
├── backlog/
└── out/ ← gitignored
JS/TS
<module>/
├── README.kmd
├── koder.toml
├── .editorconfig
├── LICENSE
├── package.json
├── package-lock.json ← commit (npm) ou pnpm-lock.yaml (pnpm)
├── tsconfig.json ← se TS
├── src/ ← preferred
│ ├── index.ts
│ └── ...
├── test/ ← Jest/Vitest setup
│ └── *.test.ts
├── docs/
├── examples/
├── public/ ← se web app
├── backlog/
└── dist/, node_modules/ ← gitignored
Shell scripts (módulo standalone)
<module>/
├── README.kmd
├── koder.toml
├── LICENSE
├── bin/ ← scripts executáveis (chmod +x)
│ └── <script>
├── lib/ ← funções source-able
│ └── <lib>.sh
├── test/ ← bats-core ou similar
├── docs/
└── backlog/
R1 — Tests location
| Linguagem | Convenção |
|---|---|
| Go | next-to-source (foo_test.go ao lado de foo.go) |
| Rust | unit: inline mod tests; integration: tests/ |
| Dart | test/ separado |
| Python | tests/ separado (preferred Koder) ou next-to (PEP 396 OK) |
| Koda | test/ separado |
| JS/TS | test/ ou src/__tests__/ (config Jest/Vitest) |
| Shell | test/ separado |
Princípio: seguir idiom da linguagem. A Koder não força uniformidade contra o tooling oficial.
R2 — Fixtures / testdata
| Linguagem | Convenção |
|---|---|
| Go | testdata/ (ignorado pelo go build) |
| Rust | tests/fixtures/ |
| Dart | test/fixtures/ |
| Python | tests/fixtures/ ou tests/data/ |
| Koda | test/fixtures/ |
| JS/TS | test/fixtures/ |
R3 — Resources / assets
- Static assets (imagens, fonts):
assets/(Flutter),static/(Go web),public/(JS web) - Templates:
templates/(Python/Go) ouviews/(Rails-like) - Migrations DB:
migrations/na raiz do módulo
R4 — Build artifacts (sempre gitignored)
| Diretório | Linguagem |
|---|---|
dist/ |
JS/TS, Python, Dart |
build/ |
Dart, Java, generic |
target/ |
Rust, Java/Maven |
out/ |
Koda, generic |
bin/ |
Go (output de go build) — exceção: scripts source-controlled |
*.pyc, __pycache__/ |
Python |
node_modules/ |
JS/TS |
.venv/, venv/, env/ |
Python |
.gitignore template canônico em meta/docs/stack/specs/code/gitignore.template.
R5 — Generated code
Quando código é gerado por tooling (protoc, openapi-generator,
codegen Koder):
- Marker comment no header:
// Code generated by <tool>. DO NOT EDIT. - Diretório
gen/ou per-tool (protoc/) - Gitignore quando reproduzível trivialmente (build step rápido)
- Commit quando custoso/lento ou quando o gerador não é parte do build padrão
R6 — Config files
- Project config:
koder.tomlna raiz (sempre) - Language config:
.golangci.yml,pyproject.toml,analysis_options.yaml,tsconfig.json— na raiz - Editor:
.editorconfigna raiz (sempre) - Env:
.env.examplena raiz;.envgitignored - CI:
.gitea/workflows/(Gitea Actions)
R7 — Docs intra-módulo
README.kmdna raiz (overview, install, usage curto)docs/pra docs maiores (docs/getting-started.kmd,docs/api.kmd,docs/architecture.kmd)- ADRs em
docs/decisions/NNNN-<title>.kmd(perpolicies/content-location.kmd) - RFCs intra-módulo em
docs/rfcs/<scope>-RFC-<NN>-<title>.kmd
R8 — Examples
Quando o módulo é library, examples/ com 1+ exemplos completos
runnable. Cada exemplo standalone (não compartilha state com outros).
Audit deterministic
project-layout-audit.sh:
README.kmd,koder.toml,.editorconfig,LICENSEna raiz- Diretório de build na lista de gitignored
- Generated code com marker comment
- Tests em location idiomática (warning se inconsistente)
Cross-link
- RFC-006 (sector layout inter-módulo)
code/imports.kmd(import paths refletem layout)readmes/products.kmd(README format)koder-toml/format.kmd(config canônica)policies/backlog.kmd(backlog/directory)policies/content-location.kmd(where to put doc types)
References
rfcs/design-RFC-001-koder-design-system.kmdrfcs/RFC-006 (sector layout)specs/code/imports.kmdspecs/readmes/products.kmdspecs/koder-toml/format.kmdpolicies/design-governance.kmd