Intelligenz, für alle bezahlbar — gute, langlebige Technik, kuratiert statt Ramsch.
evig makes genuinely good computing affordable to everyone — curated, decent hardware people actually want to use, not junk refurb. Founded 2026. This repository is the platform that runs it: a storefront, a community marketplace, repair & IT-help, workshops, an AI-assisted intake pipeline, and an in-house AI assistant.
| Surface | Who it serves | What it does |
|---|---|---|
| Storefront | The public | Sells refurbished hardware (evig-certified) to fund operations |
| P2P Marketplace | Community | Lets members buy / sell / give away tech between each other |
| IT-Hilfe | People who need help | Matches help requests with volunteer technicians; in-person + remote |
| Workshops | Community | Repair Café sessions, Linux installs, digital-skills classes — paid + free |
| Erfassung pipeline | Staff | AI-assisted intake → triage → photo → publish for donated hardware |
| Member services | Members | Member directory, donation history, voting on association decisions (no tax-deductible donation receipts while the Verein is in formation) |
| HIRN AI | Staff | In-house knowledge / action assistant; cascades through Groq / OpenRouter / Ollama |
evig is a non-profit association in formation, run on a market/quality model where affordable pricing is the product, not a subsidy. The economic model is deliberately mixed so no single source carries the whole organization:
- Storefront revenue — curated, decent hardware sold at affordable prices. Margin funds operations.
- Service revenue — paid workshops, repair services, IT-Hilfe billable to companies that can pay (kept affordable for individuals).
- Donations — direct BTC donations and in-kind hardware donations.
- Membership — yearly membership fees.
- Grants & partnerships — selective collaborations with aligned organizations.
The platform is the operational backbone for all five. It is open-source (MIT) so other circular-economy organizations can adopt it directly — there's no extractive layer in between.
The application is a single Next.js 16 app with App Router for both pages and API routes. In production, data lives in self-hosted PostgreSQL 17 on the Hetzner box, accessed through Drizzle ORM via DATABASE_URL. Authentication uses NextAuth v5 (Auth.js) with the @auth/pg-adapter, sharing the same connection pool as the app. Search is powered by Meilisearch. Payments go through Payrexx (Swiss-based, ZKB/Twint/card). Email goes through Resend when RESEND_API_KEY is set, Listmonk when LISTMONK_ENABLED=true, and SMTP (Nodemailer) otherwise (src/config/email.ts). Product/listing images are stored in Cloudflare R2 (S3-compatible).
src/config/database.ts defines every table name as a constant. Every database query references TABLE_NAMES -- never a hardcoded string. The constants are organized into logical groups:
User & Auth | Inventory | Messaging | Services | Workshops | Locations
Applications | Payments | Reviews | Documents | IT-Hilfe | HIRN AI
Staff | Tasks | Content | Activity Stream | Meeting Protocols
P2P Marketplace | Organizational Numbers
Related SSOT exports live alongside: APPOINTMENT_ROLES, REVIEW_TARGET_TYPES, CONVERSATION_TYPES, SERVICE_CATEGORIES, FEATURED_SERVICE_SLUGS.
Adding a new domain means adding constants to one file. If a table name is wrong, it's wrong in one place.
Three tiers, zero ambiguity:
Users --> Staff (is_staff, granted by a super admin) --> Super Admins (DB flag + owner floor)
is_staffboolean +staff_permissionstext array on the users table- Staff status is never derived from the e-mail domain. Anyone may register;
is_staffis granted explicitly (PATCH /api/admin/users/[id]/permissionsor the HR hire flow).isStaffEmailis cosmetic only — it picks a welcome-email template. Super admins come fromusers.is_super_admin, withSUPER_ADMIN_EMAILSas a bootstrap floor so the org cannot lock itself out. - Sensitive sections (finance, users, settings, …) require an explicit
permission —
is_staffalone grants none of them, so money and admin routes must check the section, never the staff flag.
draft --> pending --> approved / rejected
Stored in user_content_submissions. Nothing goes live without review.
In-house AI knowledge management system with an action cockpit and executor. Handles organizational intelligence -- not a chatbot wrapper.
These are enforced, not suggested:
- Logger --
import { logger } from '@/lib/logger'. Neverconsole.log. - TABLE_NAMES -- never hardcoded table strings. Import from
src/config/database.ts. - Parameterized queries -- never string concatenation. No exceptions.
- Swiss German -- user-facing text uses
ss(notß), properä/ö/ü(neverae/oe/ue).pnpm run lint:umlautscatches violations.
| Layer | Technology |
|---|---|
| Framework | Next.js 16 (App Router), React 19, TypeScript 6, Tailwind 4 |
| Database | PostgreSQL (prod: Hetzner self-hosted; dev: Docker 5433), Drizzle ORM |
| Auth | NextAuth v5 (Auth.js) + @auth/pg-adapter (shares the app DATABASE_URL pool) |
| Search | Meilisearch |
| Payments | Payrexx (Swiss-based; ZKB / Twint / card) |
Resend (preferred), Listmonk (opt-in), SMTP via Nodemailer (fallback) — src/config/email.ts |
|
| Storage | Cloudflare R2 (S3-compatible) for product/listing images |
| Rate limiting | Redis |
| AI | HIRN (in-house provider stack: Groq → OpenRouter → Ollama cascade) |
| Testing | Vitest (7,500+ tests), Playwright (E2E) |
| CI/CD | GitHub Actions → self-hosted Hetzner deploy (systemd evig-app) |
Quick Start
- Node.js 22.13+ (CI and deploy run Node 24)
- A PostgreSQL database — local Docker via
pnpm run services:up(port 5433) - Optional: Meilisearch, Redis, Resend or Listmonk for full feature coverage
git clone https://github.com/bitbaum/evig.git
cd evig
cp .env.example .env.local # fill in DATABASE_URL, AUTH_SECRET, payment keys, etc.
pnpm install
pnpm run db:migrate
pnpm run dev # Next.js on :3000At minimum, configure:
DATABASE_URL-- PostgreSQL connection string (postgresql://postgres:postgres@localhost:5433/revampit_cmsfor local Docker; prod uses Hetzner — see.env.selfhost.local.example)AUTH_SECRET-- 32+ char random string for NextAuth JWT signingPAYREXX_INSTANCE/PAYREXX_API_SECRET/PAYREXX_WEBHOOK_SECRET-- payment integrationRESEND_API_KEY(or Listmonk / SMTP settings) -- email deliveryMEILISEARCH_URL/MEILISEARCH_KEY-- search
See .env.example for the full list.
7,500+ tests across 500+ Vitest suites, plus a Playwright E2E layer.
| Category | Coverage |
|---|---|
| API routes | Notifications, admin, IT-Hilfe |
| Business logic | Protocols, payments, currency, tax compliance, HIRN AI |
| Auth | Password handling, permissions, rate limiter |
| Data processing | Bulk extraction, file parsing, CSV export/import |
| Validation | Schema tests |
| E2E (Playwright) | Auth smoke, marketplace, IT-Hilfe, security |
pnpm test # run all Vitest tests
pnpm run test:e2e # run Playwright E2E suiteDefined in .github/workflows/ci.yml:
- Code Quality --
pnpm run verify(lint, umlauts, typecheck, tests, build) on every pull request; on a squash merge tomain(subject ends in(#N)) onlypnpm run verify:main(the same checks without tests and build, about 3 minutes) - Auth Smoke Test and Dual-Persona Inventory Smoke -- Playwright against production, when the test secrets are set
- Migration Drift Check -- replays every migration from zero
- Unit Tests -- Vitest, PR only
- Dependency Security Audit
Merge → live. One full proof per change, on the pull request. On main, a PR merge runs the fast gate and skips the E2E journeys and the production smokes the PR already ran; a main push without (#N) runs everything. Re-running the full bundle on main for a PR merge is a regression. Main runs are grouped per commit, so merges never queue behind each other.
On merge to main, the .github/workflows/deploy-selfhost.yml workflow lints, type-checks, builds the Next standalone bundle, rsyncs it to the Hetzner box, and restarts the systemd evig-app service (with a page-render rollback gate). Vercel is not used for production.
src/
app/ # Next.js App Router (pages + API routes)
[locale]/ # Public site (next-intl, de/fr/en/it/es/ja/ko/ru)
admin/ # Staff admin surface
api/ # API route handlers
components/ # React components (UI only, no business logic)
config/
database.ts # TABLE_NAMES SSOT
org.ts # Org-wide data SSOT (name, address, email, hours)
lib/
auth/ # NextAuth v5 wiring, permissions, staff detection
services/ # Business logic (no HTTP, no UI)
email/ # Templates and delivery
it-hilfe/ # IT-Hilfe domain (notifications, matching, offers)
payments/ # Payrexx integration
logger.ts # Structured logging
hooks/ # Data fetching (SWR), state management
db/schema/ # Drizzle schemas
scripts/
db/migrations/ # Sequential SQL migrations (072 ADD COLUMN token_version, etc.)
src/**/__tests__/ # Vitest suites (co-located with the code)
tests/ # Playwright E2E tests
- Fork and create a feature branch
- Follow the development standards (TABLE_NAMES, logger, parameterized queries, Swiss German rules)
- Run
pnpm testandpnpm run lint:umlautsbefore pushing - Open a PR against
main-- CI will validate code quality and tests
Bitbaum is a platform for the new economy and for creation: building, engineering and researching. It's a community of builders, creators and researchers, and of the people who support them. We work as engineers in the loop: agents do much of the typing, and people own the judgement.
This code is MIT-licensed so that you can take it. Use it, fork it, rebrand it, sell it, or lift a single file. Make it yours and keep improving it the way you like. You don't need to ask, book a call or sign a CLA. Just keep the LICENSE with your copy.
npx degit bitbaum/evig my-evig # a clean copy without our git history
cd my-evig && pnpm install- Needs: Postgres (
pnpm run services:upstarts one in Docker) and.env.example. - Make it yours: the name, colours and contact details start in
src/config/org.ts. - Shared pieces: the
@bitbaum/*kits install from public npm or public GitHub, so you need no tokens or private registry.
More to take: orangecat.ch/steal and github.com/bitbaum.
Copying code is free. What stays scarce once agents and robots write most of it is seeing the whole system. Pick one of these, in this repo, and open an issue or a pull request:
- Find the second source of truth. Find a fact this code defines in two places. Show how the copies will drift, and say where the one copy should live.
- Find the silent failure. Pick a promise this system makes. Find where it fails while every check stays green, and propose the check that would catch it.
- Find where the human belongs. Point to a step where an agent acts alone but a person should decide, or the reverse, and say why.
A short, correct answer beats a long one, and so does an answer that admits what it doesn't know.
evig -- Intelligenz, für alle bezahlbar -- evig.orangecat.ch