# Core and ext

Two repositories and one runtime: what belongs in core, what belongs in ext and how the folders are laid out.

## Two repositories, one runtime

Nimbly splits every project into two separate git repositories that live nested on disk:

| Repository | What it is | Who owns it |
|---|---|---|
| **core** | The Nimbly framework - routing, template engine, shortcodes, admin, API | Nimbly (never modified per project) |
| **ext** | Your application - routes, templates, data, custom shortcodes | You (every project has its own ext repo) |

On disk they combine into one directory tree:

```
my-project/          ← core repo root
  core/              # Framework internals
  ext/               ← ext repo root (nested inside core)
  css/               # CSS source (shared build)
  js/                # JS source (shared build)
```

This means `git status` at the project root reflects core changes; `git status` inside `ext/` reflects application changes. They are independent repos with independent histories, branches, and remotes.

They are also licensed separately: core is open source under the ISC license, while every ext repo is proprietary - copyright Nimbly Web Systems, all rights reserved - and carries its own `ext/LICENSE.txt`.

## Deciding core vs. ext

The "never modify core" rule is about not bending core's *existing* framework code to fit one app. It is not a rule about where *new* framework-level features belong. Ask: would every Nimbly app need this, not just this project?

- **Yes → core.** Built-in admin screens, generic resource CRUD, auth/roles/permissions, shortcodes any project could use. If getting basic functionality working in a new project would mean copy-pasting the same files into every ext repo, that's a sign the feature is stranded in the wrong place.
- **No → ext.** This project's own resources, routes, business logic, branding, and config - anything that only makes sense for this specific application.

Concrete example of getting it wrong: the role editor (`/nb-admin/roles/(id)` and `/nb-admin/roles/add`) was originally built entirely in `ext/uri/nb-admin/roles/`, even though every other admin resource page (users, media, jobs, ...) is served generically from `core/modules/admin/uri/nb-admin/(resource)/...` with no per-project override at all. Roles/permissions are core to Nimbly's own permission system, not app data - so that route belonged beside `debug/`, `media/`, `profile/` etc. under `core/modules/admin/uri/nb-admin/`, not in ext. Leaving it in ext meant every new project would have to hand-copy those files just to manage roles.

## Directory layout

```
core/          # Framework - never modify
  lib/         # Core libraries and shortcode implementations
  modules/     # Core modules (admin, forms, api, install, user)
  tpl/         # Core templates (html wrapper, etc.)
  uri/         # Core routes
ext/           # Your application - all custom work goes here
  data/        # Resources (.meta + JSON records)
  lib/         # Custom libraries and shortcode implementations
  modules/     # Custom modules
  tpl/         # Reusable templates
  uri/         # Route templates
  static/      # Built assets (output of npm build)
css/           # CSS source
js/            # JS source (JSX/Alpine)
```

**Rule:** Never modify `core/`. All customization lives in `ext/`.

**Rule:** All text in `core/` must be in **English**. Use `[#text Key#]` for every user-facing string so projects can supply translations via `ext/data/.i18n/text.<lang>.po`. Never hard-code Dutch or any other language in core templates.
