」工欲善其事,必先利其器。「—孔子《論語.錄靈公》
首頁 > 程式設計 > 我如何建立 PeerSplit:一個免費的點對點費用分攤應用程式 — 從構思到發布僅需數週時間

我如何建立 PeerSplit:一個免費的點對點費用分攤應用程式 — 從構思到發布僅需數週時間

發佈於2024-11-07
瀏覽:936

我构建了 PeerSplit——一个免费的、点对点的 Splitwise 替代品——从想法到发布仅用了两周时间!

PeerSplit 是一款本地优先的应用程序,用于分配团体费用。它可以离线工作,100% 免费且私密,不需要注册或任何个人数据。

以下是我如何构建它以及我在此过程中学到的一切。

为何选择 PeerSplit?

我多年来一直依靠 Splitwise 来管理与朋友和室友的开支。但由于最近的每日交易限制和侵入性广告,它的使用变得令人沮丧。

我想要一个免费的、隐私优先的替代方案,不需要服务器来存储或同步数据。我不会相信第三方服务器的费用。

在完成了点对点、本地优先的项目(例如锻炼追踪器和无干扰写作应用程序)后,我意识到我可以应用相同的方法来分配费用。

PeerSplit 就这样诞生了。我开始设计应用程序。


使用 Nuxt 构建 UI Nuxt UI

我不擅长设计 UI。

几个月前,我不会想到我可以构建一个像 PeerSplit 一样精美的 UI(有些人甚至说它比 Splitwise 具有更好的用户体验)。

那么,我是如何做到的呢? Nuxt UI。

Nuxt UI 非常华丽,并且拥有令人惊叹的开发者体验 (DX)。

它还附带其他有用的 Nuxt 模块,如 @nuxt/icon、@nuxtjs/tailwindcss 和 @nuxtjs/colormode。

我所要做的就是选择一种主色,并且我拥有了将 PeerSplit 的 UI 整合在一起所需的所有组件(图标、深色模式和其他所有内容)。


cr-sqlite 用于本地同步?

对于本地数据存储和同步,我选择了 cr-sqlite,它基于 wa-sqlite 构建并使用 CRDT(无冲突复制数据类型)。

CRDT 非常适合点对点系统,因为它们会自动处理冲突,因此用户可以离线工作,并且当他们重新连接时,更改会无缝合并。

但是,cr-sqlite 本身不会通过网络同步更改。它仅提供用于导出和合并更改的 API。您需要在设备之间手动发送这些更改。


Gun.js 用于点对点同步?

为了处理安全的点对点同步,我使用了 Gun.js,它提供了点对点分布式图形数据库。

Gun 的gun.user API 让我可以为每个组创建加密节点。组的所有更改都存储在该节点上,并且仅与组成员同步,从而保持所有内容的私密性。

当用户执行操作时,我将从 cr-sqlite 导出的更改并将它们推送到节点。当用户重新上线时,Gun 会同步新的更改,让每个人都了解最新情况。

以高性能的方式实现这一点很棘手。欲了解更多详细信息,您可以在这里查看源代码。


简化债务?

Splitwise(现在是 PeerSplit)的一个很酷的功能是“简化债务”。

具体原理是这样的:如果A欠B,B欠C,A可以直接向C付款,以减少还款次数。

在PeerSplit中,我首先计算每个人的净余额。然后我对这些余额进行排序,并建议一项一项付款,每次至少使一个人的余额为零。

这种排序可确保每个人在其设备上看到相同的还款。

这不是 100% 最优(某些群体可能仍然有最多 n-1 笔付款),但在大多数情况下效果很好。

最佳解决方案的计算结果是指数级的,并且只能节省少量费用。所以这是简单性和速度的最佳权衡!

export const groupGetPayments = (group) => {
  const payments = [];
  const balances = Object.entries(groupGetBalances(group)).map(([a, b]) => [
    b,
    a,
  ]);
  balances.sort();
  let i = 0,
    j = balances.length - 1;
  while (i  balances[j][0]) {
      payments.push({
        from: balances[i][1],
        to: balances[j][1],
        value: round(balances[j][0]),
      });
      balances[i][0]  = balances[j][0];
      balances[j][0] = 0;
    } else {
      payments.push({
        from: balances[i][1],
        to: balances[j][1],
        value: round(-balances[i][0]),
      });
      balances[j][0]  = balances[i][0];
      balances[i][0] = 0;
    }
  }
  return payments;
};

渐进式网页应用

我希望 PeerSplit 能够作为离线应用程序运行,但我不想经历构建多个本机应用程序或处理在应用程序商店上发布它们的漫长过程的麻烦。因此,选择渐进式 Web 应用程序 (PWA) 是明智的选择。

PWA 结合了网络和移动应用程序的优点,允许用户将其安装在自己的设备上,同时仍然享受离线功能。

