feat(files): gerenciador de arquivos/anexos com árvore de pastas, upload, preview e picker

- store/files.go: pastas (parent, anti-ciclo), FileMeta (nota opcional = avulso),
  blobs com extensão neutralizada p/ tipos perigosos, sanitização de nome
- api/files.go: upload multipart (64MiB), tree, static com ETag/Range + CSP
  sandbox + attachment p/ html/svg/js (stored-XSS mitigado), move/rename/delete,
  CRUD de pastas
- web: overlay Ctrl+J / 📎 (modo seletor insere sintaxe md/html/txt e associa),
  filtros Todos/Anexos/Avulsos/Nota atual, busca, lightbox img/video/audio/pdf/texto,
  colar-e-arrastar no editor e no gerenciador, ações por card (preview/associar/
  mover/renomear/excluir), mobile-first (ações sempre visíveis)
- fix: api() já serializa o body — chamadas do gerenciador passavam JSON pré-string
  (dupla codificação); auth por cookie (sem Bearer manual no fetch)
- sw v10; testes store+api (traversal, ciclo, XSS headers, range); README
This commit is contained in:
lgcosta committed 2026-11-05 10:32:40 -03:00
1 parent ea6b3b915d
commit 119e6cefe9
10 files changed
+1605 -4

No files matched your search

+8 -3
View File
@@ -132,9 +132,11 @@ type CategoryView struct {
// Store é seguro para concorrência.
type Store struct {
dir string
mu sync.RWMutex
cats []Category // cache da árvore; persistido em categories.json
dir string
mu sync.RWMutex
cats []Category // cache da árvore; persistido em categories.json
folders []Folder // árvore do gerenciador de arquivos (folders.json)
fileMetas []FileMeta // metadados de anexos (files.json)
}
// New abre (ou cria) o diretório raiz de dados e migra metadados legados
@@ -149,6 +151,9 @@ func New(dir string) (*Store, error) {
if err := s.loadCats(); err != nil {
return nil, err
}
if err := s.loadFiles(); err != nil {
return nil, err
}
if err := s.migrateLegacy(); err != nil {
return nil, err
}