Proto commits in yinhm/friendfeed

These 79 commits are when the Protocol Buffers files have changed:

Commit:44f835d
Author:Heming
Committer:Heming

feat: add external import workflow Co-authored-by: OpenAI Codex <codex@openai.com>

The documentation is generated from this commit.

Commit:c42f7ed
Author:Heming
Committer:Heming

feat: add Feed administration CLI Co-authored-by: OpenAI Codex <codex@openai.com>

Commit:0b1a41e
Author:Heming
Committer:Heming

feat: manage feed api keys over grpc Co-authored-by: OpenAI Codex <codex@openai.com>

Commit:921a8d3
Author:Heming
Committer:Heming

feat: add feed api key storage Co-authored-by: OpenAI Codex <codex@openai.com>

Commit:d6c40c9
Author:Heming
Committer:Heming

feat: add Feed archive statistics Co-authored-by: Codex <codex@openai.com>

Commit:d634576
Author:Heming
Committer:Heming

refactor: retire legacy twitter feed jobs Co-authored-by: Codex <codex@openai.com>

Commit:046a56e
Author:Heming
Committer:Heming

refactor: retire stock subsystem Co-authored-by: Codex <codex@openai.com>

Commit:567600b
Author:Heming

feat: list groups from discovery index Co-authored-by: Codex <codex@openai.com>

Commit:90bdd7d
Author:yinhm

feat: define realtime event stream protocol

Commit:b9f85d0
Author:Heming

feat: maintain home timeline per followed feed Co-authored-by: Codex <codex@openai.com>

Commit:d14247f
Author:Heming

fix: signal first-time login via gRPC header, not a Profile field Profile is a persisted protobuf type; carrying transient RPC state on it risked the flag being serialized by later UpdateProfile writes and changed the protobuf contract. PutOAuth now marks newly created profiles through the x-profile-newly-created response header (constant in pb/helper.go), leaving pb/feed.proto byte-identical to master.

Commit:a80bae4
Author:Heming

feat: flag newly created profiles in PutOAuth responses Adds a transient Profile.newly_created field (never persisted, set only after the profile write) so the web layer can detect first-time logins and redirect them to the profile page.

Commit:07e277a
Author:Heming

feat: resolve FetchProfile by profile ID The httpd private-feed request page needs feed metadata when the feed read itself is denied; uuid stays the primary key.

Commit:7ceb141
Author:Heming

feat: add follow-request RPC definitions RequestFollow/CancelFollowRequest/ApproveFollowRequest/ RejectFollowRequest/ListFollowRequests, plus compatible field additions: FollowResponse.requested, Feed.has_pending_follow_request, GroupView.has_pending_request.

Commit:41bce08
Author:Heming

feat: rank sidebar Groups by materialized activity Materialize one rebuildable JSON ranking per user under TableMeta (group-activity/v1) scored from current facts: create +100, post +10, like +3, comment +4, floored at zero. Deltas commit in the same batch as the authoritative Entry/Like/Comment mutation; join recalculates that Group from authoritative rows, leave removes the row, account deletion drops the key. Creator identity lives in group-owner/v1 metadata since GroupAdmin is transferable. ListUserGroups gains order_by_activity for the sidebar (top 10, no cursor, membership re-checked per row, falls back to Follow order before migration). Sidebar drops the 5-minute cache so activity updates are live. Add /groups full list page consuming every cursor page, plus rebuild_group_activity maintenance command (-user, -dry-run). Co-authored-by: Codex <codex@openai.com>

Commit:acfb397
Author:Heming

fix: enforce Group domain invariants Close trust and consistency gaps in Group posting, membership, administration, service management, private reads, account deletion, and store auditing. Co-authored-by: Codex <codex@openai.com>

Commit:2f5cc2b
Author:HaiMing.Yin
Committer:HaiMing.Yin

