1
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
# Architecture
2
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
3
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
## Overview
4
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
5
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
FossilRepo is a Django web application that wraps Fossil SCM repositories with a modern UI. It reads `.fossil` files directly as SQLite databases for speed, and uses the `fossil` CLI binary for write operations to maintain artifact integrity.
6
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
7
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
```
8
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
Browser (HTMX + Alpine.js + Tailwind CSS)
9
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
|
10
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
v
11
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
Django 5 (views, ORM, permissions)
12
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
|
13
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
|-- FossilReader (direct SQLite reads, ?mode=ro)
14
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
|-- FossilCLI (subprocess for writes: commit, ticket, wiki, push/pull)
15
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
|-- fossil http (CGI proxy for clone/push/pull)
16
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
|
17
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
|-- PostgreSQL 16 (app data: users, orgs, teams, projects, settings)
18
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
|-- Redis 7 (Celery broker, cache)
19
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
|-- Celery (background: metadata sync, git mirror, webhooks, digest)
20
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
|
21
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
v
22
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
.fossil files (SQLite: code + wiki + tickets + forum + technotes)
23
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
|
24
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
v
25
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
Litestream --> S3 (continuous SQLite replication)
26
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
```
27
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
28
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
## Core Components
29
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
30
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
### FossilReader
31
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
32
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
Opens `.fossil` repository files directly as read-only SQLite databases. No network calls to a running Fossil server. Python's `sqlite3` module with `?mode=ro` URI.
33
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
34
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
Handles:
35
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
- Blob decompression (zlib with 4-byte size prefix)
36
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
- Delta chain resolution (Fossil's delta-encoded artifacts)
37
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
- Julian day timestamp conversion
38
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
- Timeline queries, file tree at any checkin, ticket/wiki/forum reads
39
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
- Commit activity aggregation, contributor stats, search
40
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
41
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
### FossilCLI
42
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
43
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
Thin subprocess wrapper around the `fossil` binary. Used for all write operations:
44
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
- Repository init, clone, push, pull, sync
45
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
- Ticket create/change, wiki create/commit
46
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
- Technote creation, blame, Pikchr rendering
47
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
- Git export for mirror sync
48
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
- Tarball and zip archive generation
49
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
- Unversioned file management
50
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
- Artifact shunning
51
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
52
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
All calls set `USER=fossilrepo` in the environment and call `ensure_default_user()` to prevent "cannot figure out who you are" errors.
53
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
54
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
### HTTP Sync Proxy
55
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
56
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
The `fossil_xfer` view proxies Fossil's wire protocol through Django. Clients clone/push/pull via:
57
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
58
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
```
59
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
fossil clone http://your-server/projects/<slug>/fossil/xfer repo.fossil
60
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
```
61
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
62
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
Django handles authentication and access control. Public repos allow anonymous pull (no `--localauth`). Authenticated users with write access get full push via `--localauth`. Branch protection rules are enforced at this layer.
63
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
64
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
### SSH Sync
65
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
66
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
An `sshd` instance runs on port 2222 with a restricted `fossil-shell` forced command. Users upload SSH public keys via their profile. The `authorized_keys` file is regenerated from the database on key add/remove.
67
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
68
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
```
69
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
fossil clone ssh://fossil@host:2222/<slug> repo.fossil
70
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
```
71
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
72
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
## Data Architecture
73
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
74
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
### Two Databases
75
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
76
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
1. **PostgreSQL** — application state: users, organizations, teams, projects, releases, webhooks, API tokens, workspace claims, code reviews, notification preferences
77
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
2. **Fossil .fossil files** — repository data: code history, tickets, wiki, forum, technotes, unversioned files
78
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
79
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
### Model Base Classes
80
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
81
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
- `Tracking` (abstract) — `version`, `created_at/by`, `updated_at/by`, `deleted_at/by`, `history` (django-simple-history)
82
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
- `BaseCoreModel(Tracking)` — adds `guid` (UUID4), `name`, `slug` (auto-generated), `description`
83
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
- Soft deletes only: `obj.soft_delete(user=request.user)`, never `.delete()`
84
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
- `ActiveManager` on `objects` excludes soft-deleted; `all_objects` includes them
85
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
86
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
### Permission Model
87
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
88
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
Two layers:
89
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
1. **Org-level roles** (Admin/Manager/Developer/Viewer) — Django Groups with permission bundles, assignable per user
90
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
2. **Project-level RBAC** (read/write/admin) — per team, via ProjectTeam model
91
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
92
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
Project visibility:
93
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
- **Public** — anyone can read (including anonymous)
94
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
- **Internal** — authenticated users can read
95
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
- **Private** — team members only
96
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
97
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
### Encryption
98
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
99
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
SSH keys and OAuth tokens encrypted at rest using Fernet (AES-128-CBC + HMAC-SHA256), keyed from Django's `SECRET_KEY`. Implemented as `EncryptedTextField` in `core/fields.py`.
100
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
101
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
## Infrastructure
102
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
103
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
### Docker (Omnibus)
104
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
105
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
Single multi-stage Dockerfile:
106
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
1. Stage 1: compile Fossil 2.24 from source (Debian bookworm)
107
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
2. Stage 2: Python 3.12 runtime with Fossil binary, sshd, gosu
108
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
109
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
Entrypoint starts sshd as root, drops to unprivileged `app` user for gunicorn.
110
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
111
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
### Celery Tasks
112
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
113
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
| Task | Schedule | Purpose |
114
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
|------|----------|---------|
115
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
| sync_metadata | Every 5 min | Update repo stats (size, checkin count) |
116
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
| check_upstream | Every 15 min | Check for new upstream artifacts |
117
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
| dispatch_notifications | Every 5 min | Send pending email notifications |
118
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
| send_digest (daily) | Every 24h | Daily notification digest |
119
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
| send_digest (weekly) | Every 7d | Weekly notification digest |
120
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
| dispatch_webhook | On event | Deliver webhook with retry |
121
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
| run_git_sync | On schedule | Git mirror export |
122
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
123
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
### Caddy
124
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
125
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
SSL termination and subdomain routing. Each repo can get its own subdomain.
126
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
127
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
### Litestream
128
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
129
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
Continuous SQLite-to-S3 replication for `.fossil` files. Point-in-time recovery.
130
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
131
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
## Django Apps
132
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
133
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
| App | Purpose |
134
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
|-----|---------|
135
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
| `core` | Base models, permissions, pagination, sanitization, encryption |
136
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
| `accounts` | Login/logout, SSH keys, user profile, personal access tokens |
137
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
| `organization` | Org settings, teams, members, roles |
138
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
| `projects` | Projects, project groups, project stars, team assignment |
139
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
| `pages` | FossilRepo KB (knowledge base articles) |
140
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
| `fossil` | Everything Fossil: reader, CLI, views, sync, webhooks, releases, CI, workspaces, reviews |
141
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
| `mcp_server` | MCP server for AI tool integration |
142
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!