Commit Graph

18 Commits

Author SHA1 Message Date
vsecoder
1c6622e809 fix(feed): more vertical gap between header and post content
marginTop 8 → 14 on the content Pressable. Gives the body text a
clear visual separation from the avatar/name header instead of
sitting flush under it.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-18 21:37:46 +03:00
vsecoder
ab98f21aac fix(feed): stack header + full-width content instead of avatar-sibling column
The previous layout put body text, attachments and action row inside
a column next to the avatar. Two recurring bugs came from that:

  1. The column's width = screen - 16 - 44 - 10 - 16 = screen - 86px.
     Long text or attachments computed against that narrower width,
     and on a few RN builds the measurement was off enough that text
     visibly ran past the card's right edge.
  2. The column visually looked weird: a photo rendered only 3/4 of
     the card width because the avatar stole 54px on the left.

Fix: make the card a vertical stack.

  ┌─────────────────────────────────────────┐
  │ [avatar] [name · time]          [menu]  │   ← HEADER row
  ├─────────────────────────────────────────┤
  │ body text, full card width              │   ← content column
  │ [attachment image, full card width]     │
  │ [action row, full card width]           │
  └─────────────────────────────────────────┘

Now body and media always occupy the full card width (paddingLeft:16
paddingRight:16 from the outer View), long lines wrap inside that,
and the earlier overflow-tricks / width-100% / paddingRight-4
band-aids aren't needed. Removed them.

Header row is unchanged structurally (avatar + name-row Pressable +
menu button) — just lifted into a dedicated View so the content
column below starts at the left card edge instead of alongside the
avatar.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-18 21:35:07 +03:00
vsecoder
9be1b60ef1 fix(feed): move card layout off Pressable style-fn so paddings stick
Same Pressable-dynamic-style-function bug that bit the FAB: on some
RN versions the style function is re-evaluated mid-render in a way
that drops properties — here we lost paddingLeft:16 and sometimes
flexDirection:'row' on the outer PostCard Pressable, which is why
the avatar ended up flush against the left edge and the header/body
sometimes stacked into a column instead of row.

Fix: move layout to a plain <View> wrapper (static styles, can never
be dropped). Tap handling stays on two Pressables:
  - the avatar wrapper (opens author profile),
  - the content column (opens post detail + long-press for menu).

The card area visually covered by these two Pressables is ~100% —
tap anywhere on a post still navigates to detail, tap on the avatar
still goes to the author. No interaction regression.

Also paired opacity press-state on the content-column Pressable so
the feedback visual matches what the old bg-colour press gave.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-18 21:28:34 +03:00
vsecoder
0bb5780a5d feat(feed/chat): VK-style share post to chats + list breathing room
Feed list padding
  FlatList had no inner padding so the first post bumped against the
  tab strip and the last post against the NavBar. Added paddingTop: 8
  / paddingBottom: 24 on contentContainerStyle in both /feed and
  /feed/tag/[tag] — first card now has a clear top gap, last card
  doesn't get hidden behind the FAB or NavBar.

