# fete A privacy-focused, self-hostable web app for event announcements and RSVPs. An alternative to Facebook Events or Telegram groups — reduced to the essentials. ## 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 `.ics` or subscribe via `webcal://` 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 ```bash # Backend cd backend && ./mvnw test # Frontend cd frontend && npm run test:unit ``` ### Running the backend locally **Option A: Without external PostgreSQL (Testcontainers)** ```bash 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** ```bash 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 ```bash # 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/` has uncommitted changes): | What | Command | Fails on | |---------------------|------------------------------|---------------------------------------| | Vitest | `npm run test:unit -- --run` | Test failures (fail-fast, stops at 1) | **Not hooked** (run manually or via editor): | What | Command | Fails on | |---------------------|------------------|-------------------| | Prettier | `npm run format` | Formatting issues | ## Deployment ### Docker Compose The app ships as a single Docker image. It requires an external PostgreSQL database. ```yaml 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](LICENSE) for details.