Files
comiaunicaty/codex_group_platform_instruction.md

44 KiB

FILE: README_USE_WITH_CODEX.md

How to use this package with Codex

This package contains a Codex-ready build brief for a browser-first group coordination platform.

Recommended use:

  1. Create an empty Git repository.
  2. Copy AGENTS.md, CODEX_TASK.md, PRODUCT_SPEC.md, ARCHITECTURE_CONTRACTS.md, and ACCEPTANCE_TESTS.md into the repository root.
  3. Open the repo in Codex.
  4. Ask Codex:
Read AGENTS.md and CODEX_TASK.md. Implement the full product described in PRODUCT_SPEC.md, ARCHITECTURE_CONTRACTS.md, and ACCEPTANCE_TESTS.md. Build a runnable monorepo. Do not stop at a prototype shell; deliver working vertical slices first, then deepen features until the acceptance tests pass.

Alternative: paste the contents of CODEX_TASK.md directly into Codex after adding the other files to the repo.

The intended result is a monorepo with:

backend/   FastAPI app, DB models, API routes, seed data, tests
frontend/  React/Vite app, mobile-first UI, client API layer, tests
docker-compose.yml
README.md

The project deliberately excludes full federation, native apps, unofficial WhatsApp bridges, and production-grade end-to-end encryption. It includes local/self-hosted servers, a home-server model, and cross-server aggregation through scoped server connections.


FILE: AGENTS.md

AGENTS.md

Project mission

Build a browser-first group coordination platform that lowers dependence on WhatsApp-style group chats by giving organizations and members a better structured alternative: events, announcements, files, member management, tasks, polls, commitments, catch-up, and cross-group aggregation.

The product is not a universal chat bridge. It is an exit ramp for groups. WhatsApp or other messengers may be represented only through manual migration aids, imports, digests, and invite/reminder copy.

Required stack

Use this stack unless the existing repository already has a strong conflicting convention:

  • Backend: Python, FastAPI, Pydantic, SQLAlchemy, SQLite by default, optional PostgreSQL configuration.
  • Frontend: React, Vite, TypeScript.
  • Styling: mobile-first responsive UI. Prefer Tailwind CSS or a clean CSS-variable design system if Tailwind setup becomes a distraction.
  • Tests: pytest for backend; Vitest/React Testing Library for frontend where practical.
  • Packaging: Docker Compose for local development.

Implementation behavior

  • If the repository is empty, scaffold a complete monorepo.
  • Prefer a fully runnable vertical slice over many nonfunctional placeholders.
  • Do not ask product questions unless absolutely blocked. Make reasonable choices and document them.
  • Do not stop at mock screens. Implement working backend-backed flows for the core use cases.
  • Keep the browser-first/accountless join flow working at all times.
  • Make security-conscious defaults: invite token hashes, HttpOnly cookies for sessions, no long-lived auth secrets in localStorage, scoped permissions, CORS allowlists, role checks.
  • When production-grade implementation is too large for one pass, create a clean adapter/interface and a working development implementation. Mark the gap clearly in code and README.
  • Run formatting/tests/builds where possible before finishing.

Non-goals

Do not implement:

  • Full server-to-server federation.
  • A native mobile app.
  • Unofficial WhatsApp, Signal, iMessage, Facebook, or WeChat scraping/bridging.
  • Social feed mechanics unrelated to group coordination.
  • Password-first sign-up.
  • Mandatory login before a user can open an invite and complete the first useful action.
  • Production E2EE unless specifically requested in a later task.

Product principles

  1. The group, not the individual account, is the migration unit.
  2. Account creation must be separate from membership identity.
  3. The first useful action must happen before registration friction.
  4. Chat is present but demoted. Structured objects are first-class.
  5. The home screen answers: “What needs my attention?”
  6. Users with multiple groups need aggregation, not just another inbox.
  7. Self-hosting must be possible without forcing full federation.
  8. Portability and export are part of the product promise.

UX principles

  • Mobile-first. The first session likely starts from a link in a phone messenger.
  • The UI should feel more like a group command center than a chat clone.
  • Top-level navigation should prioritize: Home, Calendar, Groups, Files, Me.
  • Chat should live inside groups and threads, not as the primary navigation item.
  • Separate “official” from “chatter.”
  • Use clear empty states, skeletons, and friendly recovery paths.
  • Avoid jargon such as OAuth, WebAuthn, passkey, token, federation in user-facing copy unless necessary.

Coding conventions

  • Use clear module boundaries: auth, groups, structured objects, aggregation, remote servers, files, notifications.
  • Use UUID primary identifiers externally. Internal numeric IDs are acceptable only if not exposed casually.
  • Validate all API inputs with Pydantic schemas.
  • Never store raw invite tokens. Store token hashes.
  • Use environment-driven configuration.
  • Include seed data for demonstration.
  • Include a README with setup, architecture, and known limitations.

FILE: CODEX_TASK.md

CODEX_TASK.md

You are Codex. Build this project from scratch as a runnable monorepo.

Goal

Implement a browser-first, mobile-first group coordination platform that helps groups migrate away from WhatsApp-style chaotic chats by replacing the stream with structured coordination: events, announcements, files, member management, tasks, polls, commitments, catch-up, notification preferences, and cross-group aggregation.

