docs and agents.md
This commit is contained in:
commit
fde4e11f24
7 changed files with 579 additions and 0 deletions
89
AGENTS.md
Normal file
89
AGENTS.md
Normal file
|
|
@ -0,0 +1,89 @@
|
|||
# AGENTS.md — eutopic
|
||||
|
||||
eutopic is a photo-first social app for small, trusted, invite-only communities.
|
||||
not a global network. not optimized for engagement or attention.
|
||||
target: 5–50 users at launch, growing by invite only.
|
||||
|
||||
---
|
||||
|
||||
## where to look
|
||||
|
||||
| what you need | read | when |
|
||||
|---|---|---|
|
||||
| vision + values | docs/CONCEPT.md | onboarding, big picture, tone questions |
|
||||
| interaction + UI decisions | docs/DESIGN.md | frontend, UX, feature work |
|
||||
| entities + schema | docs/DATA-MODEL.md | backend, db, API work |
|
||||
| what's decided vs open | docs/OPEN-QUESTIONS.md | before proposing anything new — always |
|
||||
| versioned plan | docs/ROADMAP.md | scoping, prioritization |
|
||||
| backend + API structure | docs/ARCHITECTURE.md | does not exist yet. create before v0 alpha. |
|
||||
|
||||
---
|
||||
|
||||
## locked — do not relitigate
|
||||
|
||||
**product**
|
||||
- chronological feed only. no algorithm, no ranking, no engagement bait.
|
||||
- no push notifications in v1.
|
||||
- no DMs in v1.
|
||||
- no analytics or tracking. zero. not even self-hosted.
|
||||
- no federation UI. activitypub via fedify is in the stack, federation flag is OFF.
|
||||
- no premium tier. no donor badges. no class hierarchy in the app.
|
||||
- no manifesto, no political iconography on any user-facing surface.
|
||||
- `is_event` flag on posts for bulletin board. not a separate entity.
|
||||
- reactions: poster defines up to 5 emoji + open picker fallback. stored as user + post + emoji + timestamp.
|
||||
- save/bookmark: optional, toggled by poster at compose. default off.
|
||||
- story interactions: no replies. "witnessed" metadata only, private, 24h.
|
||||
- comments: flat, chronological, on posts only.
|
||||
|
||||
**ux**
|
||||
- users should never be asked to understand anything instagram doesn't ask them to understand.
|
||||
- onboarding: invite link → install → email + username → magic link → in.
|
||||
- the activitypub layer is invisible to users, always.
|
||||
|
||||
**never use**
|
||||
- firebase, meta SDKs, google analytics, cloudflare, amazon, github, stripe-as-primary.
|
||||
|
||||
---
|
||||
|
||||
## conditionally open
|
||||
|
||||
- **notifications**: off in v1. DM notifications only if DMs land in v2. never for feed activity.
|
||||
- **DMs**: deferred to v2. three options on table. not decided.
|
||||
- **federation**: flag off. may flip in v2/v3. UI stays invisible either way.
|
||||
- **PWA**: deferred. may ship in v1.5.
|
||||
|
||||
---
|
||||
|
||||
## stack (settled)
|
||||
|
||||
runtime: bun / framework: elysia / activitypub: fedify / db: sqlite (postgres-ready) /
|
||||
storage: filesystem → s3-compatible / uploads: tus.io / mobile: react native + expo (no EAS) /
|
||||
hosting: njalla VPS / proxy: nginx / process: systemd / forge: radicle / funding: liberapay
|
||||
|
||||
---
|
||||
|
||||
## tone + voice
|
||||
|
||||
- quiet, not precious.
|
||||
- no manifestos. no "we believe in" statements.
|
||||
- register: "eutopic is a quiet place for friends to share photos."
|
||||
- corporate, activist, or startup-y copy is wrong.
|
||||
- transparency about costs: fine. nagging: not.
|
||||
|
||||
---
|
||||
|
||||
## values (as constraints)
|
||||
|
||||
- anti-attention economy: check every feature decision against this.
|
||||
- "the architecture is the belief" — values show in what's built and refused, not in copy.
|
||||
- compromises (react native, app stores) are named honestly in the about/credits page.
|
||||
|
||||
---
|
||||
|
||||
## when in doubt
|
||||
|
||||
1. check OPEN-QUESTIONS.md before proposing anything. don't relitigate closed decisions.
|
||||
2. check tone: would this copy sound corporate or activist? wrong register.
|
||||
3. check values: does this feature serve attention extraction? if yes, refuse it.
|
||||
4. don't invent answers to open questions. flag them instead.
|
||||
5. if stuck or out of depth: run `/escalate` → writes `~/.claude/handover.md` → exits.
|
||||
5
docs/ARCHITECTURE.md
Normal file
5
docs/ARCHITECTURE.md
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
# ARCHITECTURE.md — eutopic
|
||||
|
||||
*to be fleshed out before v0 alpha.*
|
||||
|
||||
covers: backend structure, API shape, federation mechanics, background job design, endpoint inventory.
|
||||
209
docs/CONCEPT.md
Normal file
209
docs/CONCEPT.md
Normal file
|
|
@ -0,0 +1,209 @@
|
|||
# eutopic — concept doc v0.1
|
||||
|
||||
> *a small good place. social media that visits you when you visit it.*
|
||||
|
||||
## what it is
|
||||
|
||||
eutopic is a federation-capable, photo-first social app for small trusted communities. it's a place to post pictures and short stories for friends and friends-of-friends — explicitly not a global network, not algorithmically driven, and not optimized for attention extraction.
|
||||
|
||||
the immediate goal is to give a specific community a real alternative to instagram that doesn't ask them to learn the fediverse, pick a server, or understand what activitypub is. it should feel like opening any other app — but without the cruft, surveillance, and dopamine grift of meta's products.
|
||||
|
||||
## who it's for
|
||||
|
||||
- a small community currently on instagram, with low-to-medium tech literacy
|
||||
- 70/30 ios/android split
|
||||
- mostly EU-based, finnish leaning, mixed language preferences
|
||||
- 5-50 people at launch, growing organically by invite
|
||||
|
||||
## what it does (v1)
|
||||
|
||||
- **feed** — chronological, no algorithm, posts with up to 10 photos
|
||||
- **stories** — 10s auto-advance, basic filters via swipe, no replies, 24h expiry
|
||||
- **reactions** — a curated set of meaningful reactions (8 max), replacing the generic "like"
|
||||
- **profiles** — username, display name, avatar, bio
|
||||
- **invite-only signup** — magic-link email auth, no passwords
|
||||
- **community surveys** — adding the possibility of feedback for dev work, unusual for mass social media. shows that we care
|
||||
|
||||
## what it explicitly doesn't do (v1)
|
||||
|
||||
- **no push notifications** — eutopic doesn't ping you. you visit when you visit.
|
||||
- **no DMs** — use signal, element, or another tool. for now, profiles include "message me at [telegram/signal/element/matrix handle]". eutopic stays focused on photo-sharing only. defensible posture — "we do one thing, well." mirrors the no-notifications stance.actual dm impl deferred to v2.
|
||||
- **no analytics or tracking** — none. zero. not even self-hosted.
|
||||
- **no algorithm** — chronological feed, no ranking, no engagement bait.
|
||||
- **no scheduling, drafts, or queue UI** — bad-wifi handled invisibly via background upload.
|
||||
- **no federation** — initially. the protocol is there but turned off.
|
||||
|
||||
## what makes it different
|
||||
|
||||
1. **no notifications by design** — a deliberate stance, not a missing feature.
|
||||
2. **DIY animation aesthetic** — hand-drawn upload progress, hand-picked reactions, design imperfection as identity.
|
||||
3. **transparent costs, donation funded** — single "about" page with real monthly numbers, link to liberapay.
|
||||
4. **no premium tier, no badges** — donation is private, no class hierarchy in the app.
|
||||
5. **federation-capable but closed** — built on activitypub via fedify, federation off by default. flag-flippable later without rewrites.
|
||||
6. **invisibly leftist** — values inform every architectural choice, but never appear on the surface. no manifestos, no political iconography, no "we believe in" claims. people who care about the values recognize them; people who don't just enjoy the product. the architecture is the belief.
|
||||
|
||||
## stack
|
||||
|
||||
### backend
|
||||
- **runtime**: bun
|
||||
- **web framework**: elysia
|
||||
- **activitypub**: @fedify/fedify + @fedify/elysia
|
||||
- **database**: sqlite (via bun:sqlite), postgres-ready schema for later migration
|
||||
- **media storage**: filesystem first, swap to S3-compatible (greenhost/hetzner) later
|
||||
- **upload protocol**: tus.io (resumable, background-friendly)
|
||||
- **reverse proxy**: nginx
|
||||
- **process management**: systemd
|
||||
|
||||
### mobile
|
||||
- **framework**: react native + expo (framework only, not EAS)
|
||||
- **navigation**: expo router
|
||||
- **builds**: local on M3 mac for ios, radicle CI for android
|
||||
- **upload**: tus client + expo-background-task / URLSession background tasks
|
||||
- **animations**: lottie or APNG, hand-drawn DIY
|
||||
|
||||
### infrastructure
|
||||
- **hosting**: njalla VPS from day one (skip the laptop-server phase for public use)
|
||||
- **domain**: eutopic.space canonical, eutopic.eu redirect
|
||||
- **code forge**: radicle (p2p, no github)
|
||||
- **CI**: self-hosted radicle CI runner
|
||||
- **editor**: vscodium (no microsoft telemetry)
|
||||
- **package manager**: bun (no separate npm/yarn)
|
||||
- **funding**: liberapay primary, ko-fi/open collective backup, mobilepay deferred
|
||||
|
||||
### dev toolchain (the ai-stack + front-desk)
|
||||
front-desk is a CLI orchestrator that routes coding sessions to models based on **user state**, not task type. 4-choice check-in on session start:
|
||||
|
||||
- **fresh** ── clean slate → gemma-4-E4B-it (local, LM Studio)
|
||||
- **continuing** ── picking up prior work → gemma-4-E4B-it (local, LM Studio)
|
||||
- **stuck** ── need help thinking through blockers → claude sonnet (native, subscription)
|
||||
- **overwhelmed** ── small steps, one at a time → qwen3-4b-instruct-2507-mlx (local, LM Studio)
|
||||
|
||||
cloud stack via opencode for involved work: GLM-4.7 (z.ai, apache 2.0) as conversational daily, DeepSeek V3.2 as cost-efficient workhorse, GLM-4.7-Flash for lightweight tasks.
|
||||
|
||||
escalation: `/escalate` writes `~/.claude/handover.md` and exits; front-desk detects it on next start and execs native claude.
|
||||
|
||||
hardware ceiling: M3 MBP, 18GB unified memory → practical local model ceiling ~10–11GB.
|
||||
|
||||
repo: `/Users/pthfndr/dev/ai-stack`, radicle primary, github mirror as `eutopiacode`.
|
||||
|
||||
### shared context for eutopic
|
||||
single `AGENTS.md` at the eutopic repo root, read by all routed models in front-desk. terse and decision-focused — encodes the locked-in choices (no notifications, federation off, invisibly leftist tone, etc.) so any model invoked produces consistent output.
|
||||
|
||||
## architecture decisions
|
||||
|
||||
### why fedify from day one with federation off
|
||||
- avoids painful rewrite later if federation becomes desired
|
||||
- adds upfront cost is minimal (it's a library, not a protocol implementation)
|
||||
- data model uses URIs from the start, makes future migration trivial
|
||||
- can be turned on by config flag without breaking clients
|
||||
|
||||
### why no notifications in v1
|
||||
- biggest single technical simplification (no APNs, FCM, UnifiedPush, device tokens)
|
||||
- aligns with anti-attention-economy values
|
||||
- ships v1 weeks faster
|
||||
- ships with a strong differentiator
|
||||
- can revisit if/when DMs are added in v2
|
||||
|
||||
### why background + resumable uploads
|
||||
- meta's posting feels instant because uploads are invisible
|
||||
- bad-wifi survival (commutes, trains, rural areas)
|
||||
- "the slowest part of using social media" disappears
|
||||
- tus protocol is open, multiple implementations
|
||||
|
||||
### why njalla day one, not laptop
|
||||
- laptop-server experience killed pixelfed adoption in this community before
|
||||
- residential bandwidth + sleep + ISP outages = trust death
|
||||
- €15-30/mo on njalla covers 20-100 users comfortably
|
||||
- migration path to bigger hosts exists if needed
|
||||
|
||||
## the meta-migration problem (named)
|
||||
|
||||
this community already tried pixelfed and bounced back to instagram. the failure mode wasn't pixelfed's quality — it was the cumulative weight of small decisions: pick a server, understand handles, install a third-party client, deal with federation timeline weirdness. each "wait, what?" is a friction point that compounds.
|
||||
|
||||
eutopic's design constraint: **the user should never be asked to understand anything that doesn't have a direct analog in instagram.** no server picker, no handle explanation, no fediverse vocabulary anywhere in the UI. the activitypub layer is invisible.
|
||||
|
||||
## onboarding flow (target)
|
||||
|
||||
```
|
||||
1. friend texts you an invite link
|
||||
2. tap link → app store / play store → install
|
||||
3. open app, invite code prefilled from deep link
|
||||
4. enter email + pick username
|
||||
5. magic link to email → tap → you're in
|
||||
6. friends-of-the-inviter auto-suggested to follow
|
||||
7. post your first photo
|
||||
```
|
||||
|
||||
zero decisions about technology. zero "where do you want to live online" questions.
|
||||
|
||||
## funding model
|
||||
|
||||
a single "about" page (and a settings-page link) with:
|
||||
|
||||
- **hosting** ── €X/mo
|
||||
- **domain** ── €Y/yr
|
||||
- **apple developer program** ── $99/yr
|
||||
- **current month** ── covered ✓ / short by €N
|
||||
- **support eutopic** ── link to liberapay (opens in browser, not in-app purchase)
|
||||
|
||||
no donor badges, no public donor list, no "premium tier," no nagging popups. donation is private and doesn't change in-app experience.
|
||||
|
||||
## about page tone (target)
|
||||
|
||||
a single quiet page. no manifesto, no flags. example phrasing:
|
||||
|
||||
- "eutopic is a quiet place for friends to share photos."
|
||||
- "we don't track you. we don't run ads. we don't sell your data."
|
||||
- "we don't notify you — visit when you want to."
|
||||
- "running it costs ~€X/month. donations help cover hosting."
|
||||
- "made with care in EU."
|
||||
|
||||
## the subversive stance (internal value, not surface copy)
|
||||
|
||||
eutopic is built on tools the giants gave away — react native (meta), bun (originally seeded by US capital), the npm registry (microsoft), apple's runtime (apple), even activitypub (a w3c spec adopted by what used to be a small twitter alternative). we are using their open work to build something they wouldn't.
|
||||
|
||||
this isn't compromise, it's strategy. opensourcing tools is the one good thing big tech does. using those tools against the extraction economy they invented is the entire point. linux ran on intel chips and ate intel's lunch in servers. eutopic runs on react native and aims to make meta's social graph products less necessary, one community at a time.
|
||||
|
||||
internal mantras for design and engineering decisions:
|
||||
- *take their rope, use it to leave*
|
||||
- *the tool is not the master*
|
||||
- *the architecture is the belief*
|
||||
|
||||
surface-level: a credit line in the about/credits page is enough for nerds who notice:
|
||||
|
||||
> "eutopic uses react native, an open-source framework made by meta. we use their open work to build something they wouldn't."
|
||||
|
||||
everywhere else: this stance is invisible. it's a private joke we share with anyone who asks.
|
||||
|
||||
## reactions (initial concept)
|
||||
|
||||
a curated set of 6-8 reactions, hand-picked or hand-drawn, each meaningful. final set TBD with design collaborators. starting palette:
|
||||
|
||||
- ✿ — something beautiful
|
||||
- ☕ — cozy, comfortable
|
||||
- ⚡ — electric, exciting
|
||||
- 🌱 — growth, change
|
||||
- 🫧 — gentle, soft
|
||||
- 👁 — i see you, witnessed
|
||||
|
||||
posts could be sortable by reaction type (see things people found cozy). reactions could rotate seasonally.
|
||||
|
||||
## tech audit (compromises named)
|
||||
|
||||
### actively avoided
|
||||
firebase, meta SDKs, google analytics, cloudflare, amazon, github, stripe-as-primary.
|
||||
|
||||
### compromised but unavoidable
|
||||
- **apple developer program** ($99/yr) — required for ios distribution
|
||||
- **apple app store** — gatekeeping, content review power; mitigated by PWA fallback option
|
||||
- **google play store** — same gatekeeping; mitigated by F-Droid + sideloaded APK
|
||||
- **react native** (meta-maintained) — small irony of using meta's framework to flee meta, named honestly
|
||||
|
||||
### neutral with caveats
|
||||
- expo (US company, but framework is MIT and works without EAS)
|
||||
- node/npm (microsoft-owned registry but packages themselves are FOSS)
|
||||
- njalla (values-aligned but small; backup plan = greenhost / 1984 / flokiNET)
|
||||
- fedify (small project, low bus factor; AP is a spec so swappable)
|
||||
|
||||
### values-aligned
|
||||
bun, elysia, sqlite, postgres, nginx, debian, systemd, tus, liberapay, radicle, F-Droid.
|
||||
186
docs/DATA-MODEL.md
Normal file
186
docs/DATA-MODEL.md
Normal file
|
|
@ -0,0 +1,186 @@
|
|||
# DATA-MODEL.md — eutopic
|
||||
|
||||
what gets stored and how. for interaction decisions see UIUX.md (pending).
|
||||
`?` = nullable. `//` = notes. `// constraint:` = multi-field constraint.
|
||||
|
||||
---
|
||||
|
||||
## user
|
||||
|
||||
```
|
||||
id: uri; // activitypub, internal truth
|
||||
username: string; // unique within instance
|
||||
display_name: string;
|
||||
avatar_url: string?;
|
||||
bio: string?;
|
||||
email: string; // unique
|
||||
created_at: timestamp;
|
||||
is_admin: bool; // default false. survey creation only.
|
||||
federation_ready: bool; // always false until federation flag flips
|
||||
|
||||
display_social_handle: none | mutuals | all;
|
||||
social_handles: [ // array, one entry per platform
|
||||
platform: signal | telegram | custom;
|
||||
handle: string;
|
||||
label: string?; // only for custom platform
|
||||
active: bool; // hides without deleting
|
||||
]
|
||||
contact_prefs: string?; // free text e.g. "bad texter", "weekends only"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## post
|
||||
|
||||
```
|
||||
id: uri;
|
||||
author_id: user.id;
|
||||
body: string?;
|
||||
photos: string[]; // urls, max 10
|
||||
created_at: timestamp;
|
||||
is_event: bool; // default false
|
||||
saveable: bool; // default false, toggled by poster at compose
|
||||
reaction_set: string[]?; // emoji, max 5. null = open picker only.
|
||||
|
||||
event_date: timestamp?; // required if is_event
|
||||
event_ends_at: timestamp?; // required if is_event
|
||||
event_location: string?;
|
||||
event_tags: string[]; // max 2, for bulletin board filters
|
||||
archived_at: timestamp?; // set by background job 1 day after event_ends_at
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## story
|
||||
|
||||
```
|
||||
id: uri;
|
||||
author_id: user.id;
|
||||
media_url: string;
|
||||
filter: string?;
|
||||
created_at: timestamp;
|
||||
expires_at: timestamp; // created_at + 24h
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## story_witness
|
||||
|
||||
// private. one row per viewer per story. author sees flat witness list. no public count.
|
||||
|
||||
```
|
||||
id: uri;
|
||||
story_id: story.id;
|
||||
viewer_id: user.id;
|
||||
witnessed_at: timestamp;
|
||||
expires_at: timestamp; // mirrors story.expires_at
|
||||
// constraint: unique(story_id, viewer_id)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## reaction
|
||||
|
||||
// no counters stored. counts derived at read time.
|
||||
|
||||
```
|
||||
id: uri;
|
||||
post_id: post.id;
|
||||
user_id: user.id;
|
||||
emoji: string;
|
||||
created_at: timestamp;
|
||||
// constraint: unique(post_id, user_id) // one reaction per user per post
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## comment
|
||||
|
||||
```
|
||||
id: uri;
|
||||
post_id: post.id;
|
||||
author_id: user.id;
|
||||
body: string;
|
||||
created_at: timestamp;
|
||||
deleted_at: timestamp?; // soft delete. author or post owner can delete.
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## follow
|
||||
|
||||
// junction table: tracks directional relationships between users
|
||||
|
||||
```
|
||||
id: uri;
|
||||
follower_id: user.id; // the one who initiates
|
||||
followee_id: user.id; // the one being followed
|
||||
created_at: timestamp;
|
||||
status: pending | accepted | blocked; // default accepted. no follow requests in v1, may change.
|
||||
// constraint: unique(follower_id, followee_id) // no duplicate follows
|
||||
// constraint: follower_id != followee_id // cannot follow yourself
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## invite
|
||||
|
||||
```
|
||||
id: uri;
|
||||
code: string; // unique
|
||||
created_by: user.id;
|
||||
used_by: user.id[]; // multi-use: one link per social cluster
|
||||
max_uses: int?;
|
||||
expires_at: timestamp?;
|
||||
created_at: timestamp;
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## save
|
||||
|
||||
```
|
||||
id: uri;
|
||||
post_id: post.id; // only valid if post.saveable = true
|
||||
user_id: user.id;
|
||||
created_at: timestamp;
|
||||
// constraint: unique(post_id, user_id)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## survey
|
||||
|
||||
// admin-created. mc only. ephemeral. dev use only — no results shown to users.
|
||||
|
||||
```
|
||||
id: uri;
|
||||
created_by: user.id; // must be is_admin
|
||||
question: string;
|
||||
options: string[]; // multiple choice only
|
||||
expires_at: timestamp; // short-lived, exact duration tbd
|
||||
created_at: timestamp;
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## survey_response
|
||||
|
||||
```
|
||||
id: uri;
|
||||
survey_id: survey.id;
|
||||
user_id: user.id;
|
||||
chosen_option: int; // index into survey.options
|
||||
created_at: timestamp;
|
||||
// constraint: unique(survey_id, user_id)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## notes
|
||||
|
||||
- all ids are uris internally for activitypub readiness. display layer strips domain until federation flips.
|
||||
- no counters stored anywhere. counts derived from queries.
|
||||
- event reactions surfaced to post author only. no public counts on bulletin board.
|
||||
- background job handles: story expiry, story_witness expiry, event post archiving.
|
||||
```
|
||||
5
docs/DESIGN.md
Normal file
5
docs/DESIGN.md
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
# DESIGN.md — eutopic
|
||||
|
||||
*to be drafted. captures interaction model, UI surfaces, and UX decisions.*
|
||||
|
||||
scope: what the user experiences and why. not what gets stored (see DATA-MODEL.md).
|
||||
47
docs/OPEN-QUESTIONS.md
Normal file
47
docs/OPEN-QUESTIONS.md
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
# OPEN-QUESTIONS.md — eutopic
|
||||
|
||||
decision log. open = not yet decided. closed = locked, with resolution noted.
|
||||
|
||||
---
|
||||
|
||||
## open
|
||||
|
||||
priority 0:
|
||||
- exact reaction palette (design collab pending)
|
||||
- branding + visual identity (design collab pending)
|
||||
- RSVP interaction model (deferred, not designed yet)
|
||||
- email notification format/timing for RSVPs (deferred)
|
||||
- PWA — day one alongside native, or v1.5?
|
||||
- DMs — websockets/simple in-app vs matrix vs no DMs ever. decide before v2 launch.
|
||||
- social handle platform list expansion (signal + telegram primaries. custom covers edge cases. expand tbd.)
|
||||
- server/media migration path — which host migration is least painful for media storage (filesystem → s3-compatible). greenhost/hetzner candidates.
|
||||
|
||||
- which njalla plan tier?
|
||||
- comment hearts/likes — do comments get a heart reaction? tension with "no hierarchy" value. deferred.
|
||||
- event tags — max count per event. starting point: 2 (survey community on this).
|
||||
|
||||
---
|
||||
|
||||
## closed
|
||||
|
||||
- ~~no push notifications ever~~ → v1: none. v2: DM notifications only if DMs land. never for feed activity.
|
||||
- ~~federation UI~~ → locked off. activitypub via fedify active in stack, flag OFF. UI stays invisible always.
|
||||
- ~~reaction model~~ → poster defines up to 5 emoji as their reaction set. open emoji picker always available as fallback. reactions stored as user + post + emoji + timestamp (not counters).
|
||||
- ~~bulletin board as separate entity~~ → `is_event` flag on regular posts. event fields: `event_date`, `event_location`, `event_ends_at`. auto-archives 1 day after `event_ends_at`.
|
||||
- ~~event reactions visibility~~ → visible to post author only. no public counts on bulletin board. no class hierarchy.
|
||||
- ~~who can post to bulletin board~~ → anyone. filters/subpages handle noise.
|
||||
- ~~save/bookmark~~ → optional, toggled by poster at compose time. default off for personal posts.
|
||||
- ~~story interaction model~~ → no replies. "witnessed" metadata: private, per-viewer row in story_witness table, expires with story (24h). story author can view flat witness list (like ig). no public count.
|
||||
- ~~comments~~ → flat, chronological, on posts only. not on stories.
|
||||
- ~~DMs in v1~~ → not shipping. replaced by `display_social_handle` user flag. may become vestigial if DMs land in v2.
|
||||
- ~~social handle as boolean~~ → `display_social_handle: none | mutuals | all`. single field, three states.
|
||||
- ~~social handle structure~~ → array of `{ platform, handle, label?, active }`. one entry per platform. `label` only used for custom platform. `active` hides without deleting. plus free text `contact_prefs` ("bad texter", "weekends only" etc).
|
||||
- ~~third-party auth / handle linking~~ → rejected. store strings, display them, done.
|
||||
- ~~social handle onboarding~~ → opt-in during onboarding. if skipped: "re-enable at any time in settings."
|
||||
- ~~bulletin board layout~~ → 2-column grid (`FlatList numColumns={2}`), infinite scroll, paginated fetch.
|
||||
- ~~survey creator~~ → admin only (you). `is_admin` flag on user record, used only for this.
|
||||
- ~~survey format~~ → multiple choice only. separate `/feedback` subpage always has free text field.
|
||||
- ~~survey visibility~~ → dev use only. no results shown to users, no public engagement metrics.
|
||||
- ~~survey feature~~ → v1, non-negotiable. community sees product is actively iterated on their feedback.
|
||||
- ~~survey delivery~~ → slot 1 in feed as injected card (not a real post). GIF cover image. tapping routes to `/feedback` where active survey renders above permanent free text field. card drops from slot 1 per-user once they've responded (checks `survey_response` on feed load). no modal.
|
||||
- ~~survey expiry~~ → ephemeral, 36h.
|
||||
38
docs/ROADMAP.md
Normal file
38
docs/ROADMAP.md
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
# ROADMAP.md — eutopic
|
||||
|
||||
rough versioned plan. not a project management doc. no dates.
|
||||
|
||||
---
|
||||
|
||||
## now (v0 — alpha)
|
||||
- backend skeleton: auth, users, posts, follows
|
||||
- mobile skeleton: auth flow, feed view, post creation
|
||||
- single-user testing on dev machine
|
||||
- DIY animation prototypes from design friends
|
||||
- create ARCHITECTURE.md before this ships
|
||||
|
||||
## next (v1 — friends launch)
|
||||
- feed + stories + reactions
|
||||
- background + resumable upload via tus.io
|
||||
- onboarding via invite link
|
||||
- bulletin board (`is_event` posts)
|
||||
- liberapay donation page
|
||||
- njalla deployment with systemd
|
||||
|
||||
## soon (v1.5)
|
||||
- F-Droid release
|
||||
- PWA fallback for iOS users avoiding app store
|
||||
- mobilepay via stripe if community needs it
|
||||
|
||||
## later (v2 — after v1 stable 3+ months)
|
||||
- DMs (option undecided — see OPEN-QUESTIONS.md)
|
||||
- notifications for DMs only if DMs land (never feed activity)
|
||||
- consider flipping federation flag
|
||||
|
||||
## eventually (v3+)
|
||||
- video posts
|
||||
- federation truly enabled (UI stays invisible)
|
||||
- whatever the community actually asks for
|
||||
|
||||
## dropped
|
||||
- (nothing dropped yet)
|
||||
Loading…
Reference in a new issue