Music-Credit Graph
Study Lab

An adaptive, local-first quiz covering the architecture, storage, Python data pipeline, K3s, queues, API, networking, and public delivery for the build.
Progress stays in this browser
Music-Credit Graph Project

Architecture and Technology Study Guide

Initial hardware: ZimaBoard 832 + 1 TB NVMe + four Raspberry Pi 3B nodes + optional x600 compute

Physical system topology
Physical system topology

Guide Map

SectionWhat it answers
1. Architecture decisionWhat runs where, and why K3s becomes reasonable with the ZimaBoard.
2. Storage and data layersHow the 1 TB NVMe is organized and which formats store which information.
3. Workload and network designHow the Wi-Fi-connected ZimaBoard coordinates wired Pi workers without becoming a bottleneck.
4. Application and public deliveryHow the API, static site, live game, and offline fallback fit together.
5. Build phasesA sequence that proves the game on small data before attempting a full catalog ingest.
6. Technology study matrixLanguages, frameworks, infrastructure tools, and small exercises to learn each one.
7. Study path and glossaryAn ordered curriculum and concise definitions.

1. Recommended Architecture Decision

Use the ZimaBoard 832 as the single always-on control and storage node. Install the operating system on its internal eMMC, mount the 1 TB NVMe as the project data volume, connect it to the home LAN with a Linux-supported USB 5 GHz Wi-Fi adapter, and run the K3s server there. The four Raspberry Pis become K3s agents and Python batch workers. The x600 remains optional heavy compute rather than a required control-plane member.

MachinePrimary responsibilitiesWhat it should not do
ZimaBoard 832K3s server; PostgreSQL; Redis/RQ; FastAPI; graph service; authoritative files; Cloudflare Tunnel; scheduling.Repeatedly send random graph reads over Wi-Fi; perform every heavy full-catalog rebuild.
Pi 3B ×4Read-only batch workers; path sampling; challenge scoring; network statistics; validation; local snapshot processing.Host the authoritative database; run many Python processes; hold K3s control-plane state.
x600Local development; monthly parsing and graph builds; multi-architecture image builds; optional heavy queue worker.Be required for daily availability.
CloudflareStatic site delivery; tunnel ingress; caching; rate limiting; durable public exports.Store the raw working catalog or replace the canonical local data store initially.

2. Physical Setup and Wi-Fi Constraints

2.1 ZimaBoard hardware

  • PCIe slot: occupied by the passive NVMe adapter and 1 TB NVMe drive.
  • Wi-Fi: use a USB adapter because the PCIe slot is no longer available. Prefer a chipset supported directly by the Linux kernel; avoid adapters that depend on fragile out-of-tree DKMS drivers.
  • Boot: keep the OS on eMMC at first. Use the NVMe for /srv/music-graph and relocate K3s data, databases, container storage, and project files there.
  • Filesystem: ext4 is the simplest choice for a single-drive experimental server. Use no RAID; protect only irreplaceable state with backups.
  • Addressing: reserve the ZimaBoard IP in eero DHCP, give it a stable hostname, disable Wi-Fi power saving, and monitor reconnection health.

2.2 What Wi-Fi changes

Traffic typeExpected behaviorDesign response
K3s control trafficLow volume; acceptable over stable Wi-Fi.Use a reserved IP and automatic reconnect. Expect the cluster scheduler to pause during Wi-Fi loss.
PostgreSQL / queue messagesSmall requests and results; normally fine.Workers communicate through APIs/queues rather than opening database files.
Monthly raw and Parquet transfersTens of gigabytes; slow but infrequent.Schedule overnight, resume transfers, verify checksums, and copy one worker at a time.
Random graph traversal from PisPotentially latency-sensitive and chatty.Do not traverse the graph over NFS. Replicate immutable graph snapshots to local Pi storage.
Public API trafficVery small relative to data ingest.Use Cloudflare Tunnel and cache popular results.

Upgrade path: when an extra switch port becomes available, wire the ZimaBoard to the shelf switch. The application architecture remains unchanged; only the network interface and IP reservation change.

3. Data Storage Architecture

Music-credit graph data flow
Music-credit graph data flow

3.1 Storage layers