The product must support:

  • Accountless invite-link joining.
  • Later device recovery through email, passkey-compatible architecture, QR/device linking, or admin resend.
  • A home-server concept: each user can have a home profile on a home server that stores their group memberships and remote server connection config.
  • Multiple self-hosted servers without full federation.
  • Aggregation across servers through scoped remote connections.
  • A responsive React/Vite UI optimized for phone browsers first.
  • A FastAPI backend that can run as both a home server and a group server.

Do not implement full federation. Do not implement native apps. Do not implement unofficial messenger bridges.

Deliverables

Create a repository with this shape:

.
├── backend/
│   ├── app/
│   │   ├── main.py
│   │   ├── core/
│   │   ├── db/
│   │   ├── models/
│   │   ├── schemas/
│   │   ├── routers/
│   │   ├── services/
│   │   └── tests/
│   ├── pyproject.toml
│   └── README.md
├── frontend/
│   ├── src/
│   │   ├── app/
│   │   ├── components/
│   │   ├── features/
│   │   ├── routes/
│   │   ├── api/
│   │   ├── styles/
│   │   └── test/
│   ├── package.json
│   └── README.md
├── docker-compose.yml
├── .env.example
├── README.md
└── AGENTS.md

Use a different clean structure only if there is a strong technical reason. Document the reason.

Development commands

Implement commands equivalent to:

# from repo root
docker compose up --build

# backend only
cd backend
python -m app.db.seed
pytest
uvicorn app.main:app --reload

# frontend only
cd frontend
npm install
npm run dev
npm run test
npm run build

Prefer modern package tooling, but do not let tooling block the implementation.

Core product behavior

1. Accountless join flow

A group admin can create a group and generate invite links.

A recipient opens an invite link in a browser and can immediately:

  • see the group name, purpose, and limited preview;
  • join with a display name;
  • read official announcements;
  • see upcoming events;
  • RSVP to an event;
  • participate in chat/comments if permissions allow;
  • choose notification/recovery options later.

Do not require email, password, social login, or native app install before first useful action.

Implement:

  • Invite tokens stored as hashes.
  • One-time or limited-use invite links.
  • Session cookie issued after invite claim.
  • Device record attached to the member.
  • Revocation/reset by admin.

2. Progressive identity

Users start as membership-bound participants. They may later create or attach a home profile.

Implement trust levels:

Guest link         can view public/limited content
Invite member      joined via invite link
Claimed browser    browser session/device is attached
Verified contact   email verified for recovery/notifications
Passkey-ready      model/API/UI support for passkey registration/login
Full home profile  aggregates multiple memberships and servers

If full WebAuthn/passkey implementation is feasible in the pass, implement it. Otherwise create clean backend routes, frontend UI, and a pluggable PasskeyProvider interface with a development provider. The rest of the product must not depend on passkeys working in production mode.

User-facing copy should say “Save access on this device” or “Protect access,” not “Create account” as the first step.

3. Multi-device access

Implement at least two working paths:

  1. Recovery link by email in development mode. If SMTP is not configured, log the link/code to the backend console and show a dev hint in the UI.
  2. Link another device via QR/code pairing:
    • new device starts pairing and receives a code;
    • existing device approves the pending code;
    • new device completes pairing and receives a session;
    • the device list shows both devices;
    • user/admin can revoke a device.

Model the architecture so passkey sign-in can be added cleanly.

4. Structured group objects

Implement these first-class objects:

  • Announcements
  • Events
  • RSVPs
  • Tasks
  • Polls
  • Files
  • Threads/messages
  • Members
  • Devices
  • Notification preferences
  • Commitments/action items
  • Migration status

Chat exists, but it is not the product center. Structured cards should appear in the group dashboard and home dashboard.

5. Home dashboard for multi-group users

The home page must answer “What needs my attention?” across all groups and connected servers.

Implement sections:

Needs me
Today / Upcoming
Changed since last visit
Official updates
Catch up

Action item examples:

  • missing RSVP;
  • task assigned to me;
  • poll I have not answered;
  • event changed;
  • file requiring acknowledgement;
  • direct mention or admin question.

The dashboard should group by urgency and consequence, not only chronology.

6. Group dashboard

The group page must not default to a raw chat feed.

Implement a group dashboard with:

Important now
Upcoming events
Open actions
Official announcements
Files
Active discussions
Members / admin tools depending on role

Chat or discussion threads can be one tab/section, but not the first or only concept.

7. Calendar

Implement a cross-group calendar view:

  • all events from local memberships;
  • events from connected remote servers after sync;
  • RSVP status;
  • event location;
  • attached files;
  • changed-event indicators;
  • simple list view optimized for mobile.

Calendar export can be a later enhancement. Add TODO or stub if not implemented.

8. Files

Implement file metadata and upload/download for local groups.

Minimum:

  • upload file to local storage in dev mode;
  • show file list by group and globally;
  • role/permission checks;
  • file attached to event/announcement when useful;
  • safe filenames and size limits.

9. Migration kit

