Ctrl K
ComunidadGuías…

README.md

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
# Kammer

[![CI](https://github.com/tskovlund/kammer/actions/workflows/ci.yml/badge.svg)](https://github.com/tskovlund/kammer/actions/workflows/ci.yml)
[![Docker](https://github.com/tskovlund/kammer/actions/workflows/docker.yml/badge.svg)](https://github.com/tskovlund/kammer/actions/workflows/docker.yml)
[![CodeQL](https://github.com/tskovlund/kammer/actions/workflows/codeql.yml/badge.svg)](https://github.com/tskovlund/kammer/actions/workflows/codeql.yml)
[![License](https://img.shields.io/github/license/tskovlund/kammer)](LICENSE)
[![Conventional Commits](https://img.shields.io/badge/Conventional%20Commits-1.0.0-fe5196?logo=conventionalcommits&logoColor=white)](https://www.conventionalcommits.org)
[![Renovate](https://img.shields.io/badge/renovate-enabled-brightgreen?logo=renovate)](https://github.com/tskovlund/.github/blob/main/default.json)

Kammer replaces Facebook Groups/Pages/Events, the group email thread, and the
file-sharing half of Google Drive — for associations, bands, clubs, and every
other community that exists first in the real world and only second on a
screen.

<p align="center">
  <img src="docs/screenshots/feed-desktop.png" alt="A group feed in Kammer: Markdown posts, reactions, comments, and a composer with polls, scheduling, and acknowledgment-required posts" width="800">
</p>
<p align="center">
  <img src="docs/screenshots/feed-mobile.png" alt="The mobile feed with bottom tab navigation" width="189">
  <img src="docs/screenshots/feed-desktop-dark.png" alt="The same feed in dark mode" width="399">
  <img src="docs/screenshots/event-desktop.png" alt="An event page with RSVPs and comments" width="399">
</p>
<p align="center">
  <img src="docs/screenshots/files-desktop.png" alt="A group file space with a sheet-music folder" width="800">
</p>

<sub>Screenshots are refreshed as a batch before v1; the Svelte PWA's flows are exercised end to end on every change by the Playwright suite (`scripts/e2e.sh`).</sub>

## Why Kammer

- **No ads. No algorithm. Ever.** Feeds are strictly chronological plus
  pinned posts. What your community posts is what your community sees.
- **Privacy-first.** No tracking, no analytics, no phone-home. Honest about
  limits: we tell you exactly what the server operator can and cannot see.
- **A joy to self-host.** One `docker compose up`, a first-run wizard,
  built-in backups with a restore guide, and a reproducible Nix-defined
  dev environment for contributors.
- **Institutional memory is the product.** Groups archive instead of
  vanishing; files stay browsable; seasonal bands and committees keep their
  history.

## Features

- **Passwordless sign-in** — magic links and passkeys.
- **Communities and groups** — one instance hosts many communities; four
  visibility presets (`private`, `community`, `public_link`, `public_listed`),
  join/posting/comment policies, invite links, roles, and **sealed groups**
  that even community admins cannot open.
- **Feed** — Markdown posts, images (re-encoded with metadata stripped,
  thumbnailed), polls, file attachments, emoji reactions, single-level
  comment threads, mentions, pinned + scheduled + acknowledgment-required
  posts, live updates.
- **Guest interactions** — on public groups that opt in, people without
  accounts can RSVP, sign up for slots, comment (moderator-approved), and
  subscribe to a group's feed by email (every post or a daily/weekly
  digest, one-click unsubscribe), all through signed email links with
  one-click full erasure.
- **Events** — timezone-aware, all-day/multi-day, RSVP, comments, email
  reminders, ICS calendar feeds, and **signup slots** ("bring cake ×2,
  drive ×4") that members and guests claim with one tap.
- **Files** — community and group spaces, shallow folders, preset-based
  permissions with a centrally enforced visibility invariant, version
  history on every file, quotas if you want them.
- **Collaboration tools, per group** — date-finding polls that become
  events, a flat assignments list built on volunteering, and a decisions
  register for minutes-grade institutional memory. Each is a toggle,
  off by default.
- **Search** — full-text across posts, comments, events, and files (names
  and extracted PDF/plaintext), guaranteed (property-tested) never to
  surface anything you couldn't already see.
- **Notifications** — in-app center, email, and Web Push with sane
  "highlights" defaults.
- **Home** — one merged, strictly chronological view of everything you
  belong to, across communities; every group has a "Show in Home"
  switch.
- **Feature toggles per group** — groups show only the tools they use;
  turning one off hides it without deleting anything.
- **JSON API** (`/api/v1`) — passwordless device tokens, the same
  authorization as the UI (property-tested), the foundation for the
  coming clients.
- **English + Danish** throughout, including emails.

## Quickstart (self-hosting)

```sh
git clone https://github.com/tskovlund/kammer.git
cd kammer
cp .env.example .env      # edit: PHX_HOST, SECRET_KEY_BASE, POSTGRES_PASSWORD, SMTP_*
docker compose up -d
```

Then open your instance URL and follow the first-run wizard — the setup
token is printed in the server logs (`docker compose logs app`). The wizard
creates your operator account, instance settings, first community and group,
an invite link, and (optionally) a removable demo community. Health checks
live at `/healthz`; put a TLS proxy in front (see
`docs/deploy/Caddyfile.example`). Kammer applies its boot-time
configuration against the database and deliberately fails to start if
Postgres isn't reachable — the bundled compose file already gates the
app on a healthy database; a hand-rolled systemd/k8s setup should do
the same (or rely on restart-on-failure). The image also bundles and serves the
[Svelte web app](docs/decisions/0024-pwa-replaces-liveview.md) at the site
root on the same domain — no extra configuration or separate deployment.

## Documentation

| Document                                  | What it covers                                             |
| ----------------------------------------- | ---------------------------------------------------------- |
| [Development](docs/development.md)        | Workflow, everyday commands, what the automation does      |
| [Releasing](docs/release.md)              | Tag-driven releases, versioning, immutability              |
| [Backups & restore](docs/backups.md)      | Taking snapshots, restoring them, retention and encryption |
| [Deployment](docs/deploy/)                | Reverse-proxy example; `.env.example` documents all config |
| [Architecture decisions](docs/decisions/) | The ADRs — the "why" behind the shape of the system        |

## Contributing

The dev environment is defined once (Nix flake) with three entry paths:

```sh
direnv allow    # or: devbox shell    # or: nix develop
mix setup && mix phx.server
```

Contributions work as **prompt requests**: open a well-described issue
(bug, feature, design sketch) and a maintainer implements it — usually
Claude, an AI coding agent (see [Author](#author) below) — see
[CONTRIBUTING.md](CONTRIBUTING.md) for the why, and
[CONVENTIONS.md](CONVENTIONS.md) for the bar. Engineering standards
(Credo strict, Dialyzer, warnings-as-errors, coverage floor,
Conventional Commits) are enforced by hooks and CI.

## Honest limitations

- **The server operator can technically read the database.** "Sealed" groups
  hide content from community admins — not from whoever runs the server.
  There is no end-to-end encryption.
- No chat/DMs, no video upload, no document editing in v1 — deliberate scope
  choices, not oversights.
- Upload hardening (image re-encoding, metadata stripping, content-type
  validation, forced downloads for non-images) is always on; antivirus
  scanning is not built in.

## Author

Thomas Skovlund Hansen — [skovlund.dev](https://skovlund.dev) · [thomas@skovlund.dev](mailto:thomas@skovlund.dev)

Most of Kammer's code is written by Claude (Anthropic's AI coding
agent), operating autonomously against the issue queue — implementing,
testing, and opening PRs. The owner specifies scope and retains final
say on anything product-shaping; see
[CONTRIBUTING.md](CONTRIBUTING.md) for the model and
[AGENTS.md](AGENTS.md) for the actual operating process.

## License

[AGPLv3](LICENSE). If you run a modified Kammer as a service for others, the
license requires you to publish your changes under the same terms.