LayerFormat / systemPurposeDurability
Raw sourceOriginal XML.gz snapshotsReproducible source inputs; current and previous month retained.Redownloadable, but keep checksums and manifests.
Normalized catalogPartitioned ParquetBroad artist, release, track, role, format, and credit records; supports future pivots.The most important reusable data product.
Analytical workspaceDuckDB over ParquetTransformations, joins, data-quality tests, statistics, and graph-build queries.Rebuildable from Parquet.
Application metadataPostgreSQLArtist search, aliases, challenges, scores, path cache, job records, snapshot registry.Back up regularly.
Graph snapshotCompact CSR-style binary arrays + metadataFast pathfinding with integer IDs and memory mapping.Versioned; rebuildable from normalized data.
Transient coordinationRedis + RQWork queues, leases, short-lived result caching.Treat as disposable; important results move to PostgreSQL.
Public exportJSON, SVG, optional compressed indexDaily challenges, aggregate research, cluster status, offline fallback.Replicated to Cloudflare Pages/R2.

Do not store the graph solely as relational artist-to-artist pairs. Keep a bipartite artist → release → artist representation. A release with many contributors otherwise generates a combinatorial number of pair edges. Rule-specific graphs are derived from the normalized credit records.

3.2 Suggested NVMe directory layout

/srv/music-graph/
  raw/<snapshot>/                 original XML.gz + checksums
  curated/<snapshot>/             partitioned Parquet tables
  graph/<snapshot>/<ruleset>/     immutable graph files
  postgres/                       PostgreSQL data directory
  redis/                          optional persistence
  exports/                        public JSON and SVG
  staging/                        temporary build files
  backups/                        compressed app-state backups
  manifests/                      schema, source, and checksum metadata
Allocation targetPlanning allowanceRetention policy
Raw snapshots40–60 GBCurrent + previous; older raw inputs can be redownloaded.
Curated Parquet100–200 GBSeveral schema/snapshot versions while the parser evolves.
Graph snapshots80–150 GBCurrent, previous, and a few rule sets.
PostgreSQL + indexes40–100 GBKeep app state and selected searchable metadata, not every analytical row.
Staging/build space150–250 GBClean after successful snapshot publication.
Exports, logs, backups, free spaceRemainderKeep at least 20–25% of the SSD free.

4. Runtime and Cluster Architecture

4.1 K3s node plan

Node labelMachineScheduled components
role=control, storage=nvme, arch=amd64ZimaBoard 832K3s server, API, PostgreSQL, Redis, scheduler, publisher, cloudflared, graph-query service.
role=worker, class=pi, arch=arm64Each Pi 3BOne bounded Python worker, health agent, and snapshot synchronization job.
role=heavy, class=x600, arch=amd64x600 when enabledParser, graph builder, intensive statistics, multi-arch builds, optional GPU experiments.
  • Use one K3s server with the default SQLite datastore. High availability is unnecessary for this hobby build.
  • Put /var/lib/rancher/k3s and container data on the NVMe, not the eMMC.
  • Use K3s local-path storage only on the ZimaBoard for stateful services. Do not deploy Longhorn across 1 GB Pis.
  • Use node selectors and resource requests/limits. Start with one worker process per Pi and memory limits around 200–300 MB per application worker.
  • Build linux/amd64 and linux/arm64 container images. Run all Pis on a current 64-bit Raspberry Pi OS Lite image.

4.2 Services

ServicePlacementRole
apiZimaBoardFastAPI endpoints for search, evidence, paths, challenge retrieval, and health.
graph-engineZimaBoard; library reused by workersMemory-mapped adjacency traversal; bidirectional BFS and weighted path search.
postgresZimaBoardSearch metadata, challenges, path cache, scores, job and snapshot registry.
redisZimaBoardRQ broker and short-lived cache.
schedulerK3s CronJobsDaily challenge publication, monthly ingest, cache maintenance, and backup jobs.
workerOne per PiIndependent batches: sample paths, score difficulty, validate data, estimate graph statistics.
snapshot-serverZimaBoardRead-only HTTP endpoint for versioned graph packages and checksums.
publisherZimaBoardWrites sanitized JSON/SVG exports to the public hosting layer.
cloudflaredZimaBoardOutbound-only public route to the API.