Implement practical migration features:

  • admin-created invite link/QR-ready URL;
  • member migration status: invited, opened, joined, verified, notification-enabled;
  • WhatsApp reminder copy generator;
  • “legacy channel” status flag;
  • optional WhatsApp chat export importer for .txt export files, stored as an archive, not as live bridged chat.

The app must never require or use WhatsApp APIs.

10. Notification preferences

Implement data model and UI for notification preferences:

Immediate:
- direct mentions
- event changes
- urgent admin announcements
- tasks assigned to me

Quiet / digest:
- discussions
- new files
- photos/general chatter

Mute:
- reactions/off-topic messages

Backend should store preferences. Implement in-app notification behavior and email dev-mode notifications/digests if feasible. Web push can be a future adapter if not implemented.

11. Home server and self-hosted aggregation

Every server instance can act as:

  • a group server: owns canonical groups and their data;
  • a home server: stores a user's home profile and remote server connection config;
  • both.

A user belongs to a home server. The home server stores config for remote servers.

Implement these concepts:

HomeProfile
RemoteServerConnection
RemoteMembership
RemoteSyncCursor
RemoteCapability
RemoteActionItem cache

A remote group server exposes a structured sync API. A home server connects to it with a scoped token and aggregates structured objects.

Important: this is not federation. Servers do not replicate groups peer-to-peer. A home server simply acts as a client to the remote servers selected by the user.

Implement a minimal remote connection flow:

  1. Remote server exposes /.well-known/group-platform.json.
  2. Remote server can create a scoped connection token for a member/admin in dev mode.
  3. Home server connects to a remote server using URL + token.
  4. Home server fetches capabilities.
  5. Home server syncs actions/events/announcements/files/threads through /api/sync.
  6. Home dashboard displays both local and remote objects.
  7. Remote objects are marked clearly with their source server/group.

Store sensitive remote tokens server-side, not in browser localStorage. Use localStorage only for non-sensitive hints such as last selected home server URL or UI preferences.

12. Open protocol seed

Expose:

GET /.well-known/group-platform.json
GET /api/sync?since=<cursor>

The manifest should contain:

{
  "server_name": "Example Group Server",
  "api_base": "http://localhost:8000/api",
  "protocol_version": "0.1",
  "capabilities": {
    "events": true,
    "tasks": true,
    "files": true,
    "chat": true,
    "polls": true,
    "federation": false
  }
}

The sync endpoint should return structured objects, not just raw chat messages:

{
  "cursor": "next_cursor",
  "actions": [],
  "events": [],
  "announcements": [],
  "files": [],
  "threads": []
}

13. Responsive UI

Build a polished mobile-first UI.

Required navigation:

Home
Calendar
Groups
Files
Me

Required screens:

  • Join invite screen
  • Home dashboard
  • Calendar
  • Group list
  • Group dashboard
  • Group discussions/chat
  • Group admin / migration dashboard
  • Event detail + RSVP
  • Announcement detail
  • Task detail
  • Poll detail
  • File list and upload
  • Me/profile
  • Devices
  • Notification preferences
  • Connected servers
  • Connect remote server

Design requirements:

  • bottom navigation on mobile;
  • responsive desktop layout with side navigation;
  • cards for action items, events, announcements, files, and discussions;
  • clear “official” vs “discussion” visual distinction;
  • accessible form labels and keyboard behavior;
  • loading and empty states;
  • seed-data demo should look credible immediately.

Use a coherent design system: spacing scale, typography, elevation, badges, status colors, rounded cards, and compact mobile layouts.

14. Seed data

Create seed data that demonstrates the concept:

  • FC Kreuzberg U12 Parents
  • Class 4B Parents
  • Tenant Association
  • Food Bank Volunteers

Include users/members:

  • Anna Müller as the main demo user
  • Coach Mark
  • Lisa Becker
  • Samir Khan
  • Priya N.
  • Tenant admin

Include events:

  • football match with missing RSVP;
  • training location changed;
  • parent evening;
  • tenant vote deadline;
  • volunteer shift.

Include actions:

  • RSVP required;
  • vote required;
  • task assigned;
  • file acknowledgement;
  • direct mention.

Include files:

  • season schedule;
  • emergency contacts;
  • meeting minutes;
  • school form.

Include discussions:

  • snack coordination;
  • carpool planning;
  • maintenance issue;
  • volunteer supplies.

15. API shape

Implement or approximate these endpoints.

Auth/session:

GET    /api/health
GET    /api/me
POST   /api/auth/invite/{token}/claim
GET    /api/join/{token}/preview
POST   /api/auth/recovery/request
POST   /api/auth/recovery/consume
POST   /api/auth/device-link/start
POST   /api/auth/device-link/approve
POST   /api/auth/device-link/complete
GET    /api/me/devices
DELETE /api/me/devices/{device_id}
POST   /api/auth/passkeys/register/options
POST   /api/auth/passkeys/register/verify
POST   /api/auth/passkeys/login/options
POST   /api/auth/passkeys/login/verify

Home/aggregation:

GET    /api/home
GET    /api/home/actions
GET    /api/home/calendar
GET    /api/home/files
GET    /api/home/official-updates
GET    /api/home/catch-up

Groups:

