PostToolUse hook triggers on openapi/*.yaml edits and runs redocly lint with the recommended ruleset (security-defined disabled since endpoints are intentionally public). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
212 lines
7.4 KiB
Markdown
212 lines
7.4 KiB
Markdown
# 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 |
|
|
|
|
### 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.
|
|
|
|
```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.
|