5. Data Pipeline and Snapshot Contract

  1. Register a source snapshot with its date, URLs, file sizes, checksums, parser version, and schema version.
  2. Stream the compressed XML with lxml.iterparse; never inflate the whole release file onto disk or load it into memory.
  3. Write broad normalized Parquet tables, preserving raw role text, normalized role category, track position, release/master IDs, formats, country, year, aliases, and provenance.
  4. Use DuckDB to validate counts, find duplicate keys, profile missing values, classify credits, and create stable internal integer IDs.
  5. Build one or more rule-specific bipartite graph snapshots. Produce adjacency arrays, role/flag arrays, searchable metadata, and a manifest.
  6. Run integrity tests: reciprocal adjacency, valid offsets, known fixture paths, disconnected-component checks, and reproducible hashes.
  7. Publish the snapshot to the ZimaBoard and mark it current only after validation. Keep the previous snapshot available for rollback.
  8. Synchronize the graph package to the Pis one at a time. Workers switch snapshots atomically after checksum verification.
  9. Generate path samples, daily challenges, difficulty scores, and aggregate findings. Persist accepted results in PostgreSQL.
  10. Export small public artifacts and invalidate relevant web caches.

Snapshot manifest example fields: source_month, parser_schema, ruleset, graph_format, artist_count, release_count, credit_count, file checksums, build commit, built_at, and compatibility version.

6. Game and API Architecture

6.1 Core endpoints

EndpointPurposeCaching
GET /artists/search?q=Autocomplete and disambiguation.Short public cache; normalized query key.
GET /artists/{id}Artist metadata and a small neighborhood summary.Longer cache by snapshot.
POST /pathsShortest or weighted evidence-backed route between two artists.Cache by endpoints + ruleset + snapshot.
GET /challenges/dailyCurrent curated challenge and constraints.Static/public cache.
POST /challenges/{id}/validateValidate a player-built path against graph evidence.Do not cache user-specific response.
GET /research/summaryPublished aggregate graph findings.Static/public cache.
GET /healthAPI, database, graph snapshot, queue, and worker health.No or very short cache.
  • The browser never receives database credentials, filesystem paths, or direct SQL access.
  • All public responses are snapshot-versioned and include evidence links or source identifiers.
  • The API is read-only for anonymous users except bounded game-validation requests.
  • Rate-limit path generation and cache common pairs. Reject unbounded neighborhood expansion requests.

6.2 Front end

LayerTechnologyUse
Static shellAstroProject pages, explanations, daily challenge shell, SEO, and deployment to Cloudflare Pages.
Interactive gameSvelte + TypeScriptArtist search, manual path construction, hints, state, and responsive interaction.
VisualizationSVG with selective D3 utilitiesReadable evidence chain and small local graph; avoid giant force-directed networks.
TestingPlaywrightSearch, path display, mobile interaction, offline fallback, and challenge completion tests.

7. Public-Site Delivery and Availability

ExperienceDelivery pathBehavior if home cluster is offline
Project explanationAstro on Cloudflare PagesFully available.
Daily challengePublished JSON bundled or fetched from R2/PagesAvailable using the last published challenge.
Research findingsStatic JSON/SVG exportFully available.
Arbitrary artist search and pathfindingBrowser → Cloudflare → Tunnel → FastAPI on ZimaBoardGraceful offline message; static modes remain available.
Cluster-status displaySmall periodically published artifactShows last update time rather than failing.

Security boundary: Cloudflare Tunnel creates outbound connections from the ZimaBoard, so the router needs no inbound port forwarding. Restrict CORS to the site domain, validate inputs, enforce timeouts and maximum search depth, and expose only the API service—not PostgreSQL, Redis, K3s, SSH, or storage shares.

8. Repository and Development Workflow

music-credit-graph/
  apps/api/                 FastAPI application
  apps/frontend/            Astro + Svelte project
  packages/catalog/         XML parsing and normalization
  packages/graph_core/      graph format and algorithms
  packages/game_rules/      configurable connection rules
  packages/workers/         RQ jobs and research tasks
  infra/ansible/             operating-system provisioning
  infra/k8s/                 Kustomize manifests
  data/contracts/            schemas, fixtures, manifests
  tests/                     unit, integration, property, browser