GET    /api/groups
POST   /api/groups
GET    /api/groups/{group_id}
PATCH  /api/groups/{group_id}
POST   /api/groups/{group_id}/invites
GET    /api/groups/{group_id}/members
PATCH  /api/groups/{group_id}/members/{member_id}

Structured objects:

GET    /api/groups/{group_id}/announcements
POST   /api/groups/{group_id}/announcements
GET    /api/groups/{group_id}/events
POST   /api/groups/{group_id}/events
POST   /api/events/{event_id}/rsvp
GET    /api/groups/{group_id}/tasks
POST   /api/groups/{group_id}/tasks
PATCH  /api/tasks/{task_id}
GET    /api/groups/{group_id}/polls
POST   /api/groups/{group_id}/polls
POST   /api/polls/{poll_id}/vote
GET    /api/groups/{group_id}/files
POST   /api/groups/{group_id}/files
GET    /api/files/{file_id}/download
GET    /api/groups/{group_id}/threads
POST   /api/groups/{group_id}/threads
POST   /api/threads/{thread_id}/messages

Migration:

GET    /api/groups/{group_id}/migration
POST   /api/groups/{group_id}/migration/reminder-copy
POST   /api/groups/{group_id}/migration/import-whatsapp-export

Notifications/preferences:

GET    /api/me/notification-preferences
PATCH  /api/me/notification-preferences
GET    /api/me/notifications
PATCH  /api/me/notifications/{notification_id}/read

Remote/self-hosted aggregation:

GET    /.well-known/group-platform.json
GET    /api/sync?since=<cursor>
POST   /api/connection-tokens
GET    /api/remote/servers
POST   /api/remote/servers/connect
POST   /api/remote/servers/{connection_id}/sync
DELETE /api/remote/servers/{connection_id}

16. Data model

Use a practical relational schema. Include at least:

HomeProfile
HomeDevice
RecoveryMethod
Session
Group
Member
MemberDevice
MemberInvite
Announcement
Event
EventRsvp
Task
Poll
PollOption
PollVote
FileAsset
Thread
Message
NotificationPreference
Notification
ActionItem
MigrationState
AuditLog
RemoteServerConnection
RemoteMembership
RemoteSyncCursor
RemoteCachedObject
ConnectionToken

A user can have a HomeProfile, but joining a group must not require one. A Member can exist without a HomeProfile. Later, a Member can attach to a HomeProfile.

17. Permissions

Implement simple roles:

owner
admin
moderator
member
guest

Enforce at least:

  • only admins/owners can create invite links;
  • only admins/owners/moderators can create official announcements;
  • members can RSVP, vote, comment, and complete their tasks;
  • file upload can be configured but default to members;
  • migration dashboard is admin-only;
  • remote connection tokens are scoped.

18. Security requirements

  • Store invite tokens and recovery tokens as hashes.
  • Use HttpOnly, Secure-in-production, SameSite cookies for sessions.
  • Add CSRF protection for cookie-authenticated mutating requests, or document and implement a safe dev alternative.
  • Use server-side storage for remote tokens.
  • Do not place long-lived remote access tokens in localStorage.
  • Validate upload size/type.
  • Sanitize filenames.
  • Add audit logs for admin actions, invite creation, device linking, token creation, remote connection changes.
  • Provide .env.example with secrets and configuration.
  • Make dev mode explicit.

19. README

Create a root README that explains:

  • product concept;
  • what is implemented;
  • quick start;
  • seed accounts/flows;
  • how to join via invite link;
  • how to link another device;
  • how to create a remote connection between two local server instances;
  • architecture overview;
  • security model;
  • limitations and next steps.

20. Quality bar

The final app must be demonstrable without manually editing the database.

At minimum, after setup:

  1. A user can open the frontend.
  2. Seed data appears.
  3. The user can use a demo invite link and join a group without account creation.
  4. The user can RSVP to an event.
  5. The user can see a cross-group action dashboard.
  6. An admin can create an invite and view migration status.
  7. A user can link a second device/session through the pairing flow.
  8. A user can connect a remote self-hosted server with URL + token and sync structured objects.
  9. The UI works well on a phone-sized viewport.
  10. Backend tests cover auth/join, permissions, actions, and remote sync.

Suggested implementation order

  1. Scaffold backend/frontend/docker.
  2. Implement DB models and seed data.
  3. Implement session/auth primitives and invite flow.
  4. Implement groups, members, announcements, events, RSVPs.
  5. Implement home dashboard/action derivation.
  6. Implement group dashboard UI.
  7. Implement files, tasks, polls, threads/messages.
  8. Implement devices/recovery/device linking.
  9. Implement migration dashboard and reminder copy generator.
  10. Implement remote server manifest, connection token, sync endpoint, home aggregation.
  11. Polish UI and responsive behavior.
  12. Add tests and README.

If time is limited, prioritize vertical completeness in this order:

invite join → group dashboard → event RSVP → home actions → admin migration → device linking → remote aggregation

Do not spend all effort on the chat feature. The product is structured coordination.


FILE: PRODUCT_SPEC.md

PRODUCT_SPEC.md

Product name placeholder

Use a neutral working name in code and UI, such as GroupHome. Keep it easy to rename.

Product thesis