Share-to-chat flow
  Replaces the placeholder share button (which showed an Alert with
  the post URL) with a real "forward to chats" flow modeled on VK's
  shared-wall-post embed.

  New modules
    lib/forwardPost.ts       — encodePostRef / tryParsePostRef +
                               forwardPostToContacts(). Serialises a
                               feed post into a tiny JSON payload that
                               rides the same encrypted envelope as any
                               chat message; decode side distinguishes
                               "post_ref" payloads from regular text by
                               trying JSON.parse on decrypted text.
                               Mirrors the sent message into the sender's
                               local history so they see "you shared
                               this" in the chat they forwarded to.

    components/feed/ShareSheet.tsx
                             — bottom-sheet picker. Multi-select
                               contacts via tick-box, search by
                               username / alias / address prefix.
                               "Send (N)" dispatches N parallel
                               encrypted envelopes. Contacts with no
                               X25519 key are filtered out (can't
                               encrypt for them).

    components/chat/PostRefCard.tsx
                             — compact embedded-post card for chat
                               bubbles. Ribbon "ПОСТ" label +
                               author + 3-line excerpt + "с фото"
                               indicator. Tap → /(app)/feed/{id} full
                               post detail. Palette switches between
                               blue-bubble-friendly and peer-bubble-
                               friendly depending on bubble side.

  Message pipeline
    lib/types.ts           — Message.postRef optional field added.
                             text stays "" when the message is a
                             post-ref (nothing to render as plain text).
    hooks/useMessages.ts   + hooks/useGlobalInbox.ts
                           — post decryption of every inbound envelope
                             runs through tryParsePostRef; matching
                             messages get the postRef attached instead
                             of the raw JSON in .text.
    components/chat/MessageBubble.tsx
                           — renders PostRefCard inside the bubble when
                             msg.postRef is set. Other bubble features
                             (reply quote, attachment preview, text)
                             still work around it.

  PostCard
    - share icon now opens <ShareSheet>; the full-URL placeholder is
      gone. ShareSheet is embedded at the PostCard level so each card
      owns its own sheet state (avoids modal-stacking issues).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-18 21:26:43 +03:00
vsecoder
50aacced0b fix(feed): header on one line, avatar padding explicit, icon/label aligned
Three related layout polish issues.

1. Avatar + name + time splitting to two lines

   Fixed by collapsing the "·" separator + time into a single Text
   component (was three sibling Texts). RN occasionally lays out
   three-Text-sibling rows oddly when the name is long because each
   Text measures independently. With the separator glued to the time,
   there's one indivisible chip for "·  2h" that flexShrink:0 keeps on
   the row; the name takes the rest and truncates with "…" if needed.
   Also wrapped the name + time in a flex:1 Pressable (author tap
   target) so the row width is authoritative.

2. Avatar flush against the left edge

   The outer Pressable's style-function paddingLeft was being applied
   but the visual offset felt wrong because avatar has no explicit
   width. Added width:44 to the avatar's own Pressable wrapper so the
   flex-row layout reserves exactly the expected space and the 16-px
   paddingLeft on the outer Pressable is visible around the avatar's
   left edge.

3. Like / view count text visually below icon's centre

   RN Text includes extra top padding (Android) and baseline-anchors
   (iOS) that push the number glyph a pixel or two below the icon
   centre in a flex-row with alignItems:'center'. Added explicit
   lineHeight:16 (matching icon size) + includeFontPadding:false +
   textAlignVertical:'center' on both the heart button's Text and the
   shared ActionButton Text → numbers now sit on the same optical
   baseline as their icons on both platforms.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-18 21:18:29 +03:00
vsecoder
38ae80f57a fix(feed): long post body no longer overflows the card
The body Text inherited the content column's width only implicitly
via flex:1 on the parent, which on some Android RN builds was
computed one or two pixels wider than the true column width — enough
to make a long line visually escape the right side of the card.

Belt-and-braces fix:
  - content column gets overflow:'hidden' so anything that escapes
    the computed width gets clipped instead of drawn outside.
  - body Text explicitly sets width:'100%' + flexShrink:1 +
    paddingRight:4 so the wrapping algorithm always knows the
    authoritative maximum and leaves a 4-px visual buffer from the
    column edge.

Together these guarantee long single-line posts wrap correctly on
both iOS and Android, and short-but-wide tokens (URLs, long
hashtags) ellipsize instead of poking out.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-18 21:14:22 +03:00
vsecoder
c5ca7a0612 feat(feed): image previews + inline header + 5-line truncation + drop comments
Server
  node/api_feed.go: new GET /feed/post/{id}/attachment route. Returns
  raw attachment bytes with the correct Content-Type so React Native's
  <Image source={uri}> can stream them directly without the client
  fetching + decoding base64 from the main /feed/post/{id} JSON (would
  blow up memory on a 40-post timeline). Respects on-chain soft-delete
  (410 when tombstoned). Cache-Control: public, max-age=3600, immutable
  — attachments are content-addressed so aggressive caching is safe.

