Projects live at URLs, have owners, and are edited together live
A project is only ever at /p/<id>/<slug>; / is the index of the projects
you own or edit. Every project has an owner, who can name editors;
anyone with the link can view. Every edit saves itself, one request in
flight at a time, as a patch of the leaves that changed, and a websocket
(channels + daphne) carries presence and each committed write to
everyone else in the project. The first write to a leaf wins, and the
loser is told.
Undo is per person: a step undoes only if the leaves it touched still
hold what it left, so it never takes a collaborator's work with it.
Named snapshots replace saving, and restore as an ordinary write.
An empty symbol now survives the leaf round trip with `:nodes {}`.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
c17ee138f2
commit
6a53adb5e0
31 changed files with 1918 additions and 158 deletions
39
clips/migrations/0008_owners_editors_leaf_seq.py
Normal file
39
clips/migrations/0008_owners_editors_leaf_seq.py
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
from django.conf import settings
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
def orphans(apps, schema_editor):
|
||||
# Every project has an owner, and none of the ones saved before owners did.
|
||||
apps.get_model("clips", "Project").objects.all().delete()
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
("clips", "0007_symbols_not_timelines"),
|
||||
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RunPython(orphans, migrations.RunPython.noop),
|
||||
migrations.AddField(
|
||||
model_name="leaf",
|
||||
name="seq",
|
||||
field=models.PositiveBigIntegerField(
|
||||
default=0, help_text="the project seq of the write that last changed it"),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name="project",
|
||||
name="editors",
|
||||
field=models.ManyToManyField(blank=True, related_name="shared_projects",
|
||||
to=settings.AUTH_USER_MODEL),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name="project",
|
||||
name="owner",
|
||||
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE,
|
||||
related_name="projects", to=settings.AUTH_USER_MODEL),
|
||||
preserve_default=False,
|
||||
),
|
||||
]
|
||||
Loading…
Add table
Add a link
Reference in a new issue