Groups remain stuck on WhatsApp-like messengers because switching costs are social, not technical. The product lowers switching costs by making the group itself movable and by making the new home materially better than chat: structured events, files, announcements, member management, tasks, polls, commitments, migration tracking, browser-first access, and no mandatory account on first use.

The product must not become a universal inbox. It must become a command center for group life.

Target users

Primary:

  • sports clubs;
  • school and parent groups;
  • tenant associations;
  • volunteer organizations;
  • local campaigns and civic groups;
  • small professional or nonprofit communities.

Secondary:

  • members who belong to several groups and need a unified action view;
  • admins who want to leave WhatsApp without excluding people.

Positioning

For organizations:

Run your group professionally without forcing members onto WhatsApp.

For members:

See what matters across all your groups without reading every chat.

For admins:

Announcements, events, files, RSVPs, and members in one place.

For anti-lock-in positioning:

Your group should not depend on one company's messenger.

Required product flows

Flow A: Admin creates a group and starts migration

  1. Admin opens app.
  2. Admin creates group with name, description, visibility, and default permissions.
  3. Admin adds seed members manually or imports a simple CSV.
  4. Admin creates invite link.
  5. Admin gets QR-ready URL and WhatsApp reminder copy.
  6. Migration dashboard tracks invited/opened/joined/verified/notification-enabled.
  7. Admin can mark the WhatsApp channel as legacy and set a transition deadline.

Flow B: Member joins without login

  1. Member taps invite link from WhatsApp/email/SMS/QR.
  2. Browser opens join screen.
  3. Member sees group preview and official reason for moving.
  4. Member enters/accepts display name.
  5. Member is assigned a browser session/device.
  6. Member can immediately read official updates and perform one useful action, such as RSVP.
  7. Member is then nudged to save access via recovery email, passkey-ready protection, or browser notifications.

Flow C: Multi-group home

  1. Anna belongs to FC Kreuzberg U12, Class 4B Parents, Tenant Association, and Food Bank Volunteers.
  2. Anna opens Home.
  3. Home shows:
    • missing RSVPs;
    • open votes;
    • tasks assigned to Anna;
    • changed events;
    • important announcements;
    • catch-up summary of chatter.
  4. Anna does not need to open every group chat.

Flow D: Multi-device access

  1. Anna joined on phone.
  2. On PC, Anna opens the app and chooses “Link from existing device.”
  3. PC displays code/QR.
  4. Phone approves the pending device.
  5. PC receives a session.
  6. Anna sees both devices in Me → Devices.
  7. Anna can revoke a device.

Flow E: Self-hosted remote aggregation

  1. Club runs club.example as a group server.
  2. Anna's home server is home.example or the hosted default.
  3. Club server creates a scoped connection token for Anna.
  4. Anna connects club.example to her home server.
  5. Home server syncs structured objects through /api/sync.
  6. Anna's Home dashboard shows club actions alongside other groups.
  7. No group data is replicated peer-to-peer between unrelated servers.

Top-level navigation

Use these nav items:

Home
Calendar
Groups
Files
Me

Chat must not be top-level navigation.

Home screen details

The Home screen must include the following cards/sections:

Needs me

High priority, actionable objects:

  • RSVP required;
  • vote required;
  • task assigned;
  • file requires acknowledgement;
  • direct mention;
  • admin request.

Each card must show:

  • group name;
  • type badge;
  • due date/time if any;
  • primary action button;
  • source server when remote.

Today / Upcoming

Unified agenda with:

  • events;
  • deadlines;
  • changed locations/times;
  • RSVP status;
  • attached file indicators.

Changed since last visit

Examples:

  • event changed;
  • new official announcement;
  • task reassigned;
  • poll result finalized;
  • file uploaded.

Official updates

Announcements and admin posts, separated from discussion chatter.

Catch up

Rule-based summary in MVP:

While you were away:
- 2 official announcements
- 1 event changed
- 3 open actions
- 47 discussion messages

Do not require AI to implement catch-up. AI hooks can be future work.

Group page details

Default group dashboard sections:

Important now
Upcoming
Open actions
Announcements
Files
Discussions
Members/Admin tools

Example for sports team:

FC Kreuzberg U12 Parents
- Match Saturday, RSVP open
- Training moved to Pitch 2
- 3 drivers still needed
- Files: Season schedule, Emergency contacts
- Discussions: Snacks, Carpool

Composer behavior

When creating group content, allow explicit content types:

Announcement
Event
Task
Poll
Question/thread
File
Chat message

MVP can implement simple forms for each type. Later AI can suggest structure from natural language; do not block MVP on that.

Notifications

Implement preferences by type, not only by group.

User settings:

Immediate
- direct mentions
- event changes
- urgent announcements
- tasks assigned to me

Digest
- normal discussions
- new files
- photos/general chatter

Muted
- reactions
- off-topic chatter

UI must make the pitch clear:

Mute the noise, not the group.

Search and files

At MVP level:

  • global file list;
  • by-group filter;
  • simple text search over names/descriptions;
  • upload/download local files;
  • show source server for remote files.

Later enhancements can include full-text search across messages.

Migration kit details

Admin dashboard should show:

31 invited
24 opened
21 joined
14 enabled notifications
4 verified recovery
7 not reached

