projects: модуль проектов с шагами по отделам и Task.

Шаблоны/ручное создание, access_projects, сид «Открытие аптеки». Плюс SILO/S3 для Django media.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-10-23 16:26:45 +03:00
parent 69ae14f65e
commit 030bbc98fd
28 changed files with 2129 additions and 3 deletions
+102
View File
@@ -0,0 +1,102 @@
# SILO → ACORE media + Nextcloud
SILO ([pgsty/silo](https://silo.pigsty.io/)) — S3-совместимое хранилище (форк MinIO).
Портал **не** ходит в S3 за документами: документы остаются через Nextcloud WebDAV.
SILO — бэкенд файлов Nextcloud и Django `MEDIA` (фото и т.п.).
```
ACORE ImageField ──▶ bucket acore-media (SILO)
ACORE Documents ──▶ Nextcloud WebDAV ──▶ bucket nextcloud (SILO)
```
## 0. SILO: бакеты и ключи
На машине с доступом к API SILO (`:9000`):
```bash
export SILO_ENDPOINT=https://s3.example.local:9000
export SILO_ROOT_USER=...
export SILO_ROOT_PASSWORD=...
chmod +x scripts/silo_bootstrap.sh
./scripts/silo_bootstrap.sh
```
Скрипт создаёт:
| Bucket | Пользователь | Назначение |
|--------|--------------|------------|
| `acore-media` | `acore-media-rw` | Django media |
| `nextcloud` | `nextcloud-rw` | Primary object store NC |
Включает versioning и smoke put/get. Root-ключ после bootstrap для приложений не использовать.
Проверка с хостов ACORE и Nextcloud:
```bash
mcli alias set check "$SILO_ENDPOINT" acore-media-rw "$S3_SECRET_KEY"
mcli ls check/acore-media
```
TLS: лучше reverse-proxy (Traefik/nginx) на API; клиентам — `https://…`.
## 1. Nextcloud: primary object store
1. Остановить NC, бэкап data-dir (`config/`, `data/`).
2. В `config/config.php` добавить **до** первого запуска с новым store (или через occ, если версия поддерживает):
```php
'objectstore' => [
'class' => '\\OC\\Files\\ObjectStore\\S3',
'arguments' => [
'bucket' => 'nextcloud',
'autocreate' => false,
'key' => 'nextcloud-rw',
'secret' => 'PASTE_SECRET',
'hostname' => 's3.example.local',
'port' => 9000,
'use_ssl' => true,
'use_path_style' => true,
'region' => 'us-east-1',
// при необходимости: 'legacy_auth' => true,
],
],
```
`hostname` — хост **без** схемы; порт отдельно. Path-style обязателен для SILO/MinIO.
3. Если на локальном диске уже есть файлы пользователей — миграция отдельным окном (occ files:scan / инструменты вендора, либо чистый стенд). Не монтируйте тот же бакет как External Storage *и* primary одновременно для одних и тех же данных.
4. Запуск NC → upload в UI → с портала browse/upload документов и документов аптеки (WebDAV без изменений в ACORE).
5. Логи: `nextcloud.log`, ошибки `objectstore` / S3.
**External Storage** (админка → Внешнее хранилище) — только если нужна *дополнительная* шара рядом с локальным диском. Для «все документы портала в SILO» нужен именно **primary object store**, как выше.
## 2. ACORE media
В `.env` (секреты из вывода bootstrap):
```env
S3_ENDPOINT=https://s3.example.local:9000
S3_ACCESS_KEY=acore-media-rw
S3_SECRET_KEY=...
S3_MEDIA_BUCKET=acore-media
S3_REGION=us-east-1
# S3_QUERYSTRING_EXPIRE=3600
```
Если `S3_ENDPOINT` + ключи заданы — `STORAGES['default']` = S3; иначе локальный `MEDIA_ROOT` (dev).
Одноразовая заливка существующего диска:
```bash
python manage.py sync_media_to_s3
# или dry-run:
python manage.py sync_media_to_s3 --dry-run
```
После стабилизации nginx **не** должен раздавать `/media/` с диска приложения: URL файлов — подписанные ссылки на SILO. Static по-прежнему с диска/`collectstatic`.
## Эксплуатация
- Бэкап бакетов SILO отдельно от PostgreSQL (versioning ≠ бэкап).
- Разные ключи на media и Nextcloud; не коммитить секреты.
- После cutover локальный `media/` можно оставить read-only архивом.