8.2 KiB
Privacy-focused, self-hostable event announcements and RSVPs.
An alternative to Facebook Events or Telegram groups — reduced to the essentials.
Create events · Share with guests · Collect RSVPs
What it does
- Create events with title, description, date, time, location, and an expiry date
- Share a single link — guests open it, see all details, and RSVP
- No accounts, no login — the organizer gets a secret token stored in the browser; guests just enter a name
- Automatic cleanup — all event data is permanently deleted after the expiry date
- Works offline-first — installable as a PWA, local event list stored entirely in the browser
For organizers
- Edit event details, post update messages, manage the guest list
- Cancel or delete events at any time
- Generate a QR code for posters and flyers
- Optionally pick a color theme or header image (via self-hosted Unsplash proxy)
For guests
- RSVP with just a name — no personal data required
- Bookmark events locally across devices
- Download
.icsor subscribe viawebcal://for calendar integration - See highlighted changes and new update indicators on revisit
Privacy by design
- No analytics, no telemetry, no external requests from the client
- No CDNs, no Google Fonts, no tracking-capable dependencies
- Server never logs PII or IP addresses
- Data retention is bounded by a mandatory expiry date
Tech stack
| Layer | Technology |
|---|---|
| Backend | Java (latest LTS), Spring Boot, Maven |
| Frontend | Vue 3, Vite, TypeScript |
| Database | PostgreSQL (external, not bundled) |
| Architecture | SPA + RESTful API, hexagonal/onion backend |
| Deployment | Single Docker container |
Development
Prerequisites
- Java (latest LTS) + Maven wrapper (
./mvnw, included) - Node.js (latest LTS) + npm
- Docker (for running backend tests via Testcontainers)
Project structure
fete/
├── backend/ # Spring Boot application (Maven)
├── frontend/ # Vue 3 SPA (Vite, TypeScript)
├── spec/ # User stories, personas, implementation phases
└── CLAUDE.md # Project statutes and AI agent instructions
Running tests
# Backend
cd backend && ./mvnw test
# Frontend unit tests
cd frontend && npm run test:unit
# Frontend E2E tests (requires Chromium: npx playwright install chromium)
cd frontend && npm run test:e2e
Running the backend locally
Option A: Without external PostgreSQL (Testcontainers)
cd backend && ./mvnw spring-boot:test-run
Starts the app with a Testcontainers-managed PostgreSQL that is created and destroyed automatically. Requires Docker.
Option B: With external PostgreSQL
cd backend
cp src/main/resources/application-local.properties.example \
src/main/resources/application-local.properties
# Edit application-local.properties if your PostgreSQL uses different credentials
./mvnw spring-boot:run -Dspring-boot.run.profiles=local
Building
# Backend
cd backend && ./mvnw package
# Frontend
cd frontend && npm run build
Code quality
Automated quality gates run as Claude Code hooks during AI-assisted development. They provide immediate feedback after every file edit and block the agent from finishing when tests fail.
Backend (Java / Maven)
After editing a *.java file (PostToolUse hook):
| What | Command | Fails on |
|---|---|---|
| Checkstyle | ./mvnw compile |
Style violations (Google Style) |
| Java compiler | ./mvnw compile |
Compile errors |
Checkstyle enforces Google Style (2-space indent, import order, Javadoc on public types) and is bound to the validate phase, so it runs automatically as part of every compile. Covers both src/main and src/test.
When the agent finishes (Stop hook — only if backend/src/ has uncommitted changes):
| What | Command | Fails on |
|---|---|---|
| JUnit 5 | ./mvnw test |
Test failures (fail-fast, stops at 1) |
| ArchUnit (9 rules) | ./mvnw test |
Hexagonal architecture violations |
ArchUnit enforces hexagonal boundaries: domain must not depend on adapters, application, config, or Spring; ports must be interfaces; web and persistence adapters must not cross-depend.
Not hooked (run manually):
| What | Command | Fails on |
|---|---|---|
| SpotBugs | ./mvnw verify |
Potential bugs, null dereferences, resource leaks |
Frontend (TypeScript / Vue)
After editing a *.ts or *.vue file (PostToolUse hook):
| What | Command | Fails on |
|---|---|---|
| TypeScript (strict) | vue-tsc --noEmit |
Type errors |
| oxlint + ESLint | oxlint, eslint |
Lint violations |
When the agent finishes (Stop hook — only if frontend/src/ or frontend/e2e/ has uncommitted changes):
| What | Command | Fails on |
|---|---|---|
| Vitest | npm run test:unit -- --run |
Test failures (fail-fast, stops at 1) |
| Playwright | npm run test:e2e |
E2E test failures |
Not hooked (run manually or via editor):
| What | Command | Fails on |
|---|---|---|
| Prettier | npm run format |
Formatting issues |
OpenAPI Spec (YAML)
After editing an openapi/*.yaml file (PostToolUse hook):
| What | Command | Fails on |
|---|---|---|
| Redocly CLI | redocly lint api.yaml |
Structural and ruleset violations |
Validates the OpenAPI 3.1 spec against the Redocly recommended ruleset (with security-defined disabled, since endpoints are intentionally public). Runs via npx @redocly/cli@latest.
Deployment
Docker Compose
The app ships as a single Docker image. It requires an external PostgreSQL database.
services:
db:
image: postgres:17-alpine
environment:
POSTGRES_DB: fete
POSTGRES_USER: fete
POSTGRES_PASSWORD: changeme
volumes:
- fete-db:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U fete"]
interval: 5s
timeout: 3s
retries: 5
app:
image: git.bahamut.nitrix.one/nitrix/fete:latest
ports:
- "8080:8080"
environment:
DATABASE_URL: jdbc:postgresql://db:5432/fete
DATABASE_USERNAME: fete
DATABASE_PASSWORD: changeme
depends_on:
db:
condition: service_healthy
volumes:
fete-db:
Environment variables
| Variable | Required | Default | Description |
|---|---|---|---|
DATABASE_URL |
Yes | — | JDBC connection string |
DATABASE_USERNAME |
Yes | — | Database username |
DATABASE_PASSWORD |
Yes | — | Database password |
License
GPL — see LICENSE for details.



