Local file upload & download service — Express backend, on-disk uploads/, glass-style web UI.
| Language | English · Русский |
| English (quick) | Overview · Features · Quick start · Usage · HTTP API · Project layout · Design · Diagrams · Screenshots · Limits |
| Русский (быстро) | Обзор · Возможности · Запуск · Использование · API · Структура · Дизайн · Схемы · Скриншоты · Ограничения |
FileStorage is a minimal, local-first web app: upload files from the browser (click or drag-and-drop), browse stored names, and open downloads. The same behavior is available via a small HTTP API for scripts and tools.
| Item | Details |
|---|---|
| Runtime | Node.js (LTS recommended) |
| Server | Express on port 3000 (default) |
| Storage | ./uploads (created on startup if missing) |
| UI | Static public/ — HTML, CSS, inline JS |
| License | See package.json (default ISC) |
| Capability | Supported |
|---|---|
| Single-file upload per request | Yes |
| Drag-and-drop + file picker | Yes |
| Live file list in the UI | Yes |
| JSON list endpoint | Yes |
Path traversal hardening on download (path.basename) |
Yes |
| Authentication / quotas | No (local / trusted use) |
| Step | Command / action |
|---|---|
| 1 | git clone your repo, then cd FileStorage |
| 2 | npm install |
| 3 | node index.js |
| 4 | Open http://localhost:3000/ |
Verify Node/npm:
node -v
npm -vExpected console output:
Server running at http://localhost:3000/
| # | Action |
|---|---|
| 1 | Start the server (node index.js). |
| 2 | Visit http://localhost:3000/. |
| 3 | Upload: click DROP ZONE or drop a file onto it. |
| 4 | Watch the status line (e.g. uploading → saved). |
| 5 | In FILES, use open to fetch the file in a new tab. |
Stored filenames on disk: <timestamp>-<originalName>. The UI shows the original segment for readability.
All blobs are under uploads/ next to index.js. Backup or purge by managing that folder.
Uploads use multipart field name file (see multer.single('file') in index.js).
| Method | Path | Description |
|---|---|---|
GET |
/ |
Web UI (public/index.html via static hosting) |
GET |
/styles.css |
UI stylesheet |
GET |
/api/files |
JSON: { "files": string[] } |
POST |
/upload |
multipart/form-data, field file — response JSON |
GET |
/files/:filename |
Stream file from uploads/ |
| Situation | HTTP | Body (shape) |
|---|---|---|
| List OK | 200 |
{ "files": [...] } |
| Upload OK | 200 |
{ "ok": true, "filename": "..." } |
| Upload with no file | 400 |
{ "error": "No file uploaded." } |
| File missing | 404 |
plain text File not found. |
| List directory error | 500 |
{ "error": "..." } |
List:
curl -s http://localhost:3000/api/filesUpload:
curl -s -X POST -F "file=@./path/to/local-file.txt" http://localhost:3000/uploadDownload:
curl -O -J http://localhost:3000/files/<stored-filename>Sample JSON:
{ "files": ["1715600000000-report.pdf", "1715600001000-photo.png"] }{ "ok": true, "filename": "1715600002000-local-file.txt" }FileStorage/
├── index.js # Express app: routes, multer, static files
├── package.json
├── public/
│ ├── index.html # UI markup + fetch / drag-and-drop logic
│ └── styles.css # Glass UI, typography, layout
├── uploads/ # Stored uploads (auto-created)
└── README.md
| Path | Responsibility |
|---|---|
index.js |
HTTP server, upload pipeline, /api/files, static public/ |
public/index.html |
User-facing page |
public/styles.css |
Visual design tokens and components |
uploads/ |
Authoritative file blob store |
The UI targets a minimal, single-column layout: generous whitespace, one primary glass panel, and restrained motion.
| Layer | Implementation |
|---|---|
| Atmosphere | Layered cool gradients + soft animated “orbs” (blurred, non-interactive) |
| Glass | Semi-transparent surfaces, backdrop-filter: blur + saturate, hairline borders, inset highlight |
| Typography | Press Start 2P (display/pixel), Silkscreen (UI/pixel) via Google Fonts |
| Accent | System-style blue (~#007AFF with alpha) |
| Feedback | Dropzone hover / drag-over states; .ok / .err status colors |
| Responsive | clamp() spacing; viewport meta for small screens |
| Asset | Role |
|---|---|
public/index.html |
Structure, upload zone, file list, inline script |
public/styles.css |
Background, glass, fonts, list, states |
High-level components and data flow:
flowchart LR
subgraph Client["Client"]
B["Browser"]
end
subgraph Node["Node.js + Express"]
S["Static\npublic/"]
R["Routes"]
M["Multer"]
end
D[("uploads/")]
B -->|"GET /"| S
B -->|"GET /api/files"| R
B -->|"POST /upload"| M
B -->|"GET /files/:name"| R
M --> D
R --> D
Typical upload sequence:
sequenceDiagram
autonumber
actor U as User
participant BR as Browser
participant EX as Express
participant MU as Multer
participant FS as Local disk
U->>BR: Select or drop file
BR->>EX: POST /upload multipart
EX->>MU: single("file")
MU->>FS: Write timestamped name
MU-->>EX: req.file
EX-->>BR: 200 JSON ok + filename
BR->>EX: GET /api/files
EX-->>BR: JSON file list
Illustrative responsibility split (not a performance metric):
%%{init: {'theme': 'neutral'}}%%
pie showData
title README — conceptual surface area
"Express routing & static" : 38
"Browser UI (HTML/CSS/JS)" : 32
"Multer + filesystem I/O" : 22
"Docs & config" : 8
| Topic | Note |
|---|---|
| Throughput / size | No explicit max body size in repo defaults — configure for production |
| Security | No auth; intended for local or trusted networks |
| Production | Add HTTPS, auth, limits, logging, virus scanning as needed |
FileStorage — локальный веб-сервис для загрузки и выдачи файлов: сервер на Express, хранение в каталоге uploads/ и интерфейс в стиле glass UI с пиксельной типографикой. То же поведение доступно через HTTP API.
| Параметр | Значение |
|---|---|
| Среда | Node.js (желательно LTS) |
| Порт | 3000 (по умолчанию) |
| Хранилище | ./uploads (создаётся при старте) |
| Интерфейс | Статика из public/ |
| Лицензия | См. package.json (ISC по умолчанию) |
| Возможность | Поддержка |
|---|---|
| Один файл за запрос | Да |
| Клик и drag-and-drop | Да |
| Список файлов в UI | Да |
| JSON-список для скриптов | Да |
Защита пути при скачивании (path.basename) |
Да |
| Авторизация / квоты | Нет |
| Шаг | Действие |
|---|---|
| 1 | Клонировать репозиторий, cd FileStorage |
| 2 | npm install |
| 3 | node index.js |
| 4 | Открыть http://localhost:3000/ |
Проверка окружения:
node -v
npm -vСообщение в консоли:
Server running at http://localhost:3000/
| # | Действие |
|---|---|
| 1 | Запустить сервер (node index.js). |
| 2 | Открыть http://localhost:3000/. |
| 3 | Загрузить файл: клик по DROP ZONE или перетаскивание. |
| 4 | Смотреть строку статуса. |
| 5 | В блоке FILES нажать open для открытия в новой вкладке. |
Имена на диске: <timestamp>-<оригинальное_имя>; в списке показывается оригинальная часть имени.
Файлы физически лежат в uploads/ рядом с index.js.
Поле multipart для загрузки: file.
| Метод | Путь | Описание |
|---|---|---|
GET |
/ |
Веб-интерфейс |
GET |
/styles.css |
Стили |
GET |
/api/files |
JSON { "files": [...] } |
POST |
/upload |
multipart/form-data, поле file |
GET |
/files/:filename |
Выдача файла из uploads/ |
| Ситуация | HTTP | Тело |
|---|---|---|
| Список успешен | 200 |
{ "files": [...] } |
| Загрузка успешна | 200 |
{ "ok": true, "filename": "..." } |
| Файл не передан | 400 |
{ "error": "No file uploaded." } |
| Файл не найден | 404 |
текст File not found. |
| Ошибка чтения каталога | 500 |
{ "error": "..." } |
Примеры curl — см. английский раздел curl examples (команды те же).
FileStorage/
├── index.js
├── package.json
├── public/
│ ├── index.html
│ └── styles.css
├── uploads/
└── README.md
| Путь | Назначение |
|---|---|
index.js |
Маршруты, multer, раздача public/ |
public/index.html |
Страница и клиентская логика |
public/styles.css |
Оформление |
uploads/ |
Загруженные файлы |
| Слой | Реализация |
|---|---|
| Фон | Многослойные градиенты, мягкие цветные «орбы», лёгкая анимация |
| Стекло | Полупрозрачность, backdrop-filter, светлая обводка, тени |
| Шрифты | Press Start 2P + Silkscreen (Google Fonts) |
| Акцент | Системный синий, состояния успеха/ошибки для статуса |
| Адаптив | clamp(), meta viewport |
Подробные пояснения по слоям — в английском блоке Design system (таблицы дублируют смысл; язык там английский).
Те же диаграммы, что выше, подходят для русскоязычного читателя:
flowchart TB
A["Браузер"] --> B["Express"]
B --> C["Статика public/"]
B --> D["Multer + uploads/"]
B --> E["GET /api/files"]
sequenceDiagram
participant П as Пользователь
participant Б as Браузер
participant С as Сервер
participant Д as Диск
П->>Б: Выбор или drop файла
Б->>С: POST /upload
С->>Д: Запись файла
С-->>Б: JSON с именем
Б->>С: GET /api/files
С-->>Б: Список имён
pie showData
title Условное распределение поверхности проекта
"Маршруты и статика" : 38
"Интерфейс" : 32
"Загрузка и I/O" : 22
"Документация" : 8
| Тема | Примечание |
|---|---|
| Размер / нагрузка | Явный лимит тела запроса в репозитории не задан — для прода настройте вручную |
| Безопасность | Нет учётных записей — только локальная или доверенная сеть |
| Продакшен | Нужны HTTPS, авторизация, лимиты, логи и т.д. по политике организации |