feat: complete Group spec server side - Restore StageJoinGroup private rejection (HEAD was red via TestJoinGroupRejectsPrivate); private Groups stay unjoinable until the approval flow exists - Close private-Group read paths per docs/group.md: cursor feed path, Home stale-row revalidation on read, Search result filtering (SearchRequest.viewer_uuid) - Enqueue idempotent home.rebuild task in the same Pebble batch as Group membership mutations (JoinGroup/LeaveGroup/RemoveGroupMember and GraphFollow's group branches), replacing fire-and-forget DeleteTimelineState goroutines - ListUserGroups/ListGroupMembers cursor per docs/group_navigation.md: seek to the last examined edge, scan budget counts only unexamined edges, zero-group pages keep making progress - New RPCs: DeleteGroup (soft delete), GetGroup (metadata plus viewer member/admin status), ListGroupMembers (paginated, admin flags) - MarkDelete rejects soft-deleting a sole Group admin, listing the blocking Groups, checked in the same critical section as the delete - Acceptance tests: timeline convergence on membership change, private non-bypass (feed/entry/home/search), sole-admin account deletion, DeleteGroup closure, cursor edge cases, member pagination - Sync docs/group.md gap list and docs/task_queue.md task types Co-authored-by: Kimi <noreply@moonshot.cn>

Commit:1f90f85
Author:HaiMing.Yin
Committer:HaiMing.Yin

feat: enforce private Group visibility with viewer_uuid Implements access control for private Groups by adding viewer_uuid to FeedRequest and EntryRequest. Non-members and unauthenticated users are now blocked from accessing private Group feeds and entries. Changes: - Add viewer_uuid field to FeedRequest and EntryRequest in pb/api.proto - Implement canAccessPrivateGroup helper in server/group.go - Enforce access control in ForwardFetchFeed and FetchEntry - Update all httpd handlers to pass viewer_uuid from session - Remove ErrPrivateGroupUnsupported block in model.StageJoinGroup (access control now handled at RPC layer) - Add TestPrivateGroupAccessControl covering all scenarios: admin/member access, outsider denial, unauthenticated denial This completes the private Group visibility requirement from docs/group.md line 224. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

Commit:970c343
Author:HaiMing.Yin
Committer:HaiMing.Yin

feat: implement ListUserGroups RPC, group creation UI, and audit tool Add ListUserGroups RPC with cursor-based pagination that returns groups a user has joined. Fix cursor pagination bug where cursor pointed to last scanned edge instead of last collected group, causing groups to be skipped. Frontend changes: - Add UserGroups() helper to load and cache user's joined groups - Invalidate groups cache in FollowHandler when following/unfollowing groups - Auto-inject user_groups into template context via HTML() method - Update layout.html sidebar to display Groups section with user's groups - Add /groups/create routes (GET page, POST handler) - Create group_create.html template with Ajax form submission Backend changes: - Implement ListUserGroups RPC that filters Follow edges by group type - Add tests covering pagination, edge cases, and deleted profile handling - Fix async goroutine lifecycle in JoinGroup/LeaveGroup/RemoveGroupMember by tracking with server.wg to prevent access to closed database in tests Audit tool: - Create tools/audit standalone tool for database integrity checks - Check for admins who are not members (orphaned GroupAdmin entries) - Check for groups without any admins - Check for Follow edges to deleted/missing groups - Check for GroupAdmin entries for deleted groups - Add comprehensive README documenting usage and checks Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

Commit:de7abaa
Author:HaiMing.Yin
Committer:HaiMing.Yin

feat: implement Group authorization and moderation Enforce Group posting membership at PostEntry mutation boundary per docs/group.md. Extends DeleteEntry and DeleteComment to allow Group admins to moderate content posted to their Group (delete-only). Adds UpdateGroup RPC for editing Group metadata with admin-only access. Changes: - PostEntry: authorizeEntryPost enforces Group membership, exempts FeedService self-posts (ProfileUuid == FeedUuid == Group) - DeleteEntry: isGroupAdminOfEntryFeed allows admin to delete any Entry where entry.FeedUuid resolves to their Group - DeleteComment: canModerateComment extended for Group admin delete-only grant (admins cannot edit comments they don't own) - UpdateGroup: new RPC with StageUpdateGroup/UpdateGroup for editing name/description/picture (ID/type/private immutable) - authorizeFeedServiceAdmin: switched from Feedinfo.Admins snapshot to GroupAdmin table as authoritative source Migration note: Existing Groups with admins only in Feedinfo.Admins require manual bootstrap (super: JoinGroup + AddGroupAdmin) or one-time backfill. Current deployment has no production Groups. Tests: 8 new tests covering PostEntry membership enforcement, DeleteEntry/DeleteComment admin moderation, UpdateGroup authorization, and Group-admin delete-only semantics. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

Commit:defb35e
Author:HaiMing.Yin
Committer:HaiMing.Yin

feat: consolidate Group Join/Leave and admin management Add JoinGroup/LeaveGroup/AddGroupAdmin/RemoveGroupAdmin/RemoveGroupMember to the domain layer, enforcing that a Group's last admin can't be demoted or removed, and that an admin must be demoted before leaving or being removed as a member. Route GraphFollow's follow/unfollow actions through this layer when the target is a Group, and expose the five operations as gRPC RPCs sharing a GroupMembershipRequest message. Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>

Commit:695678f
Author:HaiMing.Yin
Committer:HaiMing.Yin

feat: add atomic CreateGroup mutation and RPC Add model.StageCreateGroup/CreateGroup, writing Profile(Type=group), Group ID UserMap, creator Follow/Follower and creator GroupAdmin in one Pebble batch, per docs/group.md step 2. Group IDs share the user ID namespace/validation/UserRenameMap reservation rules via NormalizeProfileId/FindProfileRenameByOldId. Rejects a non-existent or non-user actor, a taken Group ID, and private=true until the approval/invite flow exists (ErrPrivateGroupUnsupported). Add the CreateGroupRequest message and CreateGroup RPC to pb/api.proto, regenerated via protoc, and server.ApiServer.CreateGroup wiring it to the domain layer with the same parse/authorize/domain-call/taskRPCError pattern as the FeedService RPCs. Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>

Commit:f99e22e
Author:Heming

feat: define interaction timeline contracts Co-authored-by: Codex <codex@openai.com>

Commit:4fdff6b
Author:Heming

feat: manage Service source lifecycle Co-authored-by: Codex <codex@openai.com>

Commit:697951d
Author:Heming

feat: add FeedService management UI Co-authored-by: Codex <codex@openai.com>

Commit:386e190
Author:Heming

feat: implement canonical Service aggregation Co-authored-by: Codex <codex@openai.com>

Commit:39f5642
Author:Heming
Committer:Heming

feat(rss): add subscription wire contracts Co-authored-by: Codex <codex@openai.com>

Commit:994142f
Author:Heming
Committer:Heming

feat(task): add queue wire and table contracts Co-authored-by: Codex <codex@openai.com>

Commit:f9dbf5c
Author:Heming

feat: add cursor pagination for user feeds Keep public, search, and explicit legacy start links on offset pagination while profile and timeline pages use compact forward-only cursors. Co-authored-by: Codex <codex@openai.com>

Commit:998626f
Author:Heming

feat: require stable user_uuid principal for comment commands Step 2 of TODO.md. CommentRequest gains user_uuid (field 3) and CommentDeleteRequest gains user_uuid (field 4) as compatible additions; the legacy user field stays on the wire but is no longer consulted. httpd fills user_uuid from the session; the server resolves the canonical profile via principalFromUserUuid and rejects missing, malformed, zero, or unknown principals with InvalidArgument/NotFound. Note this is an intentional behavior change for any external caller of these RPCs: requests without user_uuid are now rejected, closing the path where the server resolved the author from the client-supplied (comment.From.Id / user) reference. comment.From is still saved as sent; overwriting it with the canonical actor ref is Step 3. Co-authored-by: Kimi <kimi@moonshot.cn>

Commit:bf2591a
Author:HaiMing.Yin

twitter: PostTwitter

Commit:0b37411
Author:HaiMing.Yin

GICS and employees for hkex stocks

Commit:956dbc0
Author:HaiMing.Yin

golint: fix for lint

Commit:eb5ce36
Author:HaiMing.Yin

proto: updated for newer gen

Commit:ecc1001
Author:HaiMing.Yin

WIP: tabular data in feed and detail page

Commit:388c6dc
Author:HaiMing.Yin
Committer:HaiMing.Yin

WIP: tabular entry support

Commit:87aff2b
Author:HaiMing.Yin

rpc: send report to related feed

Commit:fb01c7b
Author:HaiMing.Yin

api: unified rawdata for all kind of stock data

Commit:4e4db9f
Author:HaiMing.Yin

api: unique symbol insteam of req.Market plus req.Symbol

Commit:0b42dba
Author:HaiMing.Yin

feat: new rpc api, ArchiveStockInfo, GetStockInfo

Commit:4a8a5a0
Author:HaiMing.Yin

feat: ArchiveFundamental and GetFundamental

Commit:5a80d3e
Author:HaiMing.Yin

feat: GetStock rpc

Commit:e5f0cf0
Author:HaiMing.Yin

feat: fanout to user timeline

Commit:b707663
Author:HaiMing.Yin

refactor: move service from feedinfo to its own schema

Commit:530c002
Author:HaiMing.Yin

WIP: FetchFeedinfo never used, commented for now

Commit:849a012
Author:HaiMing.Yin

WIP: renaming proto to pb

Commit:c6040fb
Author:HaiMing.Yin

WIP: renaming proto to pb

Commit:de3417a
Author:HaiMing.Yin

WIP: renew feed db design

Commit:c63bc22
Author:HaiMing.Yin

WIP: write feed to group

Commit:f1cacb2
Author:HaiMing.Yin

feat: allow user to follow/unfollow feed

Commit:576ae34
Author:HaiMing.Yin

fix: ArchiveXRXD

Commit:4c989de
Author:HaiMing.Yin

feat: GetStockList and UpdateStockList api

Commit:6ce29c9
Author:HaiMing.Yin

feat: GetKLines api

Commit:7dfaae0
Author:HaiMing.Yin

feat: sync xrxd

Commit:e3cd39c
Author:HaiMing.Yin

stock: sync dividend, not store to db yet

Commit:40431e9
Author:HaiMing.Yin

cli: sync stock klines

Commit:3f54630
Author:HaiMing.Yin

cmd: toggle super amdin

Commit:34f72df
Author:HaiMing.Yin

adding Index server

Commit:04a6500
Author:HaiMing.Yin

pb: title for entry

Commit:f4f4b14
Author:HaiMing.Yin

allow delete entry

Commit:d67e17c
Author:HaiMing.Yin

auth: allow login from twitter

Commit:02d3bab
Author:HaiMing.Yin

proto: migrated to proto3

Commit:6317fce
Author:HaiMing.Yin

delete entry, need to fix feeds

Commit:452e7c7
Author:HaiMing.Yin

server, httpd, UI: delete comment

Commit:3c73650
Author:HaiMing.Yin

server, http: move comment construct to client(http), fixed comment id

Commit:cc05adc
Author:HaiMing.Yin
Committer:HaiMing.Yin

server: mark delete for later purge, refs #2, #3

Commit:a15485b
Author:HaiMing.Yin

server: mark profile deletion, refs #2, #3

Commit:c76f9e1
Author:HaiMing.Yin

log twitter server created time, do not sync tweets before it

Commit:1093c23
Author:HaiMing.Yin

service: fixed twitter screen_name, added DeleteService by name

Commit:5c5b13d
Author:HaiMing.Yin
Committer:HaiMing.Yin

service: updated twitter archiver

Commit:83c2ca2
Author:HaiMing.Yin

client: from fetch friendfeed to fetch twitter

Commit:8b8f99e
Author:HaiMing.Yin

import twitter account

Commit:d26ccc7
Author:HaiMing.Yin

auth: import twitter

Commit:df698d8
Author:HaiMing.Yin

server, httpd, proto: introducing graph, FetchGraph then rebuild commands from web client

Commit:6fafa29
Author:HaiMing.Yin

comment handler

Commit:736b131
Author:HaiMing.Yin
Committer:HaiMing.Yin

User like/dislike entry.

Commit:efc5759
Author:HaiMing.Yin

server, http: Get current_user on each request, also show current_user feed and logout link

Commit:d57665e
Author:HaiMing.Yin

remove not used proto files

Commit:a4eaf12
Author:HaiMing.Yin

Initial checking in