PostCard — rewritten header row
  - Avatar + name + time collapsed into a single Pressable row with
    flexDirection:'row'. Name gets flexShrink:1 + numberOfLines:1 so
    long handles truncate with "…" mid-row instead of pushing the time
    onto a second line. Time and separator dot both numberOfLines:1
    with no flex — they never shrink, so "2h" stays readable.
  - Whole header is one tap target → navigates to the author's profile.

PostCard — body truncation
  - Timeline view (compact=false): numberOfLines={5} + ellipsizeMode:
    'tail'. Long posts collapse to 5 lines with "…"; tapping the card
    opens the detail view where the full body is shown.
  - Detail view (compact=true): no line cap — full text, then full-
    size attachment below.

PostCard — real image previews
  - <Image source={{ uri: `${node}/feed/post/${id}/attachment` }}>
    (feed layout).
  - Timeline: aspectRatio: 4/5 + resizeMode:'cover' — portrait photos
    get cropped so one tall image can't eat the whole feed.
  - Detail: aspectRatio: 1 + resizeMode:'contain' so the full image
    fits in its original proportions (crop-free).

PostCard — comments button removed
  v2.0.0 doesn't implement replies; a dead button with label "0" was
  noise. Action row now has 3 cells: heart (with live like count),
  eye (views), share (pinned right). Spacing stays balanced because
  each of the first two cells is still flex:1.

Post detail screen
  - Passes compact prop so the PostCard above renders in full-body /
    full-attachment mode.
  - Dropped the old AttachmentPreview placeholder — PostCard now
    handles images in both modes.

Tests
  - go test ./... — all 7 packages green (blockchain / consensus /
    identity / media / node / relay / vm).
  - tsc --noEmit on client-app — 0 errors.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-18 20:38:15 +03:00
vsecoder
7bfd8c7dea fix(feed): side padding on action row + stable FAB right-anchor
- Post action row (chat / ❤ / eye / share) had only a small paddingRight
  and no left padding. First icon sat flush under the avatar and share
  iron against the card edge. Replaced with paddingHorizontal: 12 so
  both sides get equal breathing room; each of the four cells still
  flex:1 so the icons distribute evenly.
- FAB kept appearing at the LEFT edge instead of the right on user's
  device despite position:absolute + right:12. Pressable's dynamic-
  function style can drop absolute-positioning fields between renders
  on some RN versions. Wrapping the Pressable in a plain absolute-
  positioned View fixes this: positioning lives on the View (never
  re-evaluated mid-render), the Pressable inside only declares size
  and visuals. pointerEvents="box-none" on the wrapper keeps taps
  outside the button passing through to the feed list below.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-18 20:31:03 +03:00
vsecoder
f688f45739 fix(feed): breathing room around divider + FAB back to right/bottom corner
- PostSeparator was a bare 1px line flush against both neighbouring
  cards, so the seam looked like card contact instead of a real
  break. Wrapped it in a 12px vertical padding — now there's 12px
  blank above the line, 1px line, 12px blank below. Trimmed the
  card's own paddingVertical back down since the separator now owns
  the inter-post breathing room.
- FAB was lifted to bottom: max(insets.bottom, 8) + 70 in the previous
  commit which put it far too high (a leftover from the original
  experiment with the absoluteFill wrapper). User wants 12px above
  the NavBar and 12px from the right edge. The Feed screen's
  container ends at the NavBar top (enforced by (app)/_layout.tsx's
  outer <View flex:1> + NavBar sibling), so a simple `right: 12,
  bottom: 12` on position:absolute lands the button exactly there on
  every device. Removed the now-unnecessary absoluteFill wrapper too.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-18 20:28:52 +03:00
