1783 lines
44 KiB
Markdown
1783 lines
44 KiB
Markdown
# 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:
|
|
|
|
```text
|
|
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:
|
|
|
|
```text
|
|
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:
|
|
|
|
```text
|
|
.
|
|
├── 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:
|
|
|
|
```bash
|
|
# 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:
|
|
|
|
```text
|
|
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:
|
|
|
|
```text
|
|
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:
|
|
|
|
```text
|
|
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:
|
|
|
|
```text
|
|
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:
|
|
|
|
```text
|
|
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:
|
|
|
|
```text
|
|
GET /.well-known/group-platform.json
|
|
GET /api/sync?since=<cursor>
|
|
```
|
|
|
|
The manifest should contain:
|
|
|
|
```json
|
|
{
|
|
"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:
|
|
|
|
```json
|
|
{
|
|
"cursor": "next_cursor",
|
|
"actions": [],
|
|
"events": [],
|
|
"announcements": [],
|
|
"files": [],
|
|
"threads": []
|
|
}
|
|
```
|
|
|
|
### 13. Responsive UI
|
|
|
|
Build a polished mobile-first UI.
|
|
|
|
Required navigation:
|
|
|
|
```text
|
|
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:
|
|
|
|
```text
|
|
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:
|
|
|
|
```text
|
|
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:
|
|
|
|
```text
|
|
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:
|
|
|
|
```text
|
|
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:
|
|
|
|
```text
|
|
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:
|
|
|
|
```text
|
|
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:
|
|
|
|
```text
|
|
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:
|
|
|
|
```text
|
|
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:
|
|
|
|
```text
|
|
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:
|
|
|
|
```text
|
|
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:
|
|
|
|
```text
|
|
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:
|
|
|
|
```text
|
|
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:
|
|
|
|
```text
|
|
Important now
|
|
Upcoming
|
|
Open actions
|
|
Announcements
|
|
Files
|
|
Discussions
|
|
Members/Admin tools
|
|
```
|
|
|
|
Example for sports team:
|
|
|
|
```text
|
|
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:
|
|
|
|
```text
|
|
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:
|
|
|
|
```text
|
|
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:
|
|
|
|
```text
|
|
31 invited
|
|
24 opened
|
|
21 joined
|
|
14 enabled notifications
|
|
4 verified recovery
|
|
7 not reached
|
|
```
|
|
|
|
Generate reminder copy, for example:
|
|
|
|
```text
|
|
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:
|
|
|
|
```text
|
|
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.
|
|
|
|
```text
|
|
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
|
|
|
|
```text
|
|
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
|
|
|
|
```text
|
|
id: UUID
|
|
primary_display_name: string
|
|
created_at: datetime
|
|
updated_at: datetime
|
|
last_seen_at: datetime nullable
|
|
status: active/disabled
|
|
```
|
|
|
|
### HomeDevice
|
|
|
|
```text
|
|
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
|
|
|
|
```text
|
|
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
|
|
|
|
```text
|
|
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
|
|
|
|
```text
|
|
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
|
|
|
|
```text
|
|
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
|
|
|
|
```text
|
|
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
|
|
|
|
```text
|
|
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
|
|
|
|
```text
|
|
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
|
|
|
|
```text
|
|
id: UUID
|
|
event_id: UUID
|
|
member_id: UUID
|
|
status: yes/no/maybe/unknown
|
|
note: text nullable
|
|
updated_at: datetime
|
|
```
|
|
|
|
### Task
|
|
|
|
```text
|
|
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
|
|
|
|
```text
|
|
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
|
|
|
|
```text
|
|
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
|
|
|
|
```text
|
|
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
|
|
|
|
```text
|
|
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
|
|
|
|
```text
|
|
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
|
|
|
|
```text
|
|
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:
|
|
|
|
```json
|
|
{
|
|
"error": {
|
|
"code": "permission_denied",
|
|
"message": "You do not have permission to do that.",
|
|
"details": {}
|
|
}
|
|
}
|
|
```
|
|
|
|
### Invite preview
|
|
|
|
```http
|
|
GET /api/join/{token}/preview
|
|
```
|
|
|
|
Response:
|
|
|
|
```json
|
|
{
|
|
"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
|
|
|
|
```http
|
|
POST /api/auth/invite/{token}/claim
|
|
```
|
|
|
|
Body:
|
|
|
|
```json
|
|
{
|
|
"display_name": "Anna Müller",
|
|
"device_label": "iPhone Safari"
|
|
}
|
|
```
|
|
|
|
Response sets session cookie and returns:
|
|
|
|
```json
|
|
{
|
|
"member": {},
|
|
"group": {},
|
|
"next_steps": ["save_access", "enable_notifications"]
|
|
}
|
|
```
|
|
|
|
### Home dashboard
|
|
|
|
```http
|
|
GET /api/home
|
|
```
|
|
|
|
Response:
|
|
|
|
```json
|
|
{
|
|
"profile": {},
|
|
"sections": {
|
|
"needs_me": [],
|
|
"today": [],
|
|
"changed": [],
|
|
"official_updates": [],
|
|
"catch_up": []
|
|
},
|
|
"connections": []
|
|
}
|
|
```
|
|
|
|
### Sync endpoint
|
|
|
|
```http
|
|
GET /api/sync?since=cursor
|
|
Authorization: Bearer <scoped-token>
|
|
```
|
|
|
|
Response:
|
|
|
|
```json
|
|
{
|
|
"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 `open` → `task_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:
|
|
|
|
```python
|
|
require_role(member, group, min_role="admin")
|
|
can(member, action, resource)
|
|
```
|
|
|
|
Role hierarchy:
|
|
|
|
```text
|
|
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:
|
|
|
|
```text
|
|
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.
|