Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ Tools for DJs and the people who book them, built on the AT Protocol. Each tool

| Tool | What it is | Built with |
| --------------------------------- | ---------------------------------------------------------------------------------------------------------------------- | ------------------------- |
| [Local Network](apps/web) | The website at localnetwork.computer: promoters find local DJs, DJs keep a profile, bookings run in private spaces | SvelteKit, atproto spaces |
| [Local Network](apps/web) | The website at localnetwork.computer: promoters find local DJs, DJs keep a profile, bookings run in member-only spaces | SvelteKit, atproto spaces |
| [locallibrary](apps/locallibrary) | A command line tool and terminal player that keeps rekordbox USB drives in sync, backed up and edited | Rust |
| [localtoolbox](apps/localtoolbox) | A Chrome extension for digging on SoundCloud: track lists, download links, artists' socials, and a queue to batch them | Svelte, Manifest V3 |

Expand Down
6 changes: 3 additions & 3 deletions apps/web/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

Promoters find local DJs who fit their shows. DJs (called _projects_: a solo DJ, a b2b duo, a group, or a collective) get a profile built around what promoters book on: sound, distance, slot, room size, and budget. Fans follow DJs and see where they play next.

All data lives on the AT Protocol. Public profiles are ordinary atproto records; everything private (requests, staff roles, the audit log, booking threads, personal planners) lives in [atproto spaces](https://atproto.com/blog/atproto-spaces-alpha), the protocol's permissioned-data extension. Published projects, the DJ stats, sets, press kits, shows and follows their managers and fans publish, and the few Bluesky and userinput.app records the site reads are indexed by [HappyView](https://happyview.dev), an AppView whose Lua scripts answer directory search and the show matcher and serve those records to the site. The app keeps its own SQLite index only for space data, and can rebuild it from the network. Every public record is read through HappyView, never straight from a PDS or Bluesky's AppView (see [Directory](#directory) for the few exceptions); writes go to the PDS.
All data lives on the AT Protocol. Public profiles are ordinary atproto records; everything else (requests, staff roles, the audit log, booking threads, personal planners) lives in [atproto spaces](https://atproto.com/blog/atproto-spaces-alpha), the protocol's permissioned-data extension, where each space's read policy decides who can read it. Published projects, the DJ stats, sets, press kits, shows and follows their managers and fans publish, and the few Bluesky and userinput.app records the site reads are indexed by [HappyView](https://happyview.dev), an AppView whose Lua scripts answer directory search and the show matcher and serve those records to the site. The app keeps its own SQLite index only for space data, and can rebuild it from the network. Every public record is read through HappyView, never straight from a PDS or Bluesky's AppView (see [Directory](#directory) for the few exceptions); writes go to the PDS.

> Atproto spaces is an alpha (released 2026). This app is built against `@atproto/*@0.0.0-spaces-alpha-20261022141228` and the [0016 spaces proposal](https://github.com/bluesky-social/proposals/tree/main/0016-permissioned-data). Expect breaking changes upstream; all versions are pinned.

Expand Down Expand Up @@ -102,8 +102,8 @@ All data lives on the AT Protocol. Public profiles are ordinary atproto records;
| Press kits' private part, requests and grants | One space per press kit under the root | Root (content, grants), askers | Managers, granted |
| Press kit drafts (`computer.localnetwork.epk.draft`) | Each manager's repo in the project's backstage space | Managers | The project's managers |
| Press kit view receipts | The app's database only | The app | The project's managers |
| People in acts, parties and venues (`computer.localnetwork.people.*`) | One space per performer, party or venue under the root | Root, for its people or staff | Its people, staff |
| Directory listing status (`computer.localnetwork.listing.status`) | The same space | Root, after staff action | Its people, staff |
| People in acts, parties and venues (`computer.localnetwork.people.*`) | One space per performer, party or venue under the root | Root, for its people or staff | Members (staff via app) |
| Directory listing status (`computer.localnetwork.listing.status`) | The same space | Root, after staff action | Members (staff via app) |
| Bluesky display names (`app.bsky.actor.profile`) | The account's own public repo | The account, in any Bluesky app | Admins, via HappyView |
| Managers' Bluesky follows (`app.bsky.graph.follow`) | The manager's public repo | The manager, in any Bluesky app | The app, via HappyView |
| The bug report space (`app.userinput.space`) | Its owner's public repo on userinput.app | userinput.app | The app, via HappyView |
Expand Down
2 changes: 1 addition & 1 deletion apps/web/src/lib/components/ProjectForm.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@
<PerformerFields values={shown} {sets} />

{#if showDetails}
<FormSection title="Private booking details" description="Only signed-in members see these. They're stored in a private atproto space, not your public repo.">
<FormSection title="Private booking details" description="Only this project's managers and Local Network staff see these, and people you let into one of your press kits.">
<div class="grid gap-4 sm:grid-cols-2">
<div>
<label class="label" for="bookingEmail">Booking email</label>
Expand Down
2 changes: 1 addition & 1 deletion apps/web/src/lib/sign-in.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ export const CAN: { text: string; covers: string[] }[] = [
},
{ text: 'Upload photos and tracklists', covers: ['blob'] },
{
text: 'Keep your inquiries, requests, drafts and planner private',
text: 'Keep your inquiries, requests, drafts and planner where only the people involved can read them',
covers: [
'computer.localnetwork.space.performer',
'computer.localnetwork.space.booking',
Expand Down
2 changes: 1 addition & 1 deletion apps/web/src/routes/+layout.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,6 @@
<!-- Signed out, /report sends people on to GitHub, so the link says so. -->
<a class="menu-link" href="/report?from={encodeURIComponent(page.url.pathname)}">{data.viewer ? 'Report a bug' : 'Report a bug on GitHub'}</a>
<button type="button" class="menu-link inline-flex min-h-9 items-center gap-2" aria-pressed={hotkeys.enabled} onclick={() => setHotkeysEnabled(!hotkeys.enabled)}>Keyboard shortcuts: {hotkeys.enabled ? 'on' : 'off'}</button>
<span class="text-fg-subtle sm:ml-auto">Records on the AT Protocol · private data in atproto spaces</span>
<span class="text-fg-subtle sm:ml-auto">Records on the AT Protocol · private data in spaces only their members can read</span>
</div>
</footer>
6 changes: 3 additions & 3 deletions apps/web/src/routes/about/+page.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -5,19 +5,19 @@
<div class="container-page flex flex-col gap-8 py-10 sm:gap-10 sm:py-14">
<SectionHeader level={1} eyebrow="How it works" title="Built on the AT Protocol" />
<div class="prose prose-site">
<p>Local Network stores its data on the <a href="https://atproto.com">AT Protocol</a>, not in a private database. Public profiles are ordinary atproto records; everything private uses <a href="https://atproto.com/blog/atproto-spaces-alpha">atproto spaces</a>, the protocol's permissioned-data extension. The app keeps a local index for fast search, and it can rebuild that index from the network.</p>
<p>Local Network stores its data on the <a href="https://atproto.com">AT Protocol</a>, not in a private database. Public profiles are ordinary atproto records. Everything else sits in <a href="https://atproto.com/blog/atproto-spaces-alpha">atproto spaces</a>, the protocol's permissioned-data extension, and each space's read policy decides who can read it. The app keeps a local index for fast search, and it can rebuild that index from the network.</p>

<h2 id="projects">Projects</h2>
<p>A <em>project</em> is a DJ act: a solo DJ, a b2b duo, a group, or a whole collective. Published projects are <code>computer.localnetwork.project</code> records in the Local Network root account's public repo. Only the root account writes them, after an admin adds a project or a moderator approves a request, so nobody can change a profile without review.</p>

<h2 id="requests">Requests and claims</h2>
<p>Anyone with an atproto account can list a new project, claim one an admin added, or propose changes to a project they manage. Each request is written <strong>into your own repo</strong>, inside the root account's private moderation space. Only staff can read that space. Decisions are recorded by the root account in the same space.</p>
<p>Anyone with an atproto account can list a new project, claim one an admin added, or propose changes to a project they manage. Each request is written <strong>into your own repo</strong>, inside the root account's moderation space, which only staff can read. Decisions are recorded by the root account in the same space.</p>

<h2 id="spaces">Spaces we use</h2>
<ul>
<li><strong>Audit log</strong>: anyone may write their own audit entries; staff read.</li>
<li><strong>Moderation</strong>: anyone may file requests; staff read.</li>
<li><strong>Staff</strong>: role assignments, written by the root account.</li>
<li><strong>Staff</strong>: role assignments, written by the root account; staff read.</li>
<li><strong>Industry</strong>: private booking details, readable by staff. Everyone else sees them through the site, in a press kit they've been let into.</li>
<li><strong>Booking threads</strong>: one space per inquiry, shared only by the promoter and the project's managers.</li>
<li><strong>Your planner</strong>: a personal space under your own DID, like bookmarks. We keep no copy.</li>
Expand Down
6 changes: 4 additions & 2 deletions apps/web/src/routes/privacy/+page.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,10 @@
<h2>Press kits</h2>
<p>A press kit's public part is a record in Local Network's repo that anyone can read. The rest sits in a space under Local Network's account that only the project's managers, Local Network, and the people they let in can read. Asking to see it shares your handle and any message you write with the project's managers. Each person let in gets a record in that space saying so, which any of the managers can have deleted to take access away. Drafts of a press kit sit in each manager's repo in a space only the project's current managers can read.</p>
<p>When someone let in opens a press kit on this site, its project's managers see who and when. Local Network keeps that receipt for {data.retentionDays} days, and any of the managers can delete it sooner. The audit log keeps a record that the press kit was viewed, but not by whom.</p>
<h2>Just you and the other party</h2>
<p>Booking threads are readable only by the promoter and the project's managers. Your planner is readable only by you.</p>
<h2>Acts, parties and venues</h2>
<p>Each act, party and venue has a space under Local Network's account with who's in it, their roles, invites and requests to join, and whether it's listed in the directory. Only its people are members of the space, and staff see it through this site.</p>
<h2>Booking threads and your planner</h2>
<p>Each booking thread is a space under Local Network's account whose only members are the promoter and the project's managers. Local Network indexes the thread so the site can show it to them. Your planner is readable only by you.</p>
<h2>On our server</h2>
<p>We keep a search index derived from the records above, OAuth tokens needed to act on your behalf (encrypted at rest by your host's disk encryption), hashed browser session tokens, and an outbox of audit entries waiting to be written. Signing out revokes our OAuth session.</p>
<p>Your inbox lives only on our server. Each item says what happened and where (a new inquiry or message in one of your booking threads, say) but not what anyone wrote. Read items are deleted after 90 days and unread ones after 180.</p>
Expand Down
Loading