Collaborative Collections (Saved Homes) - Shared Boards, Comments & Notifications
#94 建立於 2025年10月3日
倉庫指標
- 星標
- (38 顆星)
- PR 合併指標
- (PR 指標待抓取)
描述
Summary
Add “Collections” so users can save homes (by ZPID), group them into shareable boards, discuss with comments, rank/prioritize, and get real-time updates and digests. Works for solo users and small groups (partner/agent). Integrates with Map, Chat, Insights, and Graph (Neo4j) for explainable “why this home is similar” callouts.
Motivation & Goals
-
Problem: Users currently discover properties but have no first-class way to save, organize, or collaborate on them inside EstateWise.
-
Goals:
- Increase repeat usage and session length via saved content.
- Enable collaborative decision-making (notes, comments, statuses).
- Surface explainability via Neo4j edges on a board overview.
-
Success Metrics (30 days post-launch):
- ≥30% of authenticated users create ≥1 collection.
- Avg. homes per collection ≥5.
- ≥25% of collections have ≥1 collaborator.
- ≥15% reduction in time to “top pick” (measured by status changes / rank).
User Stories
-
As a guest, I can create a temporary collection in browser storage and later migrate it after sign-up.
-
As an authenticated user, I can:
- Save a property from Chat, Map, and Property detail via “Save → Choose/New Collection”.
- Organize items with status (Considering / Toured / Offer / Dropped), rank, tags, and notes.
- Share a collection via invite (email link) with roles (Viewer/Commenter/Editor/Owner).
- Comment on items and @mention collaborators.
- See similarity reasons (same ZIP / neighborhood / similar-to) summarized per collection.
- Get in-app notifications for comments/status changes, plus optional weekly digest.
Out of Scope (v1)
- Agent scheduling/integrations (Calendly, etc.)
- Push notifications on mobile (web push can be a follow-up)
- Advanced RBAC beyond Viewer/Commenter/Editor/Owner
UX/IA
New routes
-
/collections(list + create) -
/collections/:id(board view)- Left: board filters (status, tags), “Explain similarities”
- Main: grid/list of cards (thumbnail, price/beds/baths, status, rank, tags, quick actions)
- Right: activity feed (comments, joins, changes), board stats
Entry points
- Map markers / property cards: “Save” button
- Chat replies with ZPIDs: inline action “Save homes (3) to…” + “View on Map”
- Insights: “Add selection to collection”
Components
SaveToCollectionDialogCollectionCard,CollectionItemCardCommentThreadBoardStatsPanel(with Chart.js)SimilarityReasons(Neo4j badges)
Data Model (MongoDB)
// collections
{
_id: ObjectId,
ownerId: ObjectId,
name: string,
description?: string,
visibility: 'private'|'shared', // public later if needed
members: [{ userId: ObjectId, role: 'viewer'|'commenter'|'editor'|'owner' }],
createdAt: Date,
updatedAt: Date
}
// collection_items
{
_id: ObjectId,
collectionId: ObjectId,
zpid: string,
addedBy: ObjectId,
status: 'considering'|'toured'|'offer'|'dropped',
rank?: number, // 1..n (unique per collection)
tags?: string[],
notes?: string,
createdAt: Date,
updatedAt: Date
}
// comments
{
_id: ObjectId,
collectionId: ObjectId,
itemId: ObjectId,
authorId: ObjectId,
text: string,
mentions?: ObjectId[],
createdAt: Date
}
// invites
{
_id: ObjectId,
collectionId: ObjectId,
email: string,
role: 'viewer'|'commenter'|'editor',
token: string, // signed, exp-bound
expiresAt: Date,
acceptedAt?: Date
}
Indexes
collection_items:{ collectionId: 1, rank: 1 },{ collectionId: 1, zpid: 1 },{ addedBy: 1, createdAt: -1 }comments:{ collectionId: 1, itemId: 1, createdAt: -1 }invites:{ collectionId: 1, email: 1 },{ token: 1 } (unique)
REST Endpoints (Express)
POST /api/collections
GET /api/collections // mine + shared-with-me
GET /api/collections/:id
PUT /api/collections/:id
DELETE /api/collections/:id
POST /api/collections/:id/items
GET /api/collections/:id/items
PUT /api/collections/:id/items/:itemId
DELETE /api/collections/:id/items/:itemId
POST /api/collections/:id/comments
GET /api/collections/:id/comments?itemId=...
POST /api/collections/:id/invites
POST /api/collections/invites/accept // body: { token }
DELETE /api/collections/:id/members/:userId
GET /api/collections/:id/similarity // summarize Neo4j reasons for items
GET /api/collections/:id/stats // counts by status, price hist, etc.
tRPC (examples)
collections.create, collections.listMine, collections.get, collections.update, collections.remove
collections.addItem, collections.listItems, collections.updateItem, collections.removeItem
collections.addComment, collections.listComments
collections.invite, collections.acceptInvite, collections.removeMember
collections.similarity, collections.stats
Neo4j Integration
-
For each item’s
zpid, fetch graph context:(:Property {zpid})-[:IN_NEIGHBORHOOD|IN_ZIP|SIMILAR_TO]->(:Property ...)
-
API aggregates per-collection:
- “Top 3 similarity clusters” (neighborhood/zip)
- Count of items connected via
SIMILAR_TO
-
Fallback: if Neo4j disabled, the endpoint returns 503 and UI hides badges gracefully (consistent with current graph behavior).
Realtime & Notifications
-
Realtime: Socket.IO or tRPC WebSockets for:
- new comment, status change, member added
-
In-app notifications: bell icon + unread count, persisted in Mongo.
-
Weekly digest (optional, feature flag): background job (cron/Cloud Run) emails board summary & changes (SendGrid/Postmark).
Security & Privacy
- All endpoints require JWT auth; collection membership enforced server-side.
- Invite tokens are signed, short-lived; role cannot exceed inviter’s role.
- Rate-limit comment creation; HTML-escape text; allow safe Markdown subset.
Performance
- Redis cache for
collections.stats(TTL short, e.g., 60s) and similarity summaries (TTL 5 min). - Batch Neo4j calls per board.
- Paginate items and comments.
Telemetry
- Events:
collection_created,item_added,status_updated,comment_added,member_invited,invite_accepted,similarity_viewed. - Prometheus: counters + latency histograms per endpoint.
Rollout Plan
- Behind feature flag (
FEATURE_COLLECTIONS=true) for staff. - Internal test → limited beta (5–10% of authenticated users) → 100%.
- Backfill/migration: none needed.
- Add “What’s New” toast linking to
/collections.
Acceptance Criteria
- Create/list/get/update/delete collections behind auth.
- Save from Map and Chat adds the right ZPIDs to chosen collection.
- Commenting works with @mentions and realtime updates.
- Sharing via invite link assigns correct role; role enforcement verified.
- Board shows status filters, tags, ranking, and basic stats (counts, price histogram).
- Similarity panel renders when Neo4j is enabled; hidden (no errors) when disabled.
- In-app notifications for comments and status changes.
- E2E tests cover main flows (create, save, share, comment).
Open Questions
- Should guests be able to export a collection to CSV/PDF without sign-up?
- Allow public, read-only link for agents to share externally?
- Do we need per-item attachments (e.g., tour photos/notes) in v1?
Task Breakdown
Backend
- Schemas + indexes (Mongo)
- Controllers/routes (REST) + tRPC routers
- Role guard middleware (Owner/Editor/Commenter/Viewer)
- Invite token service (sign/verify/expire)
- Similarity aggregation using Neo4j (feature-flagged)
- Notifications service (+Redis pub/sub if using Socket.IO)
- Tests: unit (Jest) + integration
Frontend (Next.js/React, Shadcn, Tailwind, Framer Motion)
- Collections list page
- Board view (grid/list, filters, stats, similarity panel)
- SaveToCollectionDialog (Map/Chat entry points)
- CommentThread with @mentions
- Share/invite UI with role picker
- In-app notifications UI
- Tests: unit + RTL + Cypress e2e
DevOps
- Env flags:
FEATURE_COLLECTIONS,INVITE_TOKEN_SECRET,DIGEST_EMAIL_ENABLED - CI: lint/test/build gates + new coverage thresholds
- Observability: Prometheus metrics, dashboards updates
- Docs: README, TECH_DOCS, Swagger (openapi), tRPC docs
Nice-to-Haves (stretch)
- Weekly digest email (SendGrid/Postmark)
- CSV/PDF export of board
- Web push notifications
Estimated Effort
- Backend: 3–5 days
- Frontend: 5–8 days
- QA/Docs/DevOps: 2–3 days (Small team, parallelized; stretch items excluded.)
Risks & Mitigations
- Data growth (comments/items): indexes + pagination; prune old notifications.
- Permission bugs: centralize role checks; add integration tests.
- Neo4j latency: batch queries; cache summaries.