# ADR-001 (feature-local) โ€” Avatars reuse the archive bucket under an `avatars/` prefix **Status:** Accepted **Date:** 2026-06-13 **Issue:** # (profile picture upload) > **Feature-local ADR.** This decision is scoped to the avatar feature and lives with its > spec. A decision with project-wide reach is promoted to the permanent archive at > `docs/adr/` with the next free number. (For the worked example, it stays local.) ## Context Avatars are small binary objects keyed per user. The project already runs MinIO with a single archive bucket and a `FileService` abstraction used by document uploads. We must decide where avatar bytes live without adding operational surface that the self-hosted Compose deployment has to learn about. ## Decision Store each avatar in the **existing archive bucket** under the deterministic key `avatars/{userId}`, written and read through the existing `FileService`. No new bucket, no new env var, no new Compose service or bucket-bootstrap step. ## Alternatives Considered | Option | Pros | Cons | Reason rejected | |---|---|---|---| | Reuse archive bucket, `avatars/` prefix | No infra change; reuses `FileService`; idempotent overwrite | Mixes avatars with documents in one bucket | **Chosen** โ€” least operational cost; prefix keeps them logically separate | | Dedicated `avatars` bucket | Clean separation; independent lifecycle/policy | New bucket + bootstrap step + env var + Compose idempotency test | Operational overhead not justified for small, low-value objects | | Store bytes in PostgreSQL (`bytea`) | One datastore; transactional with the row | Bloats the DB and backups; streaming images via JPA is awkward | Wrong tool; MinIO already exists for blobs | | External CDN / object store | Offloads bandwidth | New third-party dependency + secret + ADR; conflicts with self-hosted goal | Contradicts the self-hosted infrastructure stance | ## Consequences - No deployment change ships with this feature โ€” only a Flyway column and code. - Avatars and documents share a bucket; any future per-object lifecycle policy must filter by the `avatars/` prefix. - The deterministic key (`avatars/{userId}`, no random suffix) makes replace an overwrite, so there is no orphan-cleanup obligation (REQ-001). - If avatars later need independent retention or a public CDN, this ADR is superseded by a project-wide ADR in `docs/adr/`. ## References - [`./spec.md`](./spec.md), [`./design.md`](./design.md) - [constitution ยง5 Dependency Policy](../../constitution.md#5-dependency-policy)