diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
new file mode 100644
index 0000000..8405b57
--- /dev/null
+++ b/CONTRIBUTING.md
@@ -0,0 +1,51 @@
+# Contributing to DS Chat
+
+Thanks for considering a contribution.
+
+## Reporting bugs and requesting features
+
+Open an issue on this project's issue tracker. Include steps to reproduce
+for a bug, or the problem you're trying to solve for a feature request —
+that's usually more useful than a proposed solution.
+
+## Development setup
+
+See the root [README.md](README.md)'s Quickstart, plus
+[backend/README.md](backend/README.md) and
+[frontend/README.md](frontend/README.md) for the full local dev setup
+(Postgres, Redis, Python venv, migrations, the Vite dev server).
+[ARCHITECTURE.md](ARCHITECTURE.md) covers the overall system design if
+you're orienting yourself before a larger change.
+
+## Before opening a pull request
+
+- **Tests**: run `pytest` in `backend/` for any backend change, and add
+ tests for new behavior rather than just the happy path — see
+ `backend/README.md`'s "Run tests" section. For frontend changes, run
+ `npx tsc -b` in `frontend/` and confirm `npm run build` succeeds.
+- **Style**: match the conventions already in the file you're editing
+ rather than introducing a new pattern — this codebase doesn't have a
+ separate style guide beyond "look at what's already there."
+- **Scope**: smaller, focused PRs are easier to review than large ones
+ that mix unrelated changes.
+
+## Contributor terms
+
+By submitting a contribution (a pull request, patch, or similar), you
+agree that:
+
+1. Your contribution is licensed under the project's own license,
+ AGPL-3.0-or-later ([LICENSE](LICENSE)), and
+2. You grant the project's maintainer(s) a perpetual, worldwide,
+ non-exclusive right to also relicense your contribution under different
+ terms — for example, as part of a separately-licensed commercial
+ offering built on this project.
+
+This keeps the option of a future dual-licensed (open-source +
+commercial) version of the project available, without requiring a
+separate signed agreement for every contribution.
+
+*This is a lightweight starting point, not a substitute for legal advice —
+if you're contributing something substantial, or maintaining a fork with
+your own commercial plans, it's worth having this reviewed by a lawyer
+rather than relying on the paragraph above alone.*
diff --git a/DEPLOYMENT.md b/DEPLOYMENT.md
index 209a4b8..24abc94 100644
--- a/DEPLOYMENT.md
+++ b/DEPLOYMENT.md
@@ -132,15 +132,16 @@ sudo -u ds-chat ssh-keygen -t ed25519 -f /srv/ds-chat/.ssh/id_ed25519 -N ""
sudo cat /srv/ds-chat/.ssh/id_ed25519.pub
```
-Add that public key as a **read-only deploy key** on the Gitea repo
-(Settings → Deploy Keys), then:
+Add that public key as a **read-only deploy key** in your git host's repo
+settings (deploy keys are supported by GitHub, GitLab, Gitea, and most
+others — look for "Deploy Keys" under the repo's Settings), then:
```bash
-sudo -u ds-chat ssh-keyscan git.darksingularity.org >> /srv/ds-chat/.ssh/known_hosts
-sudo -u ds-chat git clone git@git.darksingularity.org:DarkSingularity/ds-chat.git /srv/ds-chat
+sudo -u ds-chat ssh-keyscan >> /srv/ds-chat/.ssh/known_hosts
+sudo -u ds-chat git clone git@:/ds-chat.git /srv/ds-chat
```
-(If your Gitea's SSH is on a non-default port, adjust the clone URL and
+(If your git host's SSH is on a non-default port, adjust the clone URL and
`ssh-keyscan -p ` accordingly.)
**Alternative: a personal/deployment-user access token instead of a deploy
@@ -148,7 +149,7 @@ key** — skip the `.ssh`/`ssh-keygen`/`ssh-keyscan` commands above entirely
and clone over HTTPS with the token embedded in the URL:
```bash
-sudo -u ds-chat git clone https://@git.darksingularity.org/DarkSingularity/ds-chat.git /srv/ds-chat
+sudo -u ds-chat git clone https://@//ds-chat.git /srv/ds-chat
```
The token then lives in plaintext in `/srv/ds-chat/.git/config` (`git
@@ -232,7 +233,16 @@ admin sets it up.
`/ws`) whenever that directory exists — that's what lets Nginx Proxy
Manager forward the whole domain to one port with no custom path routing.
+Before building, copy `frontend/.env.example` to `frontend/.env.production`
+and set `VITE_SOURCE_URL` to wherever *your* copy of the repo lives — see
+that file's own comment for why this matters (AGPL-3.0 source-availability
+compliance). Vite bakes this in at build time, so it needs to be in place
+before `npm run build` runs, and needs re-running after any future change
+to it.
+
```bash
+sudo -u ds-chat cp /srv/ds-chat/frontend/.env.example /srv/ds-chat/frontend/.env.production
+sudo -u ds-chat nano /srv/ds-chat/frontend/.env.production # set VITE_SOURCE_URL
sudo -u ds-chat bash -c 'cd /srv/ds-chat/frontend && npm ci && npm run build'
```
diff --git a/LICENSE b/LICENSE
index be3f7b2..1b644a1 100644
--- a/LICENSE
+++ b/LICENSE
@@ -629,8 +629,8 @@ to attach them to the start of each source file to most effectively
state the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
-
- Copyright (C)
+ DS Chat, a self-hosted, real-time team chat service.
+ Copyright (C) 2026 Keith Smith
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
diff --git a/frontend/.env.example b/frontend/.env.example
new file mode 100644
index 0000000..2fd1846
--- /dev/null
+++ b/frontend/.env.example
@@ -0,0 +1,6 @@
+# Shown as the "Source code" link in the app's About screen -- required
+# for AGPL-3.0 section 13 compliance once you deploy this (a link so users
+# interacting with the app over the network can get the actual source,
+# including any modifications you've made). Point this at wherever *your*
+# copy of the repo actually lives, not the upstream project.
+VITE_SOURCE_URL=https://example.com/your-org/ds-chat
diff --git a/frontend/README.md b/frontend/README.md
index 3760f9d..6f14e7d 100644
--- a/frontend/README.md
+++ b/frontend/README.md
@@ -112,7 +112,7 @@ src/
LoginPage.tsx, SignupPage.tsx, ForgotPasswordPage.tsx, ResetPasswordPage.tsx
ChatShellPage.tsx, AdminPage.tsx, HelpPage.tsx
- styles/tokens.css design tokens (DarkSingularity theme: colors, spacing, etc.)
+ styles/tokens.css design tokens (default theme: colors, spacing, etc.)
sw.ts custom service worker (injectManifest): app-shell
precache + NetworkFirst runtime caching, push/notificationclick
handlers, SKIP_WAITING messaging for the update-prompt flow
diff --git a/frontend/src/components/AboutModal.tsx b/frontend/src/components/AboutModal.tsx
index bb0eab3..81eb5b7 100644
--- a/frontend/src/components/AboutModal.tsx
+++ b/frontend/src/components/AboutModal.tsx
@@ -10,8 +10,10 @@ interface AboutModalProps {
// users remotely through a computer network, you should also make sure
// that it provides a way for users to get its source... its interface
// could display a 'Source' link" -- this modal is that link, not just a
-// courtesy credits screen.
-const SOURCE_URL = 'https://git.darksingularity.org/DarkSingularity/ds-chat'
+// courtesy credits screen. Deliberately not a hardcoded URL: whoever
+// deploys this needs to point it at *their* copy of the repo (including
+// any modifications), not the upstream project -- see frontend/.env.example.
+const SOURCE_URL = import.meta.env.VITE_SOURCE_URL as string | undefined
export function AboutModal({ onClose }: AboutModalProps) {
return (
@@ -39,11 +41,13 @@ export function AboutModal({ onClose }: AboutModalProps) {
.