- Add license/Go/modules status badges to the header - Add a Version column to the modules table and the new `smtp` module - Mark `auth-firebase` as deferred and correct `auth`/`worker` dependencies - Replace the ASCII dependency tree with a colour-coded mermaid graph plus a layer legend - Add a Legal section covering the NOCHEBUENADEV (PFAE) copyright holder, AGPL-3.0 licensing, and the CLA - Add the `smtp` link reference - Add the AGPL-3.0 LICENSE file
192 lines
8.0 KiB
Markdown
192 lines
8.0 KiB
Markdown
# Einherjar
|
|
|
|
[](LICENSE)
|
|
[](https://go.dev)
|
|
[]()
|
|
|
|
> *For those who come after.*
|
|
|
|
A Go framework built from battle-tested production code — organized for teams,
|
|
documented for the developer who was never in the room.
|
|
|
|
---
|
|
|
|
## The Name
|
|
|
|
In Norse mythology, the **Einherjar** are the chosen — warriors who fell in battle
|
|
and were carried to Valhalla by the Valkyries. There they train, day after day,
|
|
preparing for Ragnarök. Not for themselves. For what comes after.
|
|
|
|
This framework carries that name deliberately. Every interface defined here, every
|
|
architectural decision recorded, every module boundary enforced exists for the
|
|
developer who will build on this code without ever speaking to its authors. No
|
|
tribal knowledge. No implicit conventions. **The documentation is the system.**
|
|
|
|
---
|
|
|
|
## What Is This
|
|
|
|
Einherjar is a collection of composable Go modules, each addressing one
|
|
infrastructure concern. The mental model is Spring Boot starters — not one framework
|
|
binary, but a curated set of independent modules with isolated dependency graphs.
|
|
|
|
Each module is its own `go.mod`. Import only what your service needs. A minimal CRUD
|
|
API requires exactly three: **`core` + `web` + one `db-*`**.
|
|
|
|
---
|
|
|
|
## Modules
|
|
|
|
| Module | Version | Purpose | Depends on |
|
|
|---|---|---|---|
|
|
| [`contracts`][contracts] | v1.0.0 | Pure interfaces. The constitution of the framework. | — |
|
|
| [`core`][core] | v1.0.0 | Lifecycle, logging, errors, validation | `contracts` |
|
|
| [`web`][web] | v1.0.0 | HTTP server, middleware, routing, health | `contracts` `core` |
|
|
| [`auth`][auth] | v1.0.0 | Auth middleware, RBAC | `contracts` `core` `web` |
|
|
| [`auth-jwt`][auth-jwt] | v1.0.0 | JWT signing, token pairs, refresh | `contracts` `core` `auth` |
|
|
| [`auth-firebase`][auth-firebase] | — | Firebase authentication *(deferred)* | `contracts` `core` `auth` |
|
|
| [`db-postgres`][db-postgres] | v1.0.0 | PostgreSQL client | `contracts` `core` |
|
|
| [`db-mysql`][db-mysql] | v1.0.0 | MySQL client | `contracts` `core` |
|
|
| [`db-sqlite`][db-sqlite] | v1.0.0 | SQLite client | `contracts` `core` |
|
|
| [`cache-valkey`][cache-valkey] | v1.0.0 | Valkey / Redis-compatible cache | `contracts` `core` |
|
|
| [`storage-minio`][storage-minio] | v1.0.0 | Object storage | `contracts` `core` |
|
|
| [`telemetry`][telemetry] | v1.0.0 | OpenTelemetry — `main` packages only | `contracts` `core` |
|
|
| [`worker`][worker] | v1.0.0 | Concurrent background worker pool | `contracts` |
|
|
| [`httpclient`][httpclient] | v1.0.0 | Resilient outbound HTTP client | `contracts` `core` |
|
|
| [`smtp`][smtp] | v1.0.0 | SMTP email delivery with no-op fallback | `contracts` `core` |
|
|
|
|
---
|
|
|
|
## Dependency Graph
|
|
|
|
```mermaid
|
|
graph TD
|
|
contracts["contracts\nv1.0.0"]
|
|
core["core\nv1.0.0"]
|
|
web["web\nv1.0.0"]
|
|
auth["auth\nv1.0.0"]
|
|
auth_jwt["auth-jwt\nv1.0.0"]
|
|
auth_firebase["auth-firebase\n(deferred)"]
|
|
db_postgres["db-postgres\nv1.0.0"]
|
|
db_mysql["db-mysql\nv1.0.0"]
|
|
db_sqlite["db-sqlite\nv1.0.0"]
|
|
cache_valkey["cache-valkey\nv1.0.0"]
|
|
storage_minio["storage-minio\nv1.0.0"]
|
|
telemetry["telemetry\nv1.0.0"]
|
|
worker["worker\nv1.0.0"]
|
|
httpclient["httpclient\nv1.0.0"]
|
|
smtp["smtp\nv1.0.0"]
|
|
|
|
contracts --> core
|
|
contracts --> web
|
|
core --> web
|
|
contracts --> auth
|
|
core --> auth
|
|
web --> auth
|
|
contracts --> auth_jwt
|
|
core --> auth_jwt
|
|
auth --> auth_jwt
|
|
contracts --> auth_firebase
|
|
core --> auth_firebase
|
|
auth --> auth_firebase
|
|
contracts --> db_postgres
|
|
core --> db_postgres
|
|
contracts --> db_mysql
|
|
core --> db_mysql
|
|
contracts --> db_sqlite
|
|
core --> db_sqlite
|
|
contracts --> cache_valkey
|
|
core --> cache_valkey
|
|
contracts --> storage_minio
|
|
core --> storage_minio
|
|
contracts --> telemetry
|
|
core --> telemetry
|
|
contracts --> worker
|
|
contracts --> httpclient
|
|
core --> httpclient
|
|
contracts --> smtp
|
|
core --> smtp
|
|
|
|
classDef foundation fill:#b45309,stroke:#78350f,color:#fff
|
|
classDef weblayer fill:#1d4ed8,stroke:#1e3a8a,color:#fff
|
|
classDef datalayer fill:#15803d,stroke:#14532d,color:#fff
|
|
classDef standalone fill:#6d28d9,stroke:#4c1d95,color:#fff
|
|
classDef deferred fill:#6b7280,stroke:#374151,color:#fff,stroke-dasharray:5 5
|
|
|
|
class contracts,core foundation
|
|
class web,auth,auth_jwt weblayer
|
|
class auth_firebase deferred
|
|
class db_postgres,db_mysql,db_sqlite,cache_valkey,storage_minio datalayer
|
|
class telemetry,worker,httpclient,smtp standalone
|
|
```
|
|
|
|
**Arrow direction:** dependency flows downward — a module above provides interfaces consumed by the module below it.
|
|
|
|
| Colour | Layer |
|
|
|---|---|
|
|
| Amber | Foundation — `contracts`, `core` |
|
|
| Blue | Web layer — `web`, `auth`, `auth-jwt` |
|
|
| Green | Data layer — `db-*`, `cache-*`, `storage-*` |
|
|
| Purple | Standalone — `telemetry`, `worker`, `httpclient`, `smtp` |
|
|
| Grey (dashed) | Deferred — not yet released |
|
|
|
|
Data modules (`db-*`, `cache-*`, `storage-*`) never import `web`. Repositories do
|
|
not know HTTP exists. This boundary is absolute.
|
|
|
|
---
|
|
|
|
## The Law
|
|
|
|
`contracts` is the constitution of this framework — pure interfaces, zero
|
|
dependencies, permanent signatures. Changes flow **outward from `contracts`**, never
|
|
inward. Before any change to `contracts`, the blast radius is calculated: which
|
|
interfaces are affected, which modules implement them, which modules consume those.
|
|
Release sequence: `contracts` first, then implementors, then consumers.
|
|
|
|
Adding a method to a published interface is a breaking change in Go. It is not
|
|
permitted without a major version bump and coordinated updates across all
|
|
implementing modules.
|
|
|
|
---
|
|
|
|
## For Those Who Come After
|
|
|
|
Good code is not written for the machine. It is not even written for the deadline.
|
|
It is written for the person who will read it at 11pm six months from now, under
|
|
pressure, trying to understand what this thing does and why it was built this way.
|
|
|
|
Every ADR in this organization exists because a decision was made and the reasoning
|
|
behind it matters as much as the outcome. Every interface in `contracts` is as small
|
|
as it can be because the developer implementing it in a new context deserves to know
|
|
exactly what is required and nothing more.
|
|
|
|
This is the standard. Not the deadline.
|
|
|
|
---
|
|
|
|
## Legal
|
|
|
|
Einherjar is developed and maintained by **NOCHEBUENADEV**, the trade name of its founder operating as a *Persona Física con Actividad Empresarial* (PFAE) under Mexican law. A PFAE is a natural person — an individual — who conducts business under their own legal identity. There is no separate corporate entity: the copyright holder is the individual behind NOCHEBUENADEV.
|
|
|
|
All modules are licensed under the **GNU Affero General Public License v3.0** (AGPL-3.0). See the `LICENSE` file in each repository.
|
|
|
|
Contributions are accepted under the terms of the [Contributor License Agreement](https://code.nochebuena.dev/einherjar/contracts/src/branch/main/CLA.md). Contributors retain ownership of their work; they grant NOCHEBUENADEV a perpetual, irrevocable license that includes the right to relicense.
|
|
|
|
---
|
|
|
|
[contracts]: https://code.nochebuena.dev/einherjar/contracts
|
|
[core]: https://code.nochebuena.dev/einherjar/core
|
|
[web]: https://code.nochebuena.dev/einherjar/web
|
|
[auth]: https://code.nochebuena.dev/einherjar/auth
|
|
[auth-jwt]: https://code.nochebuena.dev/einherjar/auth-jwt
|
|
[auth-firebase]: https://code.nochebuena.dev/einherjar/auth-firebase
|
|
[db-postgres]: https://code.nochebuena.dev/einherjar/db-postgres
|
|
[db-mysql]: https://code.nochebuena.dev/einherjar/db-mysql
|
|
[db-sqlite]: https://code.nochebuena.dev/einherjar/db-sqlite
|
|
[cache-valkey]: https://code.nochebuena.dev/einherjar/cache-valkey
|
|
[storage-minio]: https://code.nochebuena.dev/einherjar/storage-minio
|
|
[telemetry]: https://code.nochebuena.dev/einherjar/telemetry
|
|
[worker]: https://code.nochebuena.dev/einherjar/worker
|
|
[httpclient]: https://code.nochebuena.dev/einherjar/httpclient
|
|
[smtp]: https://code.nochebuena.dev/einherjar/smtp
|