Generate reminder copy, for example:

23 of 31 people have joined our new group space.
The match schedule, RSVP, and files are now here: {link}
From {date}, official announcements will only be posted there.

WhatsApp export import:

  • accept .txt export;
  • parse basic lines if format is recognized;
  • store as archive items;
  • do not treat imported messages as active verified members;
  • make archive clearly read-only.

Self-hosting and aggregation

Definitions:

  • Group server: canonical owner of one or more groups.
  • Home server: stores a user's personal dashboard config and remote server connections.
  • Remote server connection: scoped link from a home server to a group server.
  • Federation: server-to-server peer network. Explicitly not included.

V2 self-hosting target:

  • A server can be self-hosted by an organization.
  • A user can connect multiple servers to their home profile.
  • A home server aggregates structured objects.
  • Servers expose an open, documented, versioned sync API.
  • Users can export their data/config.

Copy guidelines

Avoid words that create friction:

  • Avoid “register” as first action.
  • Avoid “create account” before value.
  • Avoid “federation” in end-user UI.
  • Avoid “token” in end-user UI.

Use:

  • “Open group”
  • “Join this group”
  • “Save access”
  • “Protect access”
  • “Link another device”
  • “Connect another group server”
  • “Get updates without WhatsApp”

What not to build

  • Do not put chat as the whole product.
  • Do not require the native app.
  • Do not bridge or scrape WhatsApp.
  • Do not make localStorage the source of identity.
  • Do not force all self-hosted servers into one federation.
  • Do not hide important state in chronological messages.

FILE: ARCHITECTURE_CONTRACTS.md

ARCHITECTURE_CONTRACTS.md

Architecture overview

The same FastAPI server can operate as:

local group server
home server
both

The React frontend talks primarily to one selected home server. The home server stores local memberships and remote server connection configuration. It aggregates structured objects from connected remote group servers.

Browser/PWA
   |
   | HTTPS/API + HttpOnly session cookie
   v
Home Server
   | owns home profile, devices, preferences, remote config
   | fetches remote structured sync using scoped server-side tokens
   v
Remote Group Servers
   | own canonical groups and group data
   | expose /.well-known/group-platform.json and /api/sync

No server-to-server federation is required. Remote group servers do not know about each other.

Browser storage policy

Allowed in localStorage:

  • last selected home server URL;
  • UI preferences;
  • theme choice;
  • non-sensitive onboarding flags;
  • cached non-sensitive IDs for convenience.

Not allowed in localStorage:

  • raw invite tokens after claim;
  • session tokens;
  • remote server access tokens;
  • recovery tokens;
  • admin credentials.

Use HttpOnly cookies for sessions. Use server-side storage for remote connection credentials.

Core entity relationships

HomeProfile 1..n HomeDevice
HomeProfile 1..n RecoveryMethod
HomeProfile 1..n RemoteServerConnection
HomeProfile 0..n Member via Member.home_profile_id

Group 1..n Member
Group 1..n MemberInvite
Group 1..n Announcement
Group 1..n Event
Event 1..n EventRsvp
Group 1..n Task
Group 1..n Poll
Poll 1..n PollOption
PollOption 1..n PollVote
Group 1..n FileAsset
Group 1..n Thread
Thread 1..n Message

Member 1..n MemberDevice
Member 1..n ActionItem
Member 1..n Notification

RemoteServerConnection 1..n RemoteMembership
RemoteServerConnection 1..n RemoteSyncCursor
RemoteServerConnection 1..n RemoteCachedObject

A Member can exist without a HomeProfile. This is required for accountless invite-link joining. Later, a member may be attached to a home profile.

Suggested SQLAlchemy fields

Use exact names where practical.

HomeProfile

id: UUID
primary_display_name: string
created_at: datetime
updated_at: datetime
last_seen_at: datetime nullable
status: active/disabled

HomeDevice

id: UUID
home_profile_id: UUID nullable
member_id: UUID nullable
label: string
user_agent_summary: string
created_at: datetime
last_seen_at: datetime
revoked_at: datetime nullable
trust_level: invite_member/claimed_browser/verified/passkey_ready

RecoveryMethod

id: UUID
home_profile_id: UUID
kind: email/phone/recovery_code/passkey
value_hash: string nullable
display_hint: string
verified_at: datetime nullable
created_at: datetime

Session

id: UUID
home_profile_id: UUID nullable
member_id: UUID nullable
home_device_id: UUID nullable
member_device_id: UUID nullable
csrf_token_hash: string
expires_at: datetime
created_at: datetime
revoked_at: datetime nullable

Group

id: UUID
server_origin: string
name: string
description: text
visibility: private/public/listed
legacy_channel_status: none/transition/legacy
transition_deadline: date nullable
created_at: datetime
updated_at: datetime
archived_at: datetime nullable

Member

id: UUID
group_id: UUID
home_profile_id: UUID nullable
display_name: string
role: owner/admin/moderator/member/guest
status: invited/opened/joined/verified/suspended/left
joined_at: datetime nullable
last_seen_at: datetime nullable
notification_enabled_at: datetime nullable

MemberInvite