Development concernRecommendation
Python environmentpyproject.toml with uv; lock dependencies; build reproducible containers.
QualityRuff for formatting/linting, mypy for selected typed boundaries, pytest for unit and integration tests.
Data testingTiny checked-in XML fixtures, schema tests, count checks, and known-path golden tests.
ContainersDocker Buildx multi-platform images for amd64 and arm64; push to GHCR.
DeploymentAnsible provisions hosts; Kustomize applies environment-specific Kubernetes manifests.
CIGitHub Actions for tests and image builds; deployment remains explicit at first.
SecretsKubernetes Secrets initially; SOPS + age when the repository and deployment mature.
VersioningEvery result records source snapshot, graph ruleset, schema version, and application commit.

9. Build Phases

PhaseDeliverableExit criterion
0. Hardware and baselineNVMe mounted; Wi-Fi stable; Ansible inventory; fresh OS images; monitoring.All five nodes survive reboot and are reachable by hostname.
1. Cluster skeletonK3s server on Zima; four Pi agents; sample multi-arch Python worker.A job is scheduled on every Pi and returns a result.
2. Small-data vertical sliceHandmade or collection-sized catalog; FastAPI path search; Astro/Svelte result screen.A complete artist → release → artist route works end to end.
3. Durable data modelParquet schemas, role taxonomy, internal IDs, snapshot manifests, PostgreSQL search.Changing a game ruleset requires only a graph rebuild, not an XML reparse.
4. Medium graphThousands to low millions of credits; local Pi snapshots; RQ challenge generation.Workers generate reproducible challenges without network graph reads.
5. Full dump pipelineFull monthly ingest and graph build, preferably accelerated by x600.A validated snapshot can be published and rolled back.
6. Public betaCloudflare Pages, Tunnel API, caching, rate limiting, offline fallback.The public site fails gracefully when the ZimaBoard is disconnected.
7. Research and pivotsNew rule sets, collection mode, hidden-contributor puzzles, network findings.A new mode is built from normalized data without changing ingestion.

10. Technology Study Matrix

TechnologyCategoryRole in projectPriorityFirst study exercise
PythonPrimary languageParsing, graph algorithms, API, workers, tests.CoreBuild a bidirectional BFS over a small bipartite graph.
SQLQuery languagePostgreSQL app queries and DuckDB transformations.CoreWrite a query that finds releases with multiple qualifying performers.
TypeScriptFront-end languageTyped UI state and API contracts.CoreRender a typed path response as evidence cards.
Bash / YAMLOperations languagesAutomation, container entrypoints, Ansible and Kubernetes configuration.Working knowledgeAutomate a health check and deployment variable override.
AnsibleProvisioningUsers, SSH, packages, hostnames, mounts, K3s installation.Core infraRebuild one Pi from a clean image without manual package installation.
K3s / KubernetesOrchestrationScheduling, service discovery, CronJobs, resource limits, rollout.Core infraDeploy one global worker and pin PostgreSQL to the ZimaBoard.
Docker / BuildxPackagingReproducible amd64/arm64 services.Core infraPublish one image that runs on ZimaBoard and Pi.
PostgreSQLTransactional databaseSearch metadata, challenges, caches, game state.Core dataAdd an indexed normalized-name search table.
Redis + RQQueue/cacheDistribute independent Python jobs to Pi workers.Core computeQueue 1,000 pair-scoring jobs and collect results safely.
ParquetColumnar file formatCompact normalized catalog and batch interchange.Core dataWrite and read partitioned credits by snapshot or role category.
DuckDBAnalytical SQL engineQuery Parquet, normalize data, validate builds.Core dataCalculate credit counts and missing-role profiles directly from Parquet.
lxml.iterparseStreaming XMLProcess very large compressed XML without loading it into RAM.Core dataParse a fixture while clearing elements to keep memory flat.
NumPy / SciPy sparseNumerical storageCompact integer arrays and CSR-style adjacency.Core graphSerialize offsets and neighbor arrays, then memory-map them.
NetworkXGraph reference toolPrototype and test algorithms on small subgraphs.SupportingCompare your custom BFS results with NetworkX fixtures.
FastAPI + PydanticAPI frameworkValidated public endpoints and typed response schemas.Core appCreate /paths with bounded inputs and structured errors.
AstroStatic web frameworkFast project pages and Cloudflare Pages deployment.Core front endCreate an always-available daily-challenge page.
SvelteInteractive UISearch, path construction, hints, state, and transitions.Core front endBuild a path editor that alternates artist and release cards.
SVG / D3 utilitiesVisualizationEvidence chains and small local graphs.SupportingDraw a responsive horizontal/vertical path without force layout.
Cloudflare Pages / TunnelPublic deliveryStatic hosting and secure outbound API ingress.Core deliveryServe a local health endpoint through a private tunnel hostname.
pytest / PlaywrightTestingParser, graph, API, and browser regression coverage.Core qualityGolden-test a path and complete the same challenge in a browser test.
DaskOptional distributed computeLarger parameter sweeps or DataFrame experiments after the RQ pipeline works.LaterCompare a batch calculation with RQ and Dask implementations.

