-
-
Notifications
You must be signed in to change notification settings - Fork 0
Project Structure
Ferran Buireu edited this page Jun 13, 2026
·
2 revisions
ContribKit is a pnpm-workspace monorepo with three components that share design tokens.
ContribKit/
├── web/ Astro + TypeScript on Cloudflare Workers (contribkit.app + API)
├── app/ Flutter iOS & Android app with home-screen widgets
├── shared/ Single source of truth: palettes, shapes, usernames (JSON)
├── scripts/ Repo tooling (e.g. sync-shared-assets.mjs)
└── .github/ CI/CD workflows
| Directory | Component | Stack |
|---|---|---|
web/ |
contribkit.app + SVG/JSON API | Astro · TypeScript · Cloudflare Workers |
app/ |
iOS & Android app with widgets | Flutter · Riverpod · RevenueCat |
shared/ |
Palettes, shapes, usernames | JSON consumed by both apps |
domain/
value-objects/ Username, Year, ContributionLevel, Palette, ShapeKind, calendar-labels
entities/ ContributionDay, ContributionCalendar (types.ts)
repositories/ ContributionsRepository (interface only)
services/ calendar-grid, svg-geometry, cell-shapes, dates, SvgRenderer type
failures/ Failure union + constructors + isFailure
application/
use-cases/ fetchContributions, renderCalendarSvg, loadInitialContributions
http/ failure-http (statusFor, messageFor)
infrastructure/
github/ createGithubHtmlContributionsRepository (HTML scraping)
rendering/ svgStringRenderer
logging/ better-stack-logger, logServerError
ui/
components/ Astro components (core/, grid/, error/, icons/, features…)
utils/ page-init, render/state, roving, url/cookie, mulberry, …
styles/ @layer-based global CSS
pages/
index.astro landing page (SSR + client interactivity)
api/ contributions.ts, health.ts
user/ [username].svg.ts
404.astro, 500.astro, legal-notice/privacy/terms
middleware.ts rate limiting + security headers
Most layers carry a colocated CONTEXT.md documenting their rules. See Architecture and Web Application.
domain/ Entities, value objects, repository interfaces, services, failures
application/ Use cases (fetch, export, tips)
infrastructure/ GitHub repo, asset repos, export (png/svg/markdown), persistence, purchases
ui/ Features (viewer, customizer, export, tip), widgets, theme, DI
See Mobile App.
The single source of truth for data used by both apps:
| File | Contents |
|---|---|
palettes.json |
11 color palettes (5 levels each) |
shapes.json |
5 cell shapes |
usernames.json |
Suggested usernames |
Edit the JSON here — never edit the copies under
app/assets/.
-
web imports these directly via the
@sharedalias at build time. -
app (Flutter) can only bundle assets inside its own package, so it uses generated copies in
app/assets/*.json. They are regenerated:- automatically on commit (lefthook
pre-commitrunsscripts/sync-shared-assets.mjs --stagewhen ashared/*.jsonis staged), - in CI before the release build,
- manually with
pnpm sync:assets.
- automatically on commit (lefthook
Repo-wide Node scripts, invoked by Git hooks and CI:
| Script | Purpose |
|---|---|
sync-shared-assets.mjs |
Copies shared/*.json → app/assets/*.json (--stage re-stages them). Exposed as pnpm sync:assets. |
auto-scope.mjs |
Blocks a commit that touches both app/ and web/, keeping per-package changelogs clean. |
See Git Hooks for how these run.
-
Package manager: pnpm workspaces (
pnpm-workspace.yaml) -
Git hooks: lefthook (
lefthook install) - Commits: Conventional Commits, enforced by commitlint
-
Releases: semantic-release per component (
web-vX.Y.Z/app-vX.Y.Ztags) - CI: path-filtered workflows that only run when their component changes — see CI/CD
- Git hooks: lefthook runs formatting, linting, and commit-message checks locally — see Git Hooks