Initial public commit
Daybook: a self-hosted, multi-user Django + DRF app where agents, scripts, or people publish artifacts and each logged-in user browses their own time-ordered, label-filterable feed. This squashes prior local development history (kept privately on a separate branch) into a single clean starting point for the public repository. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
commit
940a703cd7
62 changed files with 5755 additions and 0 deletions
27
artifacts/migrations/0001_initial.py
Normal file
27
artifacts/migrations/0001_initial.py
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
initial = True
|
||||
|
||||
dependencies = []
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name="Artifact",
|
||||
fields=[
|
||||
("id", models.CharField(max_length=8, primary_key=True, serialize=False)),
|
||||
("persona", models.CharField(db_index=True, max_length=80)),
|
||||
("title", models.CharField(max_length=200)),
|
||||
("kind", models.CharField(choices=[("html_fragment", "HTML fragment"), ("html_full", "Full HTML"), ("markdown", "Markdown"), ("deck", "Deck"), ("image", "Image"), ("pdf", "PDF"), ("binary", "Binary")], max_length=20)),
|
||||
("theme", models.CharField(blank=True, max_length=40)),
|
||||
("day", models.DateField(db_index=True)),
|
||||
("created_at", models.DateTimeField(auto_now_add=True)),
|
||||
("path", models.CharField(max_length=500)),
|
||||
("original_kind", models.CharField(max_length=20)),
|
||||
("tags", models.JSONField(blank=True, default=list)),
|
||||
("source_prompt", models.TextField(blank=True)),
|
||||
],
|
||||
options={"ordering": ["-created_at"]},
|
||||
),
|
||||
]
|
||||
|
|
@ -0,0 +1,41 @@
|
|||
# Generated by Django 5.2.15 on 2026-06-10 15:14
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
def fill_existing_source_names(apps, schema_editor):
|
||||
Artifact = apps.get_model('artifacts', 'Artifact')
|
||||
for artifact in Artifact.objects.filter(source_name=''):
|
||||
artifact.source_name = artifact.persona
|
||||
artifact.save(update_fields=['source_name'])
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('artifacts', '0001_initial'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='artifact',
|
||||
name='metadata',
|
||||
field=models.JSONField(blank=True, default=dict),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='artifact',
|
||||
name='source_id',
|
||||
field=models.CharField(blank=True, max_length=120),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='artifact',
|
||||
name='source_name',
|
||||
field=models.CharField(blank=True, max_length=120),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='artifact',
|
||||
name='source_type',
|
||||
field=models.CharField(choices=[('agent', 'Agent'), ('person', 'Person'), ('system', 'System')], default='agent', max_length=20),
|
||||
),
|
||||
migrations.RunPython(fill_existing_source_names, migrations.RunPython.noop),
|
||||
]
|
||||
20
artifacts/migrations/0003_tagcolor.py
Normal file
20
artifacts/migrations/0003_tagcolor.py
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
# Generated by Django 5.2.15 on 2026-07-23 06:42
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('artifacts', '0002_artifact_metadata_artifact_source_id_and_more'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='TagColor',
|
||||
fields=[
|
||||
('name', models.CharField(max_length=40, primary_key=True, serialize=False)),
|
||||
('color', models.CharField(max_length=20)),
|
||||
],
|
||||
),
|
||||
]
|
||||
16
artifacts/migrations/0004_rename_persona_to_source.py
Normal file
16
artifacts/migrations/0004_rename_persona_to_source.py
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
from django.db import migrations
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
("artifacts", "0003_tagcolor"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RenameField(
|
||||
model_name="artifact",
|
||||
old_name="persona",
|
||||
new_name="source",
|
||||
),
|
||||
]
|
||||
24
artifacts/migrations/0005_add_owner_nullable.py
Normal file
24
artifacts/migrations/0005_add_owner_nullable.py
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
import django.db.models.deletion
|
||||
from django.conf import settings
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||
("artifacts", "0004_rename_persona_to_source"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name="artifact",
|
||||
name="owner",
|
||||
field=models.ForeignKey(
|
||||
null=True,
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
related_name="artifacts",
|
||||
to=settings.AUTH_USER_MODEL,
|
||||
),
|
||||
),
|
||||
]
|
||||
27
artifacts/migrations/0006_backfill_owner.py
Normal file
27
artifacts/migrations/0006_backfill_owner.py
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
from django.db import migrations
|
||||
|
||||
|
||||
def backfill_owner(apps, schema_editor):
|
||||
User = apps.get_model("auth", "User")
|
||||
Artifact = apps.get_model("artifacts", "Artifact")
|
||||
|
||||
first_superuser = User.objects.filter(is_superuser=True).order_by("date_joined").first()
|
||||
if first_superuser is None:
|
||||
return
|
||||
|
||||
Artifact.objects.filter(owner__isnull=True).update(owner=first_superuser)
|
||||
|
||||
|
||||
def noop_reverse(apps, schema_editor):
|
||||
pass
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
("artifacts", "0005_add_owner_nullable"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RunPython(backfill_owner, noop_reverse),
|
||||
]
|
||||
23
artifacts/migrations/0007_owner_required.py
Normal file
23
artifacts/migrations/0007_owner_required.py
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
import django.db.models.deletion
|
||||
from django.conf import settings
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||
("artifacts", "0006_backfill_owner"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name="artifact",
|
||||
name="owner",
|
||||
field=models.ForeignKey(
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
related_name="artifacts",
|
||||
to=settings.AUTH_USER_MODEL,
|
||||
),
|
||||
),
|
||||
]
|
||||
18
artifacts/migrations/0008_artifact_read_at.py
Normal file
18
artifacts/migrations/0008_artifact_read_at.py
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
# Generated by Django 5.2.15 on 2026-07-23 21:52
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('artifacts', '0007_owner_required'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='artifact',
|
||||
name='read_at',
|
||||
field=models.DateTimeField(blank=True, null=True),
|
||||
),
|
||||
]
|
||||
34
artifacts/migrations/0009_quota_and_keep.py
Normal file
34
artifacts/migrations/0009_quota_and_keep.py
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
# Generated by Django 5.2.15 on 2026-07-24 07:15
|
||||
|
||||
import django.db.models.deletion
|
||||
from django.conf import settings
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('artifacts', '0008_artifact_read_at'),
|
||||
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='artifact',
|
||||
name='is_kept',
|
||||
field=models.BooleanField(default=False),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='artifact',
|
||||
name='size_bytes',
|
||||
field=models.BigIntegerField(default=0),
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='UserProfile',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('quota_bytes', models.BigIntegerField(default=1073741824)),
|
||||
('user', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, related_name='profile', to=settings.AUTH_USER_MODEL)),
|
||||
],
|
||||
),
|
||||
]
|
||||
43
artifacts/migrations/0010_backfill_sizes_and_profiles.py
Normal file
43
artifacts/migrations/0010_backfill_sizes_and_profiles.py
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
from pathlib import Path
|
||||
|
||||
from django.conf import settings
|
||||
from django.db import migrations
|
||||
|
||||
|
||||
def backfill(apps, schema_editor):
|
||||
Artifact = apps.get_model("artifacts", "Artifact")
|
||||
User = apps.get_model("auth", "User")
|
||||
UserProfile = apps.get_model("artifacts", "UserProfile")
|
||||
|
||||
root = Path(settings.ARTIFACTS_ROOT)
|
||||
for artifact in Artifact.objects.all():
|
||||
total = 0
|
||||
primary = root / artifact.path
|
||||
if primary.exists():
|
||||
total += primary.stat().st_size
|
||||
if artifact.kind == "markdown":
|
||||
sidecar = primary.with_suffix(".md")
|
||||
if sidecar.exists():
|
||||
total += sidecar.stat().st_size
|
||||
if artifact.size_bytes != total:
|
||||
artifact.size_bytes = total
|
||||
artifact.save(update_fields=["size_bytes"])
|
||||
|
||||
default_quota = 1024 * 1024 * 1024 # 1 GB
|
||||
for user in User.objects.all():
|
||||
UserProfile.objects.get_or_create(user=user, defaults={"quota_bytes": default_quota})
|
||||
|
||||
|
||||
def noop_reverse(apps, schema_editor):
|
||||
pass
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
("artifacts", "0009_quota_and_keep"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RunPython(backfill, noop_reverse),
|
||||
]
|
||||
31
artifacts/migrations/0011_add_asset.py
Normal file
31
artifacts/migrations/0011_add_asset.py
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
# Generated by Django 5.2.15 on 2026-07-24 10:13
|
||||
|
||||
import django.db.models.deletion
|
||||
from django.conf import settings
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('artifacts', '0010_backfill_sizes_and_profiles'),
|
||||
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='Asset',
|
||||
fields=[
|
||||
('id', models.CharField(max_length=12, primary_key=True, serialize=False)),
|
||||
('path', models.CharField(max_length=500)),
|
||||
('content_type', models.CharField(max_length=100)),
|
||||
('size_bytes', models.BigIntegerField(default=0)),
|
||||
('created_at', models.DateTimeField(auto_now_add=True)),
|
||||
('artifact', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='assets', to='artifacts.artifact')),
|
||||
('owner', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='assets', to=settings.AUTH_USER_MODEL)),
|
||||
],
|
||||
options={
|
||||
'ordering': ['-created_at'],
|
||||
},
|
||||
),
|
||||
]
|
||||
0
artifacts/migrations/__init__.py
Normal file
0
artifacts/migrations/__init__.py
Normal file
Loading…
Add table
Add a link
Reference in a new issue