为了将我的 Nuxt 应用程序转换为 PWA,我使用了 vite-pwa。
我在 Figma 中设计了一个 SVG 徽标,并使用它通过 vite-pwa 的资产生成器生成所有必需的 PWA 资产。

之后,我配置了 PWA 清单,vite-pwa 会自动为我设置 Service Worker。

我将 Nuxt 配置为预渲染所有路线,以便我的应用程序可以完全离线运行。


这就结束了。感谢您的阅读!

产品搜索发布

PeerSplit 刚刚在 Product Hunt 上推出!这是我的第一次发布,希望得到您的支持和反馈。

查看 Product Hunt 上的 PeerSplit

PeerSplit 是公平来源的,因此请随意在 GitHub 上贡献或提交功能请求。

How I built PeerSplit: A free, peer-to-peer expense-splitting app—from idea to launch in just eeks 塔奈维克 / 同行分裂

PeerSplit 是一款免费、本地优先的点对点应用程序,可帮助您轻松、私密地分配和跟踪团体费用。

对等分裂​​

PeerSplit 是一款免费、本地优先的点对点应用程序,可帮助您轻松、私密地分配和跟踪团体费用。

特征

  • 100% 免费 — 无需注册
  • 本地优先 — 完全离线工作
  • 跨平台 PWA — 在移动设备、台式机或笔记本电脑上使用
  • 点对点 — 与朋友协作,同时保持数据私密性
  • 简单的用户体验 — 流畅且简约的界面,不妨碍您
  • 深色和浅色模式 — 在主题之间切换以符合您的喜好
  • 导入/导出 — 从 Splitwise 导入并将数据导出到 CSV

计划的功能

  • 高级账单拆分 — 添加明细账单作为单一费用。
  • 账单扫描 — 通过拍照自动扫描和拆分账单。
  • 多币种支持 — 通过实时汇率处理不同币种的费用。
  • 交易备注和评论 — 为每笔交易添加备注和评论以保留…


在 GitHub 上查看


