{"id":24736533,"url":"https://github.com/phukon/clack","last_synced_at":"2026-02-28T02:01:40.405Z","repository":{"id":229464512,"uuid":"754413198","full_name":"phukon/clack","owner":"phukon","description":"Clack syncs your writing ✍🏽 activity from Notion and Google Docs, and comes with an AI assistant and a Notion-style WYSIWYG editor","archived":false,"fork":false,"pushed_at":"2024-07-15T18:25:32.000Z","size":9156,"stargazers_count":14,"open_issues_count":0,"forks_count":3,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-08-03T00:23:49.406Z","etag":null,"topics":["cloudflare-worker","postgresql","vercel-ai-sdk"],"latest_commit_sha":null,"homepage":"https://clack.rkph.me","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"agpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/phukon.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2024-02-08T01:49:27.000Z","updated_at":"2025-05-18T08:43:12.000Z","dependencies_parsed_at":"2024-03-28T12:30:57.410Z","dependency_job_id":"8c95e857-004e-452f-ba21-3e69037a3f45","html_url":"https://github.com/phukon/clack","commit_stats":null,"previous_names":["phukon/clack"],"tags_count":12,"template":false,"template_full_name":null,"purl":"pkg:github/phukon/clack","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/phukon%2Fclack","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/phukon%2Fclack/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/phukon%2Fclack/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/phukon%2Fclack/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/phukon","download_url":"https://codeload.github.com/phukon/clack/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/phukon%2Fclack/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29922713,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-27T19:37:42.220Z","status":"online","status_checked_at":"2026-02-28T02:00:07.010Z","response_time":90,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["cloudflare-worker","postgresql","vercel-ai-sdk"],"created_at":"2025-01-27T21:26:10.858Z","updated_at":"2026-02-28T02:01:40.370Z","avatar_url":"https://github.com/phukon.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003c!--\n\u003cdiv\n  style={{\n    display: 'flex',\n    height: '100%',\n    width: '100%',\n    alignItems: 'center',\n    justifyContent: 'center',\n    flexDirection: 'column',\n    backgroundImage: 'linear-gradient(to bottom, #dbf4ff, #fff1f1)',\n    fontSize: 60,\n    letterSpacing: -2,\n    fontWeight: 700,\n    textAlign: 'center',\n  }}\n\u003e\n  \u003cimg style={{ maxWidth: '100%', maxHeight: '120px' }}\n    alt=\"Clack Logo\" src=\"https://clack.rkph.me/_next/image?url=%2Flogo.png\u0026w=750\u0026q=100\" /\u003e\n  \u003cdiv\n  \u003e\n    Clack\n  \u003c/div\u003e\n\n\u003c/div\u003e\n--\u003e\n\u003ca href=\"https://clack.rkph.me\"\u003e\n  \u003cimg alt=\"Clack is an open-source writing activity tracker with a Notion-style rich text editor.\" src=\"https://github.com/phukon/clack/assets/60285613/53a92208-e160-47b5-a442-71c802c6a7f7\"\u003e\n\u003c/a\u003e\n\n\n\u003ch3 align=\"center\"\u003eClack\u003c/h3\u003e\n\n\u003cp align=\"center\"\u003e\n    Track your\nwriting progress effortlessly\n    \u003cbr /\u003e\n    \u003ca href=\"https://clack.rkph.me\"\u003e\u003cstrong\u003eLearn more »\u003c/strong\u003e\u003c/a\u003e\n    \u003cbr /\u003e\n    \u003cbr /\u003e\n    \u003ca href=\"#introduction\"\u003e\u003cstrong\u003eIntroduction\u003c/strong\u003e\u003c/a\u003e ·\n    \u003ca href=\"#features\"\u003e\u003cstrong\u003eFeatures\u003c/strong\u003e\u003c/a\u003e ·\n    \u003ca href=\"#tech-stack\"\u003e\u003cstrong\u003eTech Stack\u003c/strong\u003e\u003c/a\u003e ·\n    \u003ca href=\"#author\"\u003e\u003cstrong\u003eAuthor\u003c/strong\u003e\u003c/a\u003e\n\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\n  \u003ca href=\"https://twitter.com/kungfukon\"\u003e\n   \u003cimg alt=\"X (formerly Twitter) Follow\" src=\"https://img.shields.io/twitter/follow/kungukon\"\u003e\n  \u003c/a\u003e\n  \u003ca href=\"https://github.com/phukon/clack/blob/main/LICENSE\"\u003e\n   \u003cimg alt=\"GitHub License\" src=\"https://img.shields.io/github/license/phukon/clack\"\u003e\n  \u003c/a\u003e\n\u003c/p\u003e\n\n\u003cbr/\u003e\n\n## Introduction\n\nClack syncs your writing activity from Notion and Google Docs, and comes with an AI assistant and a Notion-style WYSIWYG editor.\n\n## Features\n\n- Encrypted Notes\n- Google Integration\n- Notion Integration\n- Notion Widget\n- AI Writing Assistant\n- Notion-style WYSIWYG editor\n- 14 Heatmap Themes\n\n## Tech Stack\n\n- [Next.js](https://nextjs.org/) – framework\n- [TypeScript](https://www.typescriptlang.org/) – language\n- [Tailwind](https://tailwindcss.com/) – CSS\n- [Vercel KV](https://vercel.com/docs/storage/vercel-kv) – redis\n- [Cloudflare Workers KV](https://www.cloudflare.com/en-in/developer-platform/workers-kv/) – Low latency KV data store\n- [Prisma](https://www.prisma.io/) - orm\n- [Neon](https://neon.tech/) – database\n- [NextAuth.js](https://next-auth.js.org/) – auth\n- [Stripe](https://stripe.com/) – payments\n- [Resend](https://resend.com/) – emails\n- [Vercel](https://vercel.com/) – deployments\n\n## Author\n\n- Riki Phukon ([@kungfukon](https://twitter.com/kungfukon))\n\n\n\n\n\n### Nuances\n- Always use `finally` in async worksloads if a UI state depends on it!!. Otherwise, the UI will forever be stuck and never update after the async work is done.\n\n\n### Cron Job\n- A vercel cronjob triggers at 0000hrs UTC to set the word-count reference.\n- A second cronjob from an EC2 instance triggers at 0530hrs IST or 0000hrs UTC for redundancy.\n\n## Encryption\n**Type** : `AES-256-CBC`\n- The key should be **32 bytes** or **256 bits** in length!!\n- Initialization Vector should be **16 bytes** or **128 bits**.\n\n## Contribution logic\n- Update wordcount Ref if a document is removed.\n- Missing contributions are showed as blank on the canvas. No need to add blank contribution data to keep contributions array filled with consecutive dates.\n- Works only if the day comes before the current system date.\n- Non-consecutive dates after the current system date are not rendered. \n\n## ⚠ Documents\n- Added specific error handling for Prisma's known request errors\n- Checked for error code 'P2002' to identify unique constraint violations\n- Checked if the 'url' field was involved in the constraint violation\n- Provided a custom error message for duplicate URL scenarios\n- Added checks for unauthorized request on another User's documents.\n\nThis change enhances the reliability and user experience of the addDocument function by ensuring that duplicate URLs are handled in a more informative and user-friendly manner.\n\n### Prisma\n- After schema changes run `npx prisma migrate dev` \n- Reset KV store by sending a GET request on the KV worker url with the param `?sayonara` and a populated `X-Custom-Auth-Key` header.\n\n\n- User registers\n- Generate a new verification token using the email they used to register\n- Send verification token to that email\n- Inside the email send the route '/auth/new-verification'\n- Add that route to the public route\n- That route renders the new verification form\n- Inside that page, use the search params to fetch the token --\u003e\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fphukon%2Fclack","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fphukon%2Fclack","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fphukon%2Fclack/lists"}