# gianse/cifras-capela architecture

> Architecture diagram of the GitHub repository gianse/cifras-capela, generated by GitDiagram from its file tree, README and a sample of source files (last updated 2026-09-26). It is an AI-made overview: check details against the source.

- Interactive diagram: https://gitdiagram.com/gianse/cifras-capela
- Repository: https://github.com/gianse/cifras-capela

## Overview

Minha Biblioteca de Cifras is an installable, offline-capable songbook for a music team. A user signs in, browses or searches the library, opens a song, and reads it with transposition, capo, and presentation controls; administrators can edit or import songs and save them to the shared library. Separate workflows manage playlists, sharing, and PDF export. The frontend service/repository layer selects the Worker API and local cache, while the Worker routes API requests to authentication, song, playlist, user, and YouTube handlers. Major capabilities are represented from the README; several page and handler internals were not sampled, so their detailed wiring is omitted.

Main entry points: [`worker/src/index.ts`](https://github.com/gianse/cifras-capela/blob/main/worker/src/index.ts) (API router), [`frontend/src/services/song-service.ts`](https://github.com/gianse/cifras-capela/blob/main/frontend/src/services/song-service.ts) (Song service), [`frontend/src/pages/HomePage.tsx`](https://github.com/gianse/cifras-capela/blob/main/frontend/src/pages/HomePage.tsx) (Library browsing), [`frontend/src/pages/SongPage.tsx`](https://github.com/gianse/cifras-capela/blob/main/frontend/src/pages/SongPage.tsx) (Song reader)

## Diagram (Mermaid)

```mermaid
flowchart TD

subgraph group_app["App and Access"]
  node_app["App routes<br/>[App.tsx]"]
  node_auth["Session access<br/>[useAuth.ts]"]
  node_pwa["Offline PWA<br/>[main.tsx]"]
end

subgraph group_library["Library and Songs"]
  node_home["Library browsing<br/>[HomePage.tsx]"]
  node_libraryhook["Library state<br/>[useLibrary.ts]"]
  node_search["Song search<br/>[search-engine.ts]"]
  node_songpage["Song reader<br/>[SongPage.tsx]"]
  node_songhook["Load song<br/>[useSong.ts]"]
  node_parser["ChordPro parser<br/>[index.ts]"]
  node_reader["Reader controls<br/>[ReaderControls.tsx]"]
  node_transpose["Transpose chords<br/>[useTranspose.ts]"]
  node_songservice["Song service<br/>[song-service.ts]"]
  node_repository["Worker repository"]
  node_cache[("Local song cache")]
end

subgraph group_creation["Editing and Import"]
  node_editor["Song editor<br/>[EditorPage.tsx]"]
  node_importpage["Song import<br/>[ImportPage.tsx]"]
  node_importers["Format importers<br/>[index.ts]"]
  node_export["PDF export<br/>[pdf.ts]"]
end

subgraph group_setlists["Playlists"]
  node_playlistpages["Playlist pages<br/>[PlaylistsPage.tsx]"]
  node_playlistpage["Setlist reader<br/>[PlaylistPage.tsx]"]
  node_playliststorage[("Playlist storage<br/>[playlists.ts]")]
end

subgraph group_backend["Worker Backend"]
  node_worker["API router<br/>[index.ts]"]
  node_songsapi["Song API<br/>[songs.ts]"]
  node_playlistsapi["Playlist API<br/>[playlists.ts]"]
  node_authapi["Authentication API<br/>[auth.ts]"]
  node_usersapi["User API<br/>[users.ts]"]
  node_youtubeapi["YouTube search API<br/>[youtube.ts]"]
end

node_team(("Music team"))
node_d1[("Cloudflare D1")]
node_youtube["YouTube Data API"]

node_team -->|"opens"| node_app
node_app -->|"checks session"| node_auth
node_app -->|"routes to"| node_home
node_home -->|"loads library"| node_libraryhook
node_libraryhook -->|"requests index"| node_songservice
node_home -->|"searches songs"| node_search
node_home -->|"opens song"| node_songpage
node_songpage -->|"loads content"| node_songhook
node_songhook -->|"requests source"| node_songservice
node_songservice -->|"delegates access"| node_repository
node_repository -->|"requests songs"| node_worker
node_repository -->|"reads and writes"| node_cache
node_songservice -->|"parses source"| node_parser
node_songpage -->|"shows controls"| node_reader
node_reader -->|"sets key"| node_transpose
node_editor -->|"saves song"| node_songservice
node_importpage -->|"imports source"| node_importers
node_importpage -->|"reviews import"| node_editor
node_editor -->|"exports PDF"| node_export
node_playlistpages -->|"manages playlists"| node_playliststorage
node_playlistpage -->|"loads setlist"| node_playliststorage
node_playlistpage -->|"exports setlist"| node_export
node_playlistpage -->|"navigates songs"| node_songpage
node_worker -->|"dispatches auth"| node_authapi
node_worker -->|"dispatches songs"| node_songsapi
node_worker -->|"dispatches playlists"| node_playlistsapi
node_worker -->|"dispatches users"| node_usersapi
node_worker -->|"dispatches search"| node_youtubeapi
node_authapi -->|"checks accounts"| node_d1
node_songsapi -->|"reads and writes"| node_d1
node_playlistsapi -->|"reads and writes"| node_d1
node_usersapi -->|"manages accounts"| node_d1
node_youtubeapi -.->|"searches videos"| node_youtube
node_pwa -->|"enables offline use"| node_team

click node_app "https://github.com/gianse/cifras-capela/blob/main/frontend/src/App.tsx"
click node_auth "https://github.com/gianse/cifras-capela/blob/main/frontend/src/hooks/useAuth.ts"
click node_home "https://github.com/gianse/cifras-capela/blob/main/frontend/src/pages/HomePage.tsx"
click node_libraryhook "https://github.com/gianse/cifras-capela/blob/main/frontend/src/hooks/useLibrary.ts"
click node_search "https://github.com/gianse/cifras-capela/blob/main/frontend/src/lib/search/search-engine.ts"
click node_songpage "https://github.com/gianse/cifras-capela/blob/main/frontend/src/pages/SongPage.tsx"
click node_songhook "https://github.com/gianse/cifras-capela/blob/main/frontend/src/hooks/useSong.ts"
click node_parser "https://github.com/gianse/cifras-capela/blob/main/frontend/src/lib/parser/index.ts"
click node_reader "https://github.com/gianse/cifras-capela/blob/main/frontend/src/components/song/ReaderControls.tsx"
click node_transpose "https://github.com/gianse/cifras-capela/blob/main/frontend/src/hooks/useTranspose.ts"
click node_songservice "https://github.com/gianse/cifras-capela/blob/main/frontend/src/services/song-service.ts"
click node_repository "https://github.com/gianse/cifras-capela/blob/main/frontend/src/services/worker-repository.ts"
click node_cache "https://github.com/gianse/cifras-capela/blob/main/frontend/src/services/worker-repository.ts"
click node_editor "https://github.com/gianse/cifras-capela/blob/main/frontend/src/pages/EditorPage.tsx"
click node_importpage "https://github.com/gianse/cifras-capela/blob/main/frontend/src/pages/ImportPage.tsx"
click node_importers "https://github.com/gianse/cifras-capela/blob/main/frontend/src/lib/import/index.ts"
click node_export "https://github.com/gianse/cifras-capela/blob/main/frontend/src/lib/export/pdf.ts"
click node_playlistpages "https://github.com/gianse/cifras-capela/blob/main/frontend/src/pages/PlaylistsPage.tsx"
click node_playlistpage "https://github.com/gianse/cifras-capela/blob/main/frontend/src/pages/PlaylistPage.tsx"
click node_playliststorage "https://github.com/gianse/cifras-capela/blob/main/frontend/src/lib/storage/playlists.ts"
click node_worker "https://github.com/gianse/cifras-capela/blob/main/worker/src/index.ts"
click node_songsapi "https://github.com/gianse/cifras-capela/blob/main/worker/src/api/songs.ts"
click node_playlistsapi "https://github.com/gianse/cifras-capela/blob/main/worker/src/api/playlists.ts"
click node_authapi "https://github.com/gianse/cifras-capela/blob/main/worker/src/api/auth.ts"
click node_usersapi "https://github.com/gianse/cifras-capela/blob/main/worker/src/api/users.ts"
click node_youtubeapi "https://github.com/gianse/cifras-capela/blob/main/worker/src/api/youtube.ts"
click node_pwa "https://github.com/gianse/cifras-capela/blob/main/frontend/src/main.tsx"

classDef toneNeutral fill:#f8fafc,stroke:#334155,stroke-width:1.5px,color:#0f172a
classDef toneBlue fill:#dbeafe,stroke:#2563eb,stroke-width:1.5px,color:#172554
classDef toneAmber fill:#fef3c7,stroke:#d97706,stroke-width:1.5px,color:#78350f
classDef toneMint fill:#dcfce7,stroke:#16a34a,stroke-width:1.5px,color:#14532d
classDef toneRose fill:#ffe4e6,stroke:#e11d48,stroke-width:1.5px,color:#881337
classDef toneIndigo fill:#e0e7ff,stroke:#4f46e5,stroke-width:1.5px,color:#312e81
classDef toneTeal fill:#ccfbf1,stroke:#0f766e,stroke-width:1.5px,color:#134e4a
class node_app,node_auth,node_pwa toneBlue
class node_home,node_libraryhook,node_search,node_songpage,node_songhook,node_parser,node_reader,node_transpose,node_songservice,node_repository,node_cache,node_d1 toneAmber
class node_editor,node_importpage,node_importers,node_export,node_youtube toneMint
class node_playlistpages,node_playlistpage,node_playliststorage toneRose
class node_worker,node_songsapi,node_playlistsapi,node_authapi,node_usersapi,node_youtubeapi,node_team toneIndigo
```

## Components

### App and Access

- [App routes](https://github.com/gianse/cifras-capela/blob/main/frontend/src/App.tsx): `frontend/src/App.tsx`
- [Session access](https://github.com/gianse/cifras-capela/blob/main/frontend/src/hooks/useAuth.ts): `frontend/src/hooks/useAuth.ts`
- [Offline PWA](https://github.com/gianse/cifras-capela/blob/main/frontend/src/main.tsx): `frontend/src/main.tsx`

### Library and Songs

- [Library browsing](https://github.com/gianse/cifras-capela/blob/main/frontend/src/pages/HomePage.tsx): `frontend/src/pages/HomePage.tsx`
- [Library state](https://github.com/gianse/cifras-capela/blob/main/frontend/src/hooks/useLibrary.ts): `frontend/src/hooks/useLibrary.ts`
- [Song search](https://github.com/gianse/cifras-capela/blob/main/frontend/src/lib/search/search-engine.ts): `frontend/src/lib/search/search-engine.ts`
- [Song reader](https://github.com/gianse/cifras-capela/blob/main/frontend/src/pages/SongPage.tsx): `frontend/src/pages/SongPage.tsx`
- [Load song](https://github.com/gianse/cifras-capela/blob/main/frontend/src/hooks/useSong.ts): `frontend/src/hooks/useSong.ts`
- [ChordPro parser](https://github.com/gianse/cifras-capela/blob/main/frontend/src/lib/parser/index.ts): `frontend/src/lib/parser/index.ts`
- [Reader controls](https://github.com/gianse/cifras-capela/blob/main/frontend/src/components/song/ReaderControls.tsx): `frontend/src/components/song/ReaderControls.tsx`
- [Transpose chords](https://github.com/gianse/cifras-capela/blob/main/frontend/src/hooks/useTranspose.ts): `frontend/src/hooks/useTranspose.ts`
- [Song service](https://github.com/gianse/cifras-capela/blob/main/frontend/src/services/song-service.ts): `frontend/src/services/song-service.ts`
- [Worker repository](https://github.com/gianse/cifras-capela/blob/main/frontend/src/services/worker-repository.ts): `frontend/src/services/worker-repository.ts`
- [Local song cache](https://github.com/gianse/cifras-capela/blob/main/frontend/src/services/worker-repository.ts): `frontend/src/services/worker-repository.ts`

### Editing and Import

- [Song editor](https://github.com/gianse/cifras-capela/blob/main/frontend/src/pages/EditorPage.tsx): `frontend/src/pages/EditorPage.tsx`
- [Song import](https://github.com/gianse/cifras-capela/blob/main/frontend/src/pages/ImportPage.tsx): `frontend/src/pages/ImportPage.tsx`
- [Format importers](https://github.com/gianse/cifras-capela/blob/main/frontend/src/lib/import/index.ts): `frontend/src/lib/import/index.ts`
- [PDF export](https://github.com/gianse/cifras-capela/blob/main/frontend/src/lib/export/pdf.ts): `frontend/src/lib/export/pdf.ts`

### Playlists

- [Playlist pages](https://github.com/gianse/cifras-capela/blob/main/frontend/src/pages/PlaylistsPage.tsx): `frontend/src/pages/PlaylistsPage.tsx`
- [Setlist reader](https://github.com/gianse/cifras-capela/blob/main/frontend/src/pages/PlaylistPage.tsx): `frontend/src/pages/PlaylistPage.tsx`
- [Playlist storage](https://github.com/gianse/cifras-capela/blob/main/frontend/src/lib/storage/playlists.ts): `frontend/src/lib/storage/playlists.ts`

### Worker Backend

- [API router](https://github.com/gianse/cifras-capela/blob/main/worker/src/index.ts): `worker/src/index.ts`
- [Song API](https://github.com/gianse/cifras-capela/blob/main/worker/src/api/songs.ts): `worker/src/api/songs.ts`
- [Playlist API](https://github.com/gianse/cifras-capela/blob/main/worker/src/api/playlists.ts): `worker/src/api/playlists.ts`
- [Authentication API](https://github.com/gianse/cifras-capela/blob/main/worker/src/api/auth.ts): `worker/src/api/auth.ts`
- [User API](https://github.com/gianse/cifras-capela/blob/main/worker/src/api/users.ts): `worker/src/api/users.ts`
- [YouTube search API](https://github.com/gianse/cifras-capela/blob/main/worker/src/api/youtube.ts): `worker/src/api/youtube.ts`

### Other components

- **Music team**
- **Cloudflare D1**
- **YouTube Data API**

## Connections

- Music team → App routes: opens
- App routes → Session access: checks session
- App routes → Library browsing: routes to
- Library browsing → Library state: loads library
- Library state → Song service: requests index
- Library browsing → Song search: searches songs
- Library browsing → Song reader: opens song
- Song reader → Load song: loads content
- Load song → Song service: requests source
- Song service → Worker repository: delegates access
- Worker repository → API router: requests songs
- Worker repository → Local song cache: reads and writes
- Song service → ChordPro parser: parses source
- Song reader → Reader controls: shows controls
- Reader controls → Transpose chords: sets key
- Song editor → Song service: saves song
- Song import → Format importers: imports source
- Song import → Song editor: reviews import
- Song editor → PDF export: exports PDF
- Playlist pages → Playlist storage: manages playlists
- Setlist reader → Playlist storage: loads setlist
- Setlist reader → PDF export: exports setlist
- Setlist reader → Song reader: navigates songs
- API router → Authentication API: dispatches auth
- API router → Song API: dispatches songs
- API router → Playlist API: dispatches playlists
- API router → User API: dispatches users
- API router → YouTube search API: dispatches search
- Authentication API → Cloudflare D1: checks accounts
- Song API → Cloudflare D1: reads and writes
- Playlist API → Cloudflare D1: reads and writes
- User API → Cloudflare D1: manages accounts
- YouTube search API → YouTube Data API: searches videos
- Offline PWA → Music team: enables offline use
