Trên GitHub, JanDeDobbeleer/punch đã đạt 19 sao, ngôn ngữ TypeScript.
Tóm tắt dựng từ metadata GitHub của chính dự án — chưa có bài review TopGit. Trang sẽ tự động cập nhật khi bài review đầy đủ được xuất bản.
VÌ SAO CHƯA CÓ REVIEW
TopGit viết bài đầy đủ cho repo có nhiều sao nhất và được yêu cầu nhiều nhất. Trang này là snapshot trong thời gian chờ — xem README gốc ở tab READ ME.
A personal time-tracking app for freelancers and independent consultants. Log hours to projects and customers, track day-rate earnings, book flat-fee services, and generate branded PDF timesheets — all in a single-page app hosted on Azure.
Try it first — open Settings (gear icon) and toggle Demo mode to explore the app with realistic fictional data, no account needed.
Screenshots
Desktop
Clock
Day detail
Projects
Customers
Services
Settings
Mobile
Calendar
Drawer
Day detail
Features
Monthly calendar — colour-coded day cells with hour labels and coloured pips per project; click any day to open the detail panel
Projects — link each project to a customer, set a day rate (or multiple rate periods), and see total logged hours + earnings per project
Services — fixed-rate bookings (workshops, training, etc.) charged at a flat per-session rate
Customers — group projects under customers with a colour identity; per-customer earnings and project summaries
Earnings view — filter by customer, project, or service; choose month/quarter/year or a custom range; bar chart breakdown
Timesheet export — generate a branded PDF timesheet and a zip of all attachments for a customer or project, entirely client-side (no round-trip to the server)
Azure Blob Storage sync — full state stored as one JSON blob; optimistic concurrency via ETags so two browser tabs never silently overwrite each other
File attachments — attach receipts or documents to any time entry; files are stored in Azure Blob Storage and downloaded via short-lived SAS URLs
Demo mode — explore a full week of fictional demo data without touching your real data; switch back at any time from Settings
Responsive mobile layout — full-width calendar with collapsible drawer navigation and a floating action button for quick entry
Architecture
Browser (React 19 + TypeScript + Vite SPA)
│
├── /.auth/login/github GitHub sign-in via Azure SWA built-in auth
│
├── /api/state GET / PUT — full state as one JSON blob (ETag concurrency)
└── /api/attachments POST (SAS upload ticket) / GET (SAS download URL) / DELETE
│
Azure Functions (Node 22, managed, co-hosted with SWA)
│
Azure Blob Storage
├── container: state (state.json — the whole data model)
└── container: attachments (<entryId>/<attachmentId>)
Auth: Every route (/* and /api/*) is gated behind the owner role in staticwebapp.config.json. The GitHub identity you invite gets that role via az staticwebapp users invite. Unauthenticated visitors are redirected straight to the GitHub login page.
Self-hosting on Azure
Punch is designed to be hosted by a single user. The entire stack runs on Azure services with a generous free tier.
1 — Prerequisites
Azure CLI installed and signed in (az login)
A GitHub account (used for authentication)
This repository forked to your own GitHub account
2 — Create the storage account
# Create a resource group (pick any region)
az group create --name rg-punch --location westeurope
# Create a storage account (name must be globally unique, 3-24 lowercase chars)
az storage account create \
--name <your-storage-account> \
--resource-group rg-punch \
--sku Standard_LRS \
--kind StorageV2
# Create the two containers
az storage container create --name state --account-name <your-storage-account>
az storage container create --name attachments --account-name <your-storage-account>
Note: The owner role is a custom role defined in staticwebapp.config.json. It is separate from the Standard-plan password-protection feature — the Free tier supports it via the az staticwebapp users commands above.
6 — Enable CORS on blob storage (for attachment downloads)
The timesheet export downloads attachment files directly from Blob Storage in the browser. Add a CORS rule so the request isn't blocked:
az storage cors add \
--account-name <your-storage-account> \
--services b \
--methods GET HEAD \
--origins "https://<your-swa-hostname>.azurestaticapps.net" \
--allowed-headers "*" \
--exposed-headers "*" \
--max-age 3600
Replace <your-swa-hostname> with the auto-generated hostname shown by:
az staticwebapp show --name punch-app --resource-group rg-punch --query defaultHostname -o tsv
If you add a custom domain later, run the command again for that origin.
7 — Deploy
Push to main — the GitHub Actions workflow (.github/workflows/deploy.yml) builds and deploys automatically. The app will be live at the URL from step 6 within a few minutes.
Local development
# Install frontend dependencies
npm install
# Install API dependencies
cd api && npm install && cd ..
# Copy API settings for local Azurite / emulator use
cp api/local.settings.json.example api/local.settings.json
# Edit local.settings.json if you want to point at real Azure storage instead of Azurite
# Start Azurite (Azure Storage emulator) in a separate terminal
npx azurite --silent --location .azurite
# Start the API (in a separate terminal)
cd api && npm run watch
# Start the frontend dev server
npm run dev
The frontend runs at http://localhost:5173. Because there is no SWA auth proxy locally, set SKIP_AUTH_CHECK=1 in api/local.settings.json — the API will synthesise a dummy owner identity so all endpoints work without a real GitHub sign-in.
Trang TopGit này là một snapshot — tab "Readme" hiển thị nguyên văn README của repo (đã bỏ link, giữ ảnh). Repo GitHub ở github.com/JanDeDobbeleer/punch là nguồn chính thức.
JanDeDobbeleer/punch có bao nhiêu sao?
JanDeDobbeleer/punch có 19 sao GitHub — tải lại trang để xem số mới nhất, hoặc xem trực tiếp github.com/JanDeDobbeleer/punch. TopGit phản chiếu số sao của GitHub nhưng không cam kết đến từng phút.
JanDeDobbeleer/punch có phải mã nguồn mở không?
TopGit chưa ghi nhận license cho JanDeDobbeleer/punch. Phần lớn repo public trên GitHub là mã nguồn mở, nhưng điều khoản khác nhau từng repo — mở file LICENSE để xác nhận.
JanDeDobbeleer/punch còn đang phát triển không?
Commit gần nhất trên JanDeDobbeleer/punch là 30 ngày trước (theo timestamp GitHub). Repo có 0 fork — một chỉ báo về mức độ quan tâm của cộng đồng.
JanDeDobbeleer/punch là gì?
JanDeDobbeleer/punch (JanDeDobbeleer/punch) là dự án TypeScript TopGit theo dõi. Tính tới lần đồng bộ gần nhất, repo có 19 sao.
JanDeDobbeleer/punch viết bằng ngôn ngữ gì?
JanDeDobbeleer/punch chủ yếu viết bằng TypeScript. Trường "language" của GitHub dựa trên phần lớn byte ở nhánh mặc định.
Đọc đầy đủ README ở tab phía trên.
Muốn nghe thêm một ý kiến về punch?
Hỏi một AI đọc được trang này — một cú bấm là có ngay nhận định về punch.