vsecoder
a248c540d5 fix(feed): visible post divider + reliable FAB positioning
- Post divider was on each PostCard's outer Pressable as borderBottom
  (#222), which was barely visible on OLED black and disappeared
  entirely in pressed state (the pressed bg ate the line). Moved the
  seam to a dedicated PostSeparator component (1px, #2a2a2a) wired as
  FlatList's ItemSeparatorComponent on both /feed (timeline / for-you
  / trending) and /feed/tag/[tag]. Also bumped inter-card vertical
  padding (14-16 top / 16-20 bottom) so cards have real breathing room
  even before the divider.
- FAB position was flaky: with <Stack> at the (app) level the overlay
  could end up positioned against the Stack's card view instead of the
  tab container, which made the button drift around and stick against
  unexpected edges. Wrapped it in an absoluteFill container with
  pointerEvents="box-none" — the wrapper owns positioning against the
  tab screen, the button inside just declares right: 14 / bottom: N.
  Bumped bottom offset to `max(insets.bottom, 8) + 70` so the FAB
  always clears the 5-icon NavBar with ~14px visual gap on every
  device. Shadow switched from blue-cast to standard dark for better
  depth perception on dark backgrounds.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-18 20:23:52 +03:00
vsecoder
51bc0a1850 fix(feed): card spacing, action-row distribution, tab strip, detail inset
- PostCard rows got cramped paddings and a near-invisible divider.
  Increased paddingTop 12→16, paddingBottom 12→18, paddingHorizontal
  14→16; divider colour #141414→#222222 so the seam between posts is
  legible on OLED blacks.
- Action row (chat / ❤ / view / share) used a fixed gap:32 + spacer.
  Reworked to four flex:1 cells with justifyContent: space-between,
  so the first three icons distribute evenly across the row and share
  pins to the right edge. Matches Twitter's layout where each action
  occupies a quarter of the row regardless of label width.
- Feed tab strip (Подписки / Для вас / В тренде) used flex:1 +
  gap:10 which bunched the three labels together visually. Switched
  to justifyContent: space-between + paddingHorizontal:20 so each
  tab hugs its label and the three labels spread to the edges with
  full horizontal breathing room.
- Post detail screen (/feed/[id]) and hashtag feed (/feed/tag/[tag])
  were missing the safe-area top inset — their headers butted right
  against the status bar / notch. Added useSafeAreaInsets().top as
  paddingTop on the outer View, matching the rest of the app.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-18 20:20:18 +03:00
vsecoder
93040a0684 fix(client): DM-only info, seed on API error, proper cross-group back stack
Three related UX fixes on the client.

1. Participants count on profile

   DMs always have exactly two participants (you and the contact) so a
   "Участников: 1" row was confusing — either it's obviously the other
   person or it's wrong depending on how you count. Removed for direct
   conversations; the row still appears for group chats (and shows an
   em-dash until v2.1.0 gives groups a real member list).

2. Dev feed seed now activates on network / 404 errors

   The seed was only surfaced when the real API returned an EMPTY
   array. If the node was down (Network request failed) or the endpoint
   replied 404, the catch block quietly set posts to [] and the list
   stayed blank — defeating the point of the seed. Now both the empty-
   response path AND the network-error path fall back to getDevSeedFeed(),
   so scrolling / like-toggling works even without a running node.

   Also made the __DEV__ lookup more defensive: use `globalThis.__DEV__`
   at runtime instead of the typed global. Some bundler configurations
   have the TS type but not the runtime binding, or vice-versa — the
   runtime lookup always agrees with Metro.

3. Back from profile → previous screen instead of tab root

   Root cause: AnimatedSlot rendered <Slot>, which is stack-less. When
   /chats/xyz pushed /profile/abc (cross-group), the chats group
   unmounted. Hitting Back then re-entered chats at its root (/chats
   list) rather than /chats/xyz.

   Replaced <Slot> with <Stack> in AnimatedSlot. Tab switching still
   stays flat because NavBar uses router.replace (which maps to
   navigation.replace on the Stack — no history accumulation).
   Cross-group pushes (post author tap from feed, avatar tap from chat
   header, compose modal) now live in the outer Stack's history, so
   Back pops correctly to the caller.

   The nested Stacks (chats/_layout.tsx, feed/_layout.tsx,
   profile/_layout.tsx) still handle intra-group navigation as before.
   The PanResponder-based swipe-right-to-back was removed since the
   native Stack now provides iOS edge-swipe natively; Android uses the
   system back button.

   animation: 'none' keeps the visual swap instant — matches the prior
   Slot look so nothing flashes slide-animations that weren't there
   before. Sub-group layouts can opt into slide_from_right themselves
   (profile/_layout.tsx and feed/_layout.tsx already do).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-18 20:16:38 +03:00
vsecoder
98a0a4b8ba fix(nav): move feed.tsx → feed/index.tsx to unblock duplicate-route error
expo-router error: "A navigator cannot contain multiple 'Screen'
components with the same name (found duplicate screen named 'feed')".

Cause: having both app/(app)/feed.tsx (a file-route) and
app/(app)/feed/ (a folder with _layout.tsx) at the same level makes
expo-router try to register two routes called "feed".

Fix: the folder's _layout.tsx wraps the tab + its sub-routes in a
single Stack, so the tab screen becomes feed/index.tsx — the initial
screen of that Stack. Back navigation from /feed/[id] and
/feed/tag/[tag] now correctly pops to the Feed tab root.

No other route references changed (paths like /(app)/feed,
/(app)/feed/<id>, /(app)/feed/tag/<tag> still resolve identically).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-18 20:10:33 +03:00
vsecoder
5728cfc85a fix(client): profile polish + proper back stack + dev feed seed
Profile screen
  - Missing safe-area top inset on the header — fixed by wrapping the
    outer View in paddingTop: insets.top (matches the rest of the tab
    screens).
  - "Чат" button icon + text sat on two lines because the button used
    column layout by default. Rewritten as a full-width CTA pill with
    flexDirection: row and alignItems: center → chat-bubble icon and
    label sit on one line.
  - Dedicated "Копировать адрес" button removed. The address row in
    the info card is now the tap target: pressing it copies to clipboard
    and flips the row to "Скопировано" with a green check for 1.8s.
  - Posts tab removed entirely. User's right — a "chat profile" has no
    posts concept, just participant count + date + encryption. The
    profile screen is now a single-view info card (address, encryption
    status, added date, participants). Posts are discoverable via the
    Feed tab; a dedicated /feed/author/{pub} screen is on the roadmap
    for browsing a specific user's timeline.

Back-stack navigation
  - app/(app)/profile/_layout.tsx + app/(app)/feed/_layout.tsx added,
    each with a native <Stack>. The outer AnimatedSlot is stack-less
    (intentional — it animates tab switches), so without these nested
    stacks `router.back()` from a profile screen had no history to pop
    and fell through to root. Now tapping an author in the feed → back
    returns to feed; opening a profile from chat header → back returns
    to the chat.

Dev feed seed
  - lib/devSeedFeed.ts: 12 synthetic posts (text-only, mix of hashtags,
    one with has_attachment, varying likes/views, timestamps from "1m
    ago" to "36h ago"). Exposed via getDevSeedFeed() — stripped from
    production via __DEV__ gate.
  - Feed screen falls back to the dev seed only when the real API
    returned zero posts. Gives something to scroll / tap / like-toggle
    before the backend has real content; real data takes over as soon
    as it arrives.

Note: tapping a mock post into detail will 404 against the real node
(the post_ids don't exist on-chain). Intentional — the seed is for
scroll + interaction feel, not deep linking.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-18 20:08:48 +03:00
vsecoder
0ff2760a11 fix(feed): compose footer above keyboard, tab spacing, FAB position
- Composer footer (attach / counter / fee bar) now rides with the
  keyboard on both platforms: KeyboardAvoidingView behavior is
  "padding" on iOS and "height" on Android. Previously behavior was
  undefined on Android, and the global softwareKeyboardLayoutMode:"pan"
  setting lifted the whole screen — leaving the footer hidden below
  the keyboard.
- Feed tab strip (Подписки / Для вас / В тренде) had zero horizontal
  breathing room — three equal-width Pressables flush to the edges.
  Added 12px outer paddingHorizontal + 10px gap + slightly bigger
  paddingVertical. The active indicator is now 32px wide (was 48) so
  it sits under the label instead of underlining two words.
- Floating compose FAB pinned to the right edge with a 14px inset
  (was 18). Vertical offset tightened from +70 to +62 above the
  safe-area inset — closer to the NavBar top edge while still clear
  of the icons.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-18 20:03:15 +03:00
vsecoder
5b64ef2560 feat(client): Twitter-style social feed UI (Phase C of v2.0.0)
Ships the client side of the v2.0.0 feed feature. Folds client-app/
into the monorepo (was previously .gitignored as "tracked separately"
but no separate repo ever existed — for v2.0.0 the client is
first-class).

Feed screens

  app/(app)/feed.tsx — Feed tab
    - Three-way tab strip: Подписки / Для вас / В тренде backed by
      /feed/timeline, /feed/foryou, /feed/trending respectively
    - Default landing tab is "Для вас" — surfaces discovery without
      requiring the user to follow anyone first
    - FlatList with pull-to-refresh + viewability-driven view counter
      bump (posts visible ≥ 60% for ≥ 1s trigger POST /feed/post/…/view)
    - Floating blue compose button → /compose
    - Per-post liked_by_me fetched in batches of 6 after list load

  app/(app)/compose.tsx — post composer modal
    - Fullscreen, Twitter-like header (✕ left, Опубликовать right)
    - Auto-focused multiline TextInput, 4000 char cap
    - Hashtag preview chips that auto-update as you type
    - expo-image-picker + expo-image-manipulator pipeline: resize to
      1080px max-dim, JPEG Q=50 (client-side first-pass compression
      before the mandatory server-side scrub)
    - Live fee estimate + balance guard with a confirmation modal
      ("Опубликовать пост? Цена: 0.00X T · Размер: N KB")
    - Exif: false passed to ImagePicker as an extra privacy layer

  app/(app)/feed/[id].tsx — post detail
    - Full PostCard rendering + detailed info panel (views, likes,
      size, fee, hosting relay, hashtags as tappable chips)
    - Triggers bumpView on mount
    - 410 (on-chain soft-delete) routes back to the feed

  app/(app)/feed/tag/[tag].tsx — hashtag feed

  app/(app)/profile/[address].tsx — rebuilt
    - Twitter-ish profile: avatar, name, address short-form, post count
    - Posts | Инфо tab strip
    - Follow / Unfollow button for non-self profiles (optimistic UI)
    - Edit button on self profile → settings
    - Secondary actions (chat, copy address) when viewing a known contact

Supporting library

  lib/feed.ts — HTTP wrappers + tx builders for every /feed/* endpoint:
    - publishPost (POST /feed/publish, signed)
    - publishAndCommit (publish → on-chain CREATE_POST)
    - fetchPost / fetchStats / bumpView
    - fetchAuthorPosts / fetchTimeline / fetchForYou / fetchTrending /
      fetchHashtag
    - buildCreatePostTx / buildDeletePostTx
    - buildFollowTx / buildUnfollowTx
    - buildLikePostTx / buildUnlikePostTx
    - likePost / unlikePost / followUser / unfollowUser / deletePost
      (high-level helpers that bundle build + submitTx)
    - formatFee, formatRelativeTime, formatCount — Twitter-like display
      helpers

  components/feed/PostCard.tsx — core card component
    - Memoised for performance (N-row re-render on every like elsewhere
      would cost a lot otherwise)
    - Optimistic like toggle with heart-bounce spring animation
    - Hashtag highlighting in body text (tappable → hashtag feed)
    - Long-press context menu (Delete, owner-only)
    - Views / likes / share-link / reply icons in footer row

Navigation cleanup

  - NavBar: removed the SOON pill on the Feed tab (it's shipped now)
  - (app)/_layout: hide NavBar on /compose and /feed/* sub-routes
  - AnimatedSlot: treat /feed/<id>, /feed/tag/<t>, /compose as
    sub-routes so back-swipe-right closes them

Channel removal (client side)

  - lib/types.ts: ContactKind stripped to 'direct' | 'group'; legacy
    'channel' flag removed. `kind` field kept for backward compat with
    existing AsyncStorage records.
  - lib/devSeed.ts: dropped the 5 channel seed contacts.
  - components/ChatTile.tsx: removed channel kindIcon branch.

Dependencies

  - expo-image-manipulator added for client-side image compression.
  - expo-file-system/legacy used for readAsStringAsync (SDK 54 moved
    that API to the legacy sub-path; the new streaming API isn't yet
    stable).

Type check

  - npx tsc --noEmit — clean, 0 errors.

Next (not in this commit)

  - Direct attachment-bytes endpoint on the server so post-detail can
    actually render the image (currently shows placeholder with URL)
  - Cross-relay body fetch via /api/relays + hosting_relay pubkey
  - Mentions (@username) with notifications
  - Full-text search

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-18 19:43:55 +03:00
vsecoder
546d2c503f chore(release): clean up repo for v0.0.1 release
Excluded from release bundle:
- CONTEXT.md, CHANGELOG.md (agent/project working notes)
- client-app/ (React Native messenger — tracked separately)
- contracts/hello_go/ (unused standalone example)

Kept contracts/counter/ and contracts/name_registry/ as vm-test fixtures
(referenced by vm/vm_test.go; NOT production contracts).

Docs refactor:
- docs/README.md — new top-level index with cross-references
- docs/quickstart.md — rewrite around single-node as primary path
- docs/node/README.md — full rewrite, all CLI flags, schema table
- docs/api/README.md — add /api/well-known-version, /api/update-check
- docs/contracts/README.md — split native (Go) vs WASM (user-deployable)
- docs/update-system.md — new, full 5-layer update system design
- README.md — link into docs/, drop CHANGELOG/client-app references

Build-time version system (inherited from earlier commits this branch):
- node --version / client --version with ldflags-injected metadata
- /api/well-known-version with {build, protocol_version, features[]}
- Peer-version gossip on dchain/version/v1
- /api/update-check against Gitea release API
- deploy/single/update.sh with semver guard + 15-min systemd jitter
2026-04-17 14:37:00 +03:00
vsecoder
7e7393e4f8 chore: initial commit for v0.0.1
DChain single-node blockchain + React Native messenger client.

Core:
- PBFT consensus with multi-sig validator admission + equivocation slashing
- BadgerDB + schema migration scaffold (CurrentSchemaVersion=0)
- libp2p gossipsub (tx/v1, blocks/v1, relay/v1, version/v1)
- Native Go contracts (username_registry) alongside WASM (wazero)
- WebSocket gateway with topic-based fanout + Ed25519-nonce auth
- Relay mailbox with NaCl envelope encryption (X25519 + Ed25519)
- Prometheus /metrics, per-IP rate limit, body-size cap

Deployment:
- Single-node compose (deploy/single/) with Caddy TLS + optional Prometheus
- 3-node dev compose (docker-compose.yml) with mocked internet topology
- 3-validator prod compose (deploy/prod/) for federation
- Auto-update from Gitea via /api/update-check + systemd timer
- Build-time version injection (ldflags → node --version)
- UI / Swagger toggle flags (DCHAIN_DISABLE_UI, DCHAIN_DISABLE_SWAGGER)

Client (client-app/):
- Expo / React Native / NativeWind
- E2E NaCl encryption, typing indicator, contact requests
- Auto-discovery of canonical contracts, chain_id aware, WS reconnect on node switch

Documentation:
- README.md, CHANGELOG.md, CONTEXT.md
- deploy/single/README.md with 6 operator scenarios
- deploy/UPDATE_STRATEGY.md with 4-layer forward-compat design
- docs/contracts/*.md per contract
2026-04-17 14:16:44 +03:00