版本聲明 本文轉載於:https://dev.to/tanay/how-i-built-peersplit-a-free-peer-to-peer-expense-splitting-app-from-idea-to-launch-in-just- 2-weeks-386m?1如有侵犯,請聯絡[email protected]刪除
最新教學 更多>
  • 大批
    大批
    方法是可以在物件上呼叫的 fns 數組是對象,因此它們在 JS 中也有方法。 slice(begin):將陣列的一部分提取到新數組中,而不改變原始數組。 let arr = ['a','b','c','d','e']; // Usecase: Extract till index ...
    程式設計 發佈於2024-12-25
  • 插入資料時如何修復「常規錯誤:2006 MySQL 伺服器已消失」?
    插入資料時如何修復「常規錯誤:2006 MySQL 伺服器已消失」?
    插入記錄時如何解決「一般錯誤:2006 MySQL 伺服器已消失」介紹:將資料插入MySQL 資料庫有時會導致錯誤「一般錯誤:2006 MySQL 伺服器已消失」。當與伺服器的連線遺失時會出現此錯誤,通常是由於 MySQL 配置中的兩個變數之一所致。 解決方案:解決此錯誤的關鍵是調整wait_tim...
    程式設計 發佈於2024-12-25
  • 如何在 PHP 中組合兩個關聯數組,同時保留唯一 ID 並處理重複名稱?
    如何在 PHP 中組合兩個關聯數組,同時保留唯一 ID 並處理重複名稱?
    在 PHP 中組合關聯數組在 PHP 中,將兩個關聯數組組合成一個數組是常見任務。考慮以下請求:問題描述:提供的代碼定義了兩個關聯數組,$array1 和 $array2。目標是建立一個新陣列 $array3,它合併兩個陣列中的所有鍵值對。 此外,提供的陣列具有唯一的 ID,而名稱可能重疊。要求是建...
    程式設計 發佈於2024-12-25
  • 在 Go 中使用 WebSocket 進行即時通信
    在 Go 中使用 WebSocket 進行即時通信
    构建需要实时更新的应用程序(例如聊天应用程序、实时通知或协作工具)需要一种比传统 HTTP 更快、更具交互性的通信方法。这就是 WebSockets 发挥作用的地方!今天,我们将探讨如何在 Go 中使用 WebSocket,以便您可以向应用程序添加实时功能。 在这篇文章中,我们将介绍: WebSoc...
    程式設計 發佈於2024-12-25
  • HTML 格式標籤
    HTML 格式標籤
    HTML 格式化元素 **HTML Formatting is a process of formatting text for better look and feel. HTML provides us ability to format text without us...
    程式設計 發佈於2024-12-24
  • 儘管程式碼有效,為什麼 POST 請求無法擷取 PHP 中的輸入?
    儘管程式碼有效,為什麼 POST 請求無法擷取 PHP 中的輸入?
    解決PHP 中的POST 請求故障在提供的程式碼片段中:action=''而非:action="<?php echo $_SERVER['PHP_SELF'];?>";?>"檢查$_POST陣列:表單提交後使用 var_dump 檢查 $_POST 陣列的內...
    程式設計 發佈於2024-12-24
  • Bootstrap 4 Beta 中的列偏移發生了什麼事?
    Bootstrap 4 Beta 中的列偏移發生了什麼事?
    Bootstrap 4 Beta:列偏移的刪除和恢復Bootstrap 4 在其Beta 1 版本中引入了重大更改柱子偏移了。然而,隨著 Beta 2 的後續發布,這些變化已經逆轉。 從 offset-md-* 到 ml-auto在 Bootstrap 4 Beta 1 中, offset-md-*...
    程式設計 發佈於2024-12-24
  • Java中如何使用Selenium WebDriver高效率上傳檔案?
    Java中如何使用Selenium WebDriver高效率上傳檔案?
    在Java 中使用Selenium WebDriver 上傳文件:詳細指南將文件上傳到Web 應用程式是軟體測試期間的一項常見任務。 Selenium WebDriver 是一種流行的自動化框架,它提供了一種使用 Java 程式碼上傳檔案的簡單方法。然而,重要的是要明白,在 Selenium 中上傳...
    程式設計 發佈於2024-12-24
  • 使用 GNU Emacs 進行 C 語言開發
    使用 GNU Emacs 進行 C 語言開發
    Emacs is designed with programming in mind, it supports languages like C, Python, and Lisp natively, offering advanced features such as syntax highli...
    程式設計 發佈於2024-12-24
  • 如何在 PHP 中列印單引號內的變數?
    如何在 PHP 中列印單引號內的變數?
    無法直接回顯帶有單引號的變數需要在單引號字串中列印變數?直接這樣做是不可能的。 如何在單引號內列印變數:方法1:使用串聯追加 為此,請使用點運算子將變數連接到字串上:echo 'I love my ' . $variable . '.';此方法將變數追加到字串中。 方法 2:使用雙引號或者,在字串並...
    程式設計 發佈於2024-12-24
  • std::vector 與普通數組:何時效能真正重要?
    std::vector 與普通數組:何時效能真正重要?
    std::vector 與普通數組:性能評估雖然人們普遍認為std::vector 的操作與數組類似,但最近的測試對這一概念提出了挑戰。在本文中,我們將研究 std::vector 和普通數組之間的效能差異,並闡明根本原因。 為了進行測試,實施了一個基準測試,其中涉及重複建立和修改大型陣列像素物件。...
    程式設計 發佈於2024-12-24
  • 為什麼雙精確度的小數位數比宣傳的 15 位多?
    為什麼雙精確度的小數位數比宣傳的 15 位多?
    雙精度和小數位精度在電腦程式設計中,雙精度資料型態通常被假定為具有 15 位小數的近似精度。但是,某些數字表示形式(例如 1.0/7.0)在變數內部表示時似乎具有更高的精確度。本文將探討為什麼會發生這種情況,以及為什麼精確度通常被描述為小數點後 15 位左右。 內部表示IEEE 雙精度數有 53 個...
    程式設計 發佈於2024-12-24
  • 箭頭函數中的隱式回傳與明確傳回:何時需要大括號?
    箭頭函數中的隱式回傳與明確傳回:何時需要大括號?
    箭頭函數中的花括號:隱式與明確返回箭頭函數可以用兩種方式編寫:帶或不帶花括號。當大括號不存在時,函數體被認為是“簡潔體”,並且隱式傳回其中的最後一個表達式。 帶有簡潔體的隱式回傳In不帶大括號的範例:state.map(one => oneTodo(one, action))The函數立即傳回...
    程式設計 發佈於2024-12-24
  • 為什麼使用「transform:scale()」後我的文字在 Chrome 中變得模糊?
    為什麼使用「transform:scale()」後我的文字在 Chrome 中變得模糊?
    變換後Chrome 中的文字模糊:scale()在最近的Chrome 更新中,出現了一個特殊問題,即使用CSS 轉換呈現的文字:scale() 屬性顯得模糊。使用以下特定程式碼時已觀察到此問題:@-webkit-keyframes bounceIn { 0% { opacity: 0; ...
    程式設計 發佈於2024-12-24
  • 如何在 GoLang 中實作 MDC 日誌記錄?
    如何在 GoLang 中實作 MDC 日誌記錄?
    GoLang 中的 MDC LoggingJava 的 MDC Logging 依賴線程本地存儲,這在 GoLang 中不可用。然而,透過堆疊中的線程化 Context 可以實現類似的功能。 Java MDC 依賴線程本地存儲,這是 Go 所不具備的。最接近的是透過堆疊線程化 Context,這正在...
    程式設計 發佈於2024-12-23

免責聲明: 提供的所有資源部分來自互聯網,如果有侵犯您的版權或其他權益,請說明詳細緣由並提供版權或權益證明然後發到郵箱:[email protected] 我們會在第一時間內為您處理。

Copyright© 2022 湘ICP备2022001581号-3