id: UUID
group_id: UUID
member_id: UUID nullable
created_by_member_id: UUID
label: string
scope: specific_member/open_seat/admin_invite
permission_role: guest/member/admin
plain_token_display_once: not persisted
token_hash: string
expires_at: datetime nullable
max_uses: int
use_count: int
consumed_at: datetime nullable
revoked_at: datetime nullable
created_at: datetime

Announcement

id: UUID
group_id: UUID
author_member_id: UUID
title: string
body: text
priority: normal/urgent
official: bool
requires_ack: bool
created_at: datetime
updated_at: datetime

Event

id: UUID
group_id: UUID
created_by_member_id: UUID
title: string
description: text nullable
starts_at: datetime
ends_at: datetime nullable
location_name: string nullable
location_address: string nullable
rsvp_required: bool
changed_at: datetime nullable
created_at: datetime
updated_at: datetime

EventRsvp

id: UUID
event_id: UUID
member_id: UUID
status: yes/no/maybe/unknown
note: text nullable
updated_at: datetime

Task

id: UUID
group_id: UUID
created_by_member_id: UUID
assigned_to_member_id: UUID nullable
title: string
description: text nullable
due_at: datetime nullable
status: open/done/cancelled
created_at: datetime
updated_at: datetime

Poll / PollOption / PollVote

Poll: id, group_id, title, description, closes_at, status, created_by_member_id, created_at
PollOption: id, poll_id, label, position
PollVote: id, poll_id, option_id, member_id, created_at

FileAsset

id: UUID
group_id: UUID
uploaded_by_member_id: UUID
filename_original: string
filename_stored: string
content_type: string
size_bytes: int
storage_path: string
visibility: members/admins/public_link
created_at: datetime

Thread / Message

Thread: id, group_id, title, kind discussion/question/archive, created_by_member_id, created_at, updated_at
Message: id, thread_id, author_member_id, body, created_at, edited_at nullable, deleted_at nullable

ActionItem

id: UUID
home_profile_id: UUID nullable
member_id: UUID nullable
remote_connection_id: UUID nullable
source_type: local/remote
source_server_origin: string
source_group_id: string
source_group_name: string
type: rsvp_required/vote_required/task_assigned/event_changed/file_ack/direct_mention/admin_request
status: open/done/dismissed
priority: low/normal/high/urgent
title: string
summary: text
object_type: event/task/poll/file/announcement/message
object_id: string
due_at: datetime nullable
created_at: datetime
updated_at: datetime

RemoteServerConnection

id: UUID
home_profile_id: UUID
server_origin: string
server_name: string
api_base: string
protocol_version: string
capabilities_json: json
access_token_encrypted: string
status: active/error/revoked
last_sync_at: datetime nullable
last_error: text nullable
created_at: datetime
updated_at: datetime

RemoteCachedObject

id: UUID
remote_connection_id: UUID
object_type: action/event/announcement/file/thread
remote_id: string
group_remote_id: string
group_name: string
payload_json: json
updated_at_remote: datetime nullable
cached_at: datetime

API contracts

Use JSON. Use ISO 8601 datetimes. Use consistent error response:

{
  "error": {
    "code": "permission_denied",
    "message": "You do not have permission to do that.",
    "details": {}
  }
}

Invite preview

GET /api/join/{token}/preview

Response:

{
  "group": {
    "id": "...",
    "name": "FC Kreuzberg U12 Parents",
    "description": "Planning, matches, files, and announcements."
  },
  "invite": {
    "label": "Parent invite",
    "expires_at": null,
    "role": "member"
  },
  "preview": {
    "announcements": [],
    "events": []
  }
}

Claim invite

POST /api/auth/invite/{token}/claim

Body:

{
  "display_name": "Anna Müller",
  "device_label": "iPhone Safari"
}

Response sets session cookie and returns:

{
  "member": {},
  "group": {},
  "next_steps": ["save_access", "enable_notifications"]
}

Home dashboard

GET /api/home

Response:

{
  "profile": {},
  "sections": {
    "needs_me": [],
    "today": [],
    "changed": [],
    "official_updates": [],
    "catch_up": []
  },
  "connections": []
}

Sync endpoint

GET /api/sync?since=cursor
Authorization: Bearer <scoped-token>

Response:

{
  "cursor": "next-cursor",
  "server_time": "2026-06-29T10:00:00Z",
  "actions": [],
  "events": [],
  "announcements": [],
  "files": [],
  "threads": []
}

Remote aggregation behavior

The home server stores a cursor per remote connection. Sync should be idempotent.

Remote cached objects should include enough payload to render in the Home dashboard without live remote calls every time. When a user performs a write action on a remote object, the MVP can open the remote group page in a new tab if write-through is not implemented. Implement write-through for RSVP if feasible.

Derived action logic

Generate local action items from structured state:

  • Event with rsvp_required=true and no RSVP by current member → rsvp_required.
  • Task assigned to current member and status opentask_assigned.
  • Poll open with no vote by current member → vote_required.
  • Event changed after member's last seen time → event_changed.
  • Announcement requires acknowledgement and no acknowledgement exists → file_ack or future announcement_ack.

It is acceptable to recompute on request in MVP, but persist/cache for remote sync.

Permissions contract

Implement a simple helper:

