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, Swiss-compliant donation receipts, voting on association decisions |
| HIRN AI | Staff | In-house knowledge / action assistant; cascades through Groq / OpenRouter / Ollama |
evig is not VC-backed and not a charity — it runs 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 is delivered via Listmonk with Nodemailer / Brevo as fallback. Product/listing images are stored in Cloudflare R2 (S3-compatible).
src/config/database.ts defines ~130 table name constants. 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 (@revamp-it.ch email) --> Super Admins (hardcoded list)
is_staffboolean +staff_permissionstext array on the users table- Staff detection by email domain; super admins by explicit list
- Sensitive sections require permission checks -- no implicit trust
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).npm run lint:umlautscatches violations.
| Layer | Technology |
|---|---|
| Framework | Next.js 16 (App Router), React 18, TypeScript 5, Tailwind 3 |
| 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) |
| Listmonk (primary), Nodemailer / Brevo (fallback) | |
| Storage | Cloudflare R2 (S3-compatible) for product/listing images |
| Rate limiting | Redis (upstash) |
| AI | HIRN (in-house provider stack: Groq → OpenRouter → Ollama cascade) |
| Testing | Jest (7,500+ tests), Playwright (E2E) |
| CI/CD | GitHub Actions → self-hosted Hetzner deploy (systemd revampit-app) |
Quick Start
- Node.js 20+
- A PostgreSQL database — local Docker via
npm run services:up(port 5433) - Optional: Meilisearch, Redis, Listmonk for full feature coverage
git clone https://github.com/maonakamoto/evig.git
cd evig
cp .env.example .env.local # fill in DATABASE_URL, AUTH_SECRET, payment keys, etc.
npm install
npm run db:migrate
npm 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 integrationLISTMONK_URL+ Listmonk credentials -- email deliveryMEILISEARCH_URL/MEILISEARCH_KEY-- search
See .env.example for the full list.
7,500+ tests across 500+ Jest 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 |
npm test # run all Jest tests
npm run test:e2e # run Playwright E2E suiteDefined in .github/workflows/ci.yml:
- Code Quality -- ESLint + TypeScript type check + Next.js build
- Auth Smoke Test -- Playwright, runs conditionally
- Unit Tests -- Jest, PR only
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 revampit-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/en/fr/es/it/ja/ko)
admin/ # Staff admin surface
api/ # API route handlers
components/ # React components (UI only, no business logic)
config/
database.ts # TABLE_NAMES SSOT (~130 constants)
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.)
tests/ # Jest test suites
e2e/ # Playwright E2E tests
- Fork and create a feature branch
- Follow the development standards (TABLE_NAMES, logger, parameterized queries, Swiss German rules)
- Run
npm testandnpm run lint:umlautsbefore pushing - Open a PR against
main-- CI will validate code quality and tests
MIT
evig -- Intelligenz, für alle bezahlbar -- evig.orangecat.ch