11. Suggested Study Sequence

OrderFocus
1. Python data contractsDataclasses/Pydantic, pyproject, pytest, small XML fixtures.
2. Discogs domain modelArtists, releases, masters, credits, track credits, aliases, and source provenance.
3. Streaming ingestionlxml.iterparse, incremental writes, memory profiling, and restartable jobs.
4. Parquet and DuckDBColumnar schemas, partitions, analytical SQL, and data-quality checks.
5. Graph representationBipartite graphs, integer IDs, adjacency arrays, BFS, Dijkstra, hub penalties.
6. PostgreSQL and APIIndexes, autocomplete, caches, Pydantic schemas, FastAPI testing.
7. Containers and multi-architectureDockerfiles, Buildx, amd64/arm64 images, resource constraints.
8. Ansible and K3sRepeatable hosts, node labels, storage placement, CronJobs, rollouts.
9. Distributed jobsRQ semantics, retries, idempotency, leases, result validation, local snapshots.
10. Astro/Svelte game UISearch, path editing, evidence display, accessibility, responsive SVG.
11. Public delivery and securityCloudflare Tunnel, caching, rate limits, offline fallback, backups.
12. Research methodsSampling bias, approximate centrality, challenge difficulty, reproducibility.

12. Decisions Intentionally Deferred

QuestionDefault nowRevisit when
Final game mechanicAutomatic path plus evidence; manual relay can follow.The medium-size graph is playable and path quality is understood.
Album artworkNo dependency; generated or typographic release tiles.Discogs and rights constraints are clarified.
SQLite vs PostgreSQLPostgreSQL from the start for app state.Only reconsider if operational simplicity becomes more important than learning.
RQ vs DaskRQ for independent jobs.A workload needs distributed DataFrame/array execution rather than queued tasks.
Full catalog on day oneNo; use staged subsets.Parser, normalized schema, and graph integrity tests are stable.
Wired ZimaBoardWi-Fi accepted with local graph replication.A switch port or shelf layout makes wiring easy.
Public arbitrary searchAfter static daily/curated mode works.Rate limiting, caching, and API availability are proven.

13. Compact Glossary

TermMeaning here
Bipartite graphA graph with two node types—artists and releases—where edges only cross between types.
CSRCompressed sparse row: compact offset and neighbor arrays used for efficient adjacency access.
Memory mapOpening a file as if it were an array while the OS loads only needed pages.
ParquetCompressed columnar files optimized for analytics rather than transactional updates.
DuckDBAn embedded analytical database that can query Parquet directly.
SnapshotAn immutable, versioned set of graph and metadata files built from one source month and ruleset.
Idempotent jobA task that can safely run again without duplicating or corrupting its result.
Control planeThe K3s components that schedule and manage workloads; hosted on the ZimaBoard.
Agent nodeA machine that runs scheduled containers; each Pi is an agent.
RulesetConfiguration defining which roles, release types, dates, or tracks count as valid connections.
ProvenanceThe source snapshot and record identifiers that explain where a connection came from.
Static fallbackPrepublished content that remains available when the live home API is offline.

14. Primary Documentation to Bookmark

  • Discogs API Terms of Use
  • Discogs developer documentation
  • Discogs public data snapshots
  • ZimaBoard 832 product specifications
  • Zima PCIe to NVMe adapter
  • K3s requirements and resource profiling
  • K3s storage documentation
  • Ansible documentation
  • PostgreSQL documentation
  • Redis documentation
  • RQ documentation
  • DuckDB documentation
  • Apache Parquet documentation
  • FastAPI documentation
  • Astro documentation
  • Svelte documentation
  • Cloudflare Tunnel documentation
  • Cloudflare Pages documentation