Monorepo RFC 001 area first directory structure
RFC001 — AreaFirst Directory Structure
| Field | Value |
|---|---|
| Status | *ccepted*(2026 |
| Author(s) | Rodrigo (with Claude as scribe) |
| Date | 2026 |
| Affects | All modules in apps/, platform/; top-level monorepo structure |
| Depends on | docs/stack/areas.md, docs/stack/engine-product-pattern.md |
1. Summary
Replace the current technologybased toplevel directories (apps/, platform/) with Area-based directories that match the 9 competency areas of the Koder Stack. Within each Area, every product becomes its own root directory containing all distribution forms (platform/, app/mobile/, app/desktop/, app/tv/) as subdirectories.
2. Problem
The current monorepo top-level mixes two incompatible classification criteria:
apps/ ← technology (Flutter)
platform/ ← technology (Go / SaaS)
ai/ ← area
infra/ ← area
observe/ ← area
data/ ← areaThis inconsistency causes three recurring problems:
2.1 Products split across two directories
A product with a SaaS backend and a Flutter app ends up in two separate directories with no formal relationship between them:
platform/kmail/ ← SaaS webmail backend
apps/kmail/ ← (hypothetical) Flutter clientThese cannot coexist with the same name under the current structure (names must be unique across the monorepo), forcing either a naming collision or a confusing suffix like kmail-mobile.
2.2 The classification question has no clear answer
When creating a new module, the question "does this go in apps/ or platform/?" has no clean answer for products that are simultaneously a SaaS backend and an installable app. The existing docs define:
apps/= "Aplicações com UI (Dart/Flutter, desktop, mobile)"platform/= "Produtos e backends SaaS"
A product that is both — a webmail that Koder hosts and a native app users install — fits neither cleanly.
2.3 Distribution form is not the same as product identity
apps/ and platform/ classify by how something is delivered, not what it is. As products gain new distribution forms (SaaS → self-hosted → mobile → TV), the classification becomes arbitrary. The same product must live in multiple directories or the directory loses its meaning.
3. Proposal
3.1 Dissolve apps/ and platform/
Remove apps/ and platform/ as top-level directories. Their contents move to Area directories (see §3.2).
3.2 Introduce Area directories for products
Create four new top-level directories corresponding to the Koder Stack Areas that contain products (as opposed to infrastructure):
| New directory | Covers |
|---|---|
foundation/ |
Identity, payments, billing, security — cross-cutting capabilities |
suite/ |
End-user productivity: email, storage, design, messaging, calendar |
devplatform/ |
Developer tools: forge, terminal, IDE, package registry |
vertical/ |
Vertical solutions: fintech, health, legal, agro, education |
The existing infrastructure Area directories remain unchanged:
| Directory | Stays as-is |
|---|---|
ai/ |
AI infrastructure (gateway, runtime, voice, RAG, eval) |
infra/ |
Network, security, edge, fleet, DNS |
observe/ |
Monitoring, logging, APM, uptime |
data/ |
Databases, queues, search |
core/ |
Shared libraries and services |
sdk/ |
SDKs (Go, JS, Python, Dart) |
lang/ |
Koder Koda and KMD |
linux/ |
Koder Linux distro and desktop |
brand/ |
Brand assets |
docs/ |
Documentation |
context/ |
Configuration, specs, policies |
3.3 Product-root structure
Within each Area directory, every product gets a single root directory. All distribution forms live inside that root as subdirectories:
<area>/<product>/
├── platform/ ← SaaS backend (Go). Koder hosts this.
├── app/
│ ├── mobile/ ← Flutter: Android + iOS
│ ├── desktop/ ← Flutter: Linux + macOS + Windows
│ ├── tv/ ← JavaScript: TizenOS + WebOS
│ └── web/ ← Self-hosted web frontend (if applicable)
└── site/ ← Landing pageRules:
- Not every product needs every subdirectory. A pure SaaS product has only
platform/.A pure mobile app has only
app/mobile/. Add subdirectories only when the distribution form actually exists or is actively planned. platform/inside a product root is the Go backend (SaaS or self-hosted server).It is not the same as the old top-level
platform/directory.app/mobile/andapp/desktop/are each independent Flutter projects(
pubspec.yamlat their respective roots), allowing different UI layouts while sharing business logic via ashared/Dart package when needed.site/is the product landing page, following the existing rule that landing pageslive inside the product repo.
3.4 Engine + product pairs
When a product follows the engine + product split pattern, both the engine and the product live in the same Area, as sibling product roots:
suite/
├── raven/ ← engine (B2B whitelabel email platform)
│ └── platform/ ← Go backend only
└── kmail/ ← product (B2C flagship email client)
├── platform/ ← SaaS webmail backend (Go + JS)
├── app/
│ ├── mobile/
│ └── desktop/
└── site/3.5 Infrastructure modules
Modules in ai/, infra/, observe/, data/ are components, not products. They do not follow the product-root structure — they keep their current flat layout:
ai/
├── gateway/ ← Go service
├── runtime/ ← Go service
└── voice/ ← Go service
infra/
├── jet/ ← Go web server
└── mesh/ ← network config4. Example: full migration of email modules
*efore:*
platform/raven/
platform/kmail/
(no Flutter email client exists yet)*fter:*
suite/
├── raven/
│ └── platform/ ← Go engine (moved from platform/raven/)
└── kmail/
├── platform/ ← Go SaaS webmail (moved from platform/kmail/)
├── app/
│ ├── mobile/ ← Flutter: Android + iOS (new)
│ └── desktop/ ← Flutter: Linux + macOS + Windows (new)
└── site/ ← landing page (moved from platform/kmail/site/)5. Go module paths
Go module paths must be updated to match the new directory structure.
*efore:*module koder.dev/platform/kmail *fter:*module koder.dev/suite/kmail/engine
The go.work file at the monorepo root must be updated to include all new paths.
6. Migration plan
Phase 0 — Freeze (Day 0)
- No new modules created in
apps/orplatform/after RFC is accepted. - New modules go directly to the correct Area directory.
Phase 1 — Infrastructure (Week 1)
- Create the four new Area directories (
foundation/,suite/,devplatform/,vertical/). - Update
CLAUDE.mdanddocs/stack/adding-a-module.mdwith the new structure. - Update
docs/stack/areas.mdto reflect the directory mapping.
Phase 2 — Migrate by Area (Weeks 2–5, one Area per week)
- Move each module to its Area directory using
git mv. - Update
go.modpaths andgo.workentries. - Update all cross-module import paths.
- Update
koder-jetsite entries and DNS if affected. - Update CI/CD pipelines.
Phase 3 — Remove empty directories (Week 6)
- Once all modules are migrated, remove
apps/andplatform/. - Update all remaining references (scripts, docs, context files).
Rollback
Each module migration is an independent git mv commit. Any individual move can be reverted without affecting others.
7. Impact
| Affected area | Change required |
|---|---|
go.work |
All Go module paths updated |
go.mod (each module) |
Module declaration updated |
| Cross-module imports | All `koder.dev/platform |