The catalog is optimized for 1k+ app records, daily GitHub sync, cleanup automation, and a web-based submit flow. The source of truth is still one file per app:
data/apps/<slug>.yml
Generated JSON is derived at build time and is not committed.
Each block has a clear owner:
| Block | Owner | Notes |
|---|---|---|
source |
submit flow / curator | Canonical repo identity. |
app |
contributor / curator | Human-facing app metadata. |
stack |
contributor / curator, taxonomy-backed | Technical classification. |
github |
GitHub Actions | GitHub-shaped API metadata. Preserve GitHub field names. |
health |
build / cleanup automation | Computed listing status. Do not hand-edit. |
curation |
curator / AI-assisted draft | Review notes and learning value. |
GitHub API fields are stored under github with their original names
(full_name, html_url, stargazers_count, pushed_at, etc.). The site
normalizes them only when generating data/generated/*.json.
schemaVersion: 1
id: github:immich-app/immich
slug: immich
source:
provider: github
owner: immich-app
repo: immich
url: https://github.com/immich-app/immich
app:
name: Immich
description: Self-hosted photo and video backup solution.
category: media
projectType: production
platforms:
- ios
- android
- web
tags:
- self-hosted
- backup
- photos
distribution:
channels:
- type: app-store
platform: ios
label: App Store
url: https://apps.apple.com/app/example
verified: false
- type: play-store
platform: android
label: Play Store
url: https://play.google.com/store/apps/details?id=app.example
verified: false
- type: github-releases
platform: android
label: APK releases
url: https://github.com/owner/repo/releases
verified: false
stack:
primary: flutter
families:
- cross-platform
- backend
technologies:
- id: flutter
role: mobile-framework
- id: dart
role: language
- id: nodejs
role: backend-runtime
- id: typescript
role: backend-language
- id: postgresql
role: database
github:
repository:
full_name: immich-app/immich
html_url: https://github.com/immich-app/immich
homepage: https://immich.app
description: High performance self-hosted photo and video management solution.
fork: false
archived: false
disabled: false
private: false
visibility: public
default_branch: main
language: TypeScript
topics:
- photos
- backup
- self-hosted
license:
key: agpl-3.0
name: GNU Affero General Public License v3.0
spdx_id: AGPL-3.0
stargazers_count: 102744
watchers_count: 102744
forks_count: 5799
open_issues_count: 500
subscribers_count: 1200
size: 123456
created_at: 2022-02-03T00:00:00Z
updated_at: 2026-06-07T00:00:00Z
pushed_at: 2026-06-06T00:00:00Z
languages:
TypeScript: 1234567
Dart: 456789
latestRelease:
tag_name: v1.120.0
name: v1.120.0
draft: false
prerelease: false
published_at: 2026-06-01T00:00:00Z
html_url: https://github.com/immich-app/immich/releases/tag/v1.120.0
activity:
monthlyCommits:
- month: 2026-01
commits: 180
- month: 2026-02
commits: 220
- month: 2026-03
commits: 190
- month: 2026-04
commits: 230
- month: 2026-05
commits: 200
- month: 2026-06
commits: 210
totalCommitsKnown: 12000
contributorsKnown: 500
openPullRequests: 40
files:
readme: true
contributing: true
codeOfConduct: true
security: true
issueTemplates: true
pullRequestTemplate: true
labels:
- name: good first issue
open_issues_count: 12
- name: help wanted
open_issues_count: 30
sync:
syncedAt: 2026-06-07T00:00:00Z
apiVersion: rest-v3
source: github-actions
health:
status: active
tier: curated
visibility: listed
cleanupCandidate: false
staleReason: null
curation:
reviewed: false
reviewedBy: null
reviewedAt: null
bestFor:
- Studying production-scale mobile architecture.
caveats:
- Large multi-service codebase.Form inputs and validation should use registry IDs, not free text:
data/taxonomy/stacks.yml
data/taxonomy/platforms.yml
data/taxonomy/categories.yml
Important distinction:
app.platformsmeans where the app runs:ios,android,web.stack.primarymeans the discovery family:flutter,react-native,ios,android,capacitor.stack.technologiesmeans actual technology inside the repo.
app.distribution.channels lists where users can install or download the app.
It is separate from github.repository.homepage because an app can have many
install channels.
Supported channel types:
| Type | Use for |
|---|---|
app-store |
Apple App Store listings. |
play-store |
Google Play Store listings. |
fdroid |
F-Droid package pages. |
github-releases |
GitHub Releases pages with binaries/APKs. |
apk |
Direct APK downloads. |
testflight |
Apple TestFlight invites. |
website |
Official download pages. |
snapcraft |
Snap packages. |
flathub |
Flatpak packages. |
microsoft-store |
Microsoft Store listings. |
other |
Any install channel that does not fit above. |
Example:
app:
distribution:
channels:
- type: fdroid
platform: android
label: F-Droid
url: https://f-droid.org/packages/org.example.app/
verified: true
- type: apk
platform: android
label: APK
url: https://example.com/download/app.apk
verified: false
notes: Direct download from the maintainer website.verified: true means a curator confirmed the link belongs to the canonical
project. Submit form drafts should default to verified: false.
Build output is split by use case:
data/generated/apps.full.json # complete normalized records
data/generated/apps.index.json # lightweight list/search records
data/generated/apps.json # compatibility alias for current site code
The browser should use index-shaped data for list pages and full data only on detail pages.
The web submit page should:
- Accept a GitHub repository URL.
- Fetch GitHub repository metadata.
- Store that metadata under
github.repositoryusing GitHub field names. - Infer
app,stack, andplatformsas editable form fields. - Generate
data/apps/<slug>.yml. - Open a PR after validation.
Contributor-facing forms should not require users to know YAML field names.
Cleanup should change health.visibility or open a PR; it should not
immediately delete records.
Suggested policy:
| Tier | Rule |
|---|---|
curated |
stargazers_count >= 500 or activity in at least 4 of last 6 months. |
listed |
Public, non-archived, at least 50 stars. |
experimental |
Lower-confidence but still useful. |
hidden |
Archived, unavailable, or stale beyond policy. |
Deletion is reserved for spam, malware, duplicates, or non-app repositories.