require_role(member, group, min_role="admin")
can(member, action, resource)

Role hierarchy:

guest < member < moderator < admin < owner

Make role checks visible in route handlers or service methods.

Development remote-server demo

Provide a way to run two local instances:

home server:   http://localhost:8000
remote server: http://localhost:8001

Options:

  • docker-compose service duplication; or
  • README command using different ports and DB paths.

Seed each with distinct server names and groups. Show how to create a remote connection token on server 8001 and connect it from server 8000.

Production limitations to document

Document these limitations in README:

  • Dev email sends to console unless SMTP configured.
  • Passkey implementation may be development/pluggable if not fully implemented.
  • Web push may be a future adapter.
  • No full federation.
  • No end-to-end encryption.
  • Remote sync tokens require secure secret management in production.
  • File storage is local filesystem in dev; production should use S3-compatible storage or mounted volume.

FILE: ACCEPTANCE_TESTS.md

ACCEPTANCE_TESTS.md

Codex should use this file as a checklist. Implement automated tests for as many as practical and document any manual checks.

Smoke tests

  • docker compose up --build starts backend and frontend.
  • Backend health endpoint returns OK.
  • Frontend loads without console-breaking errors.
  • Seed data can be created with a documented command.

Accountless join

Automated/backend:

  • Creating invite stores only token hash.
  • Valid invite preview returns group preview.
  • Claiming invite creates/updates member, member device, and session.
  • Expired/revoked invite cannot be claimed.
  • Limited-use invite increments use count and blocks after max uses.

Manual/frontend:

  • Opening invite link shows a polished mobile join screen.
  • User can join without email/password.
  • User can RSVP immediately after join.

Structured group behavior

Automated/backend:

  • Admin can create announcement.
  • Member cannot create official announcement unless permitted.
  • Admin can create event.
  • Member can RSVP to event.
  • Missing RSVP generates action item.
  • Task assigned to member generates action item.
  • Poll without member vote generates action item.

Manual/frontend:

  • Group page defaults to dashboard, not raw chat.
  • Announcements/events/files/tasks/polls appear as cards.
  • Chat/discussions are available but secondary.

Home dashboard

Automated/backend:

  • /api/home returns sections for needs_me, today, changed, official_updates, catch_up.
  • Action ordering prioritizes urgent/due items.
  • Local and remote objects can be represented consistently.

Manual/frontend:

  • Home answers “What needs me?”
  • Seed demo shows at least three actionable items across groups.
  • Remote items show source server/group badge.

Multi-device

Automated/backend:

  • Device link start creates pending pairing code.
  • Existing session can approve pending device.
  • New device completes pairing and receives session.
  • Device list includes both devices.
  • Revoked device cannot use session.

Manual/frontend:

  • User can start “Link another device.”
  • Code/QR screen is understandable.
  • Existing device approval UI is clear.
  • Device management page shows current and linked devices.

Recovery

Automated/backend:

  • Recovery request creates hashed recovery token/code.
  • Recovery consume creates session or attaches to home profile.
  • Expired/revoked recovery token fails.

Manual/frontend:

  • Dev-mode recovery shows/logs a usable link or code.
  • UI says “Save access”/“Recover access,” not mandatory account creation.

Migration kit

Automated/backend:

  • Admin can fetch migration dashboard.
  • Migration status reflects member invite/open/join/verified fields.
  • Reminder copy endpoint returns useful text with link and transition date.
  • WhatsApp export import accepts a .txt file and stores read-only archive messages if implemented.

Manual/frontend:

  • Admin migration dashboard is clear.
  • Reminder copy is one-click copyable.
  • UI explains legacy channel concept.

Files

Automated/backend:

  • Upload enforces auth and file size.
  • Download enforces permission.
  • Filename is sanitized.

Manual/frontend:

  • Files page shows global and by-group files.
  • File source group/server is visible.

Remote/self-hosted aggregation

Automated/backend:

  • /.well-known/group-platform.json returns manifest.
  • /api/sync requires valid scoped token.
  • Connection token has scopes and expiry.
  • Home server can connect to remote server with URL + token.
  • Sync stores/caches remote structured objects.
  • /api/home includes remote action items after sync.

Manual/frontend:

  • Connected servers page lists remote server.
  • Sync status/errors are visible.
  • Remote actions appear on Home.
  • No UI claims full federation.

Responsive UI

Manual:

  • 375px-wide mobile viewport is usable.
  • Bottom nav appears on mobile.
  • Desktop layout uses more horizontal space without becoming sparse.
  • Forms are readable and touch targets are adequate.
  • Empty/loading/error states are implemented.

Security checklist

Automated or code review:

  • Invite/recovery tokens hashed.
  • Sessions use HttpOnly cookies.
  • Long-lived tokens not stored in localStorage.
  • Role checks on admin endpoints.
  • Remote tokens stored server-side.
  • Upload validation implemented.
  • .env.example exists and no secrets are committed.

README checklist

Root README must include:

  • product concept;
  • architecture diagram/text;
  • setup commands;
  • seed demo instructions;
  • invite flow instructions;
  • device-linking instructions;
  • remote aggregation demo instructions;
  • known limitations;
  • security notes;
  • next-step roadmap.