{"text_format":"3","workbook":"xls","n_sheets":2,"sheets":["API","Структура базы данных"],"not_rendered":{"comments":5},"read":"whole","date_system":"1900","formulas":"cached_only"}

{"sheet":"API","index":0,"n_rows":65,"n_cols":4,"rows_kept":65,"flags":["formulas_cached_only"]}
["Метод","url","Описание"]
[null,"ADMIN /api/admin/"]
["POST","/auth/telegram","Вход. Создание сессии. "]
["POST","/auth/email","Вход. Создание сессии. "]
["POST","/auth/email/register","Регистрация нового клиента выполняется за ТРИ последовательных вызова"]
["POST","/auth/email/upgrade","Перевод авторизации с аккаунта Telegram на email за ТРИ шага"]
["POST","/auth/email/change-email","Смена email выполняется за ЧЕТЫРЕ последовательных вызова"]
["POST","/auth/email/change-password","Смена пароля выполняется за ТРИ последовательных вызова."]
["POST","/auth/email/recovery","Восстановление доступа выполняется за ТРИ последовательных вызова"]
["GET","/auth/logout","Выход. Удаление сессии."]
[]
["GET","/customer/profile","Данные профиля.\nВ поле upload_token ключ, которым можно привязать чат для хранения файлов и истории сообщений. Привязка происходит по такой же ссылке как и для обычных чатов."]
["PUT","/customer/profile","Обновление профиля"]
["GET","/customer/settings","Получение настроек"]
["PUT","/customer/settings","Обновление настроек"]
[]
["GET","/project","Список проектов"]
["POST","/project","Добавление проекта"]
["PUT","/project/:id","Обновление проекта"]
["PUT","/project/:id/arhive","Помещение проекта в архив\n1. Бот отравляет в чаты сообщение, что проект архивирован\n2. Бот прекращает отслеживать сообщения в чатах"]
["PUT","/project/:id/restore","Восстановление проекта из архива\n1. Бот отравляет в чаты сообщение, что проект восстановлен\n2. Бот возобновляет отслеживание сообщений в чатах"]
[]
["GET","/project/:id/user","Список пользователей на проекте"]
["PUT","/project/:id/user/:id","Обновление пользователя на проекте (задание ФИО, должности и статуса блокировки)"]
["GET","/project/:id/token","Получение ключа для привязки Telegram-чата"]
["GET","/project/:id/company","Список компаний на проекте"]
["POST","/project/:id/company","Создание компании на проекте"]
["PUT","/project/:id/company/:id","Обновление компании"]
["DELETE","/project/:id/company/:id","Удаление компании"]
["GET","/project/:id/company/mapping","Маскировка. Массив элементов в формате {company_id, show_to_ids}, где show_to_ids - \nмассив id-компаний, которые видят компанию с company_id. Если список пуст, то компания \nдля всех отображается как компания клиента, т.е. как компания из PROJECTS.company_id.\nЕсли для компании в маскировке нет строки, то маскировка к ней не применяется и компания для других участников отображается как есть."]
["PUT","/project/:id/company/mapping","Обновление маскировки. Ожидаемый формат вх. данных - такой же как и при получении."]
["PUT","/project/:id/company/:id/user","Задание участников компании.\nФормат вх. данных - массив из id-участников."]
[]
["GET","/project/:id/chat","Список Telegram-чатов, привязанных к проекту"]
["DELETE","/project/:id/chat/:id","Отвязка чата от проекта"]
["GET","/project/:id/history?from=…&to=…","Получить историю за период на проекте","НЕ ГОТОВО"]
[]
[null,"MINIAPP /api/miniapp/"]
["POST","/auth","Авторизация. Должна запускаться первым запросом."]
["GET","/project","Список проектов: поля таблицы + флаг можно ли прикреплять файлы, зависящий указал ли админ системы для проекта Telegram-чата для бекапа"]
["GET","/project/:id/user","Список участников проекта со всей информацией\nЕсли пользователь покинул все чаты, связанные с проектом, но при этом он отмечен как создатель встречи или участник задачи, то is_leave = 1\nУ пользователя поле company_id заполнено в соотвествии с действующими правилами маскировки на проекте."]
["GET","/project/:id/user/reload","Запускает принудительное обновление пользователей в чатах по Telegram API"]
["GET","/project/:id/company","Список компаний на проекте. \nДля пользователя определяется его компания. В итоговый список компаний попадают:\n1. Компания пользователя (если есть)\n2. Компании, для которых включена маскировка, но они показываются компании пользователя\n3. Компании, которых нет в таблице маскировок\n4. Компания клиента на проекте PROJECTS.company_id"]
["GET","/project/:id/chat","Список Telegram-чатов, привязанных к проекту, в которых участвует пользователь\nУ каждого чата в поле users содержатся идентификаторы из USERS, которые на данный момент в чате. Их число должно совпадать с user_count."]
[]
["GET","/project/:id/task","Список задач для проекта, включая данные о подписке"]
["POST","/project/:id/task","Создание задачи в проекте"]
["PUT","/project/:id/task/:id","Обновление задачи"]
["PUT","/project/:id/task/:id/observer","Изменение наблюдателей по задаче. Доступно только создателю."]
["DELETE","/project/:id/task/:id","Удаление задачи. Доступно только создателю."]
["POST","/project/:id/task/:id/attach","Загрузка файлов и их прикрепление к задаче. \nВозвращаемое значение массив описания файлов"]
[]
["GET","/project/:id/meeting","Список встреч проекта"]
["POST","/project/:id/meeting","Создание встречи в проекте"]
["PUT","/project/:id/meeting/:id","Обновление встречи"]
["PUT","/project/:id/meeting/:id/participant","Обновление списка участников встречи"]
["DELETE","/project/:id/meeting/:id","Удаление встречи"]
["POST","/project/:id/meeting/:id/attach","Загрузка файлов и их прикрепление к встрече. \nВозвращаемое значение массив описания файлов"]
[]
["GET","/project/:id/file","Список файлов в проекте"]
["GET","/project/:id/file/:id","Прямая ссылка для скачивания фвйла"]
["DELETE","/project/:id/file/:id","Удаление вложения для задачи или встречи. Доступно только создателю."]
[]
["GET","/settings","Получение настроек miniapp у пользователя"]
["PUT","/settings","Сохранение настроек miniapp пользователя"]

{"sheet":"Структура базы данных","index":1,"n_rows":123,"n_cols":4,"rows_kept":123,"merged":[[3,2,5,2],[42,2,44,2],[61,3,72,3],[89,3,102,3],[91,2,94,2],[116,3,120,3],[122,0,122,2]],"flags":["formulas_cached_only"]}
["CUSTOMERS",null,"Администраторы системы"]
["id","integer"]
["name","text"]
["email","text","Для входа в систему может использоваться как пара email/password, так и просто telegram_id. При переходе с авторизации с telegram-id на email/password, значение telegram_id сбрасывается."]
["password","text"]
["telegram_id","integer"]
["plan","integer","0 - Бесплатно\n1 - Платно"]
["json_balance","json","? json, массив {currency, amount}"]
["json_company","json","{name, email, phone, site}\nПараметры компании, которая будет создаваться на проекте."]
["upload_chat_id","integer, CHATS.id"]
["json_backup_server","json","json, описывающий подключение к серверу для бекапа\nДля первой версии будет только Яндекс.Диск, т.е. \n{\"type\": \"yandex\", token: ...}"]
["json_backup_params","json","json, описывающий что сохранять, напр. {\"messages\": true, \"files\": true}"]
["json_settings","json"]
[]
["PROJECTS",null,"Проекты"]
["id","integer, PK"]
["customer_id","integer, CUSTOMERS.id"]
["name","text"]
["description","text"]
["logo","text","base64"]
["is_logo_bg","integer","0/1"]
["company_id","integer, COMPANIES.id","Задает компанию клиента. Строка в таблице COMPANIES создается автоматически при создании проекта на основе данных CUSTOMERS.json_company."]
["is_archived","integer, 0/1"]
[]
["CHATS",null,"Чаты"]
["id","integer"]
["project_id","integer, PROJECTS.id"]
["name","text"]
["description","text","Описание из телеграм"]
["telegram_id","text","ID-telegram чата"]
["logo","text","base64"]
["is_channel","integer, 0/1"]
["invite_link","text","Ссылка на приглашение в группу. Используется для перехода в группу из миниаппа"]
["bot_can_ban","integer, 0/1"]
["owner_id","integer, USERS.id","Создатель чата"]
["user_count","integer","Число пользователей минус боты"]
["last_update_time","integer","unixtime"]
[]
["USERS",null,"Пользователи"]
["id","integer, PK"]
["telegram_id","integer"]
["access_hash","integer"]
["firstname","text","Данные из Telegram"]
["lastname","text"]
["username","text"]
["photo_id","integer","file_id в Telegram. Используется для определения изменилось ли фото или нет."]
["photo","text","base64"]
["language_code","text","Определяется из Telegram"]
["json_settings","json","Пользовательские настройки, напр. интерфейса или часового пояса."]
[]
["USER_DETAILS",null,"Описание пользователей для проекта"]
["user_id","integer, USERS.id"]
["project_id","integer, PROJECTS.id"]
["fullname","text"]
["email","text"]
["phone","text"]
["role","text","Роль"]
["department","text","Департамент"]
["is_blocked","integer, 0/1","Пользователь, заблокированный на проекте, не имеет к нему доступ в миниаппе, однако может продолжать участвовать в чатах в Telegram и как следствие получать информацию."]
[]
["TASKS",null,"Задачи"]
["id","integer, PK",null,"У задачи могут быть наблюдатели, видящие её у себя в списке, но не имеющие возможность изменить её. Наблюдатели могут скачивать документы, прикрепленные к задаче. Наблюдатели добавляются при создании задачи и могут быть отредактированы позже.\nЕсли пользователь теряет доступ к проекту и следовательно задаче, то другим участникам задачи приходит оповещение.\n\n\nЗакрыть задачу может только создатель или ответсвенный. \nИзменять задачу может только создатель.\n\nЕсли задача прикреплена к чату, т.е. заполнено поле chat_id, то её видят все участники этого чата."]
["project_id","integer, PROJECTS.id"]
["name"]
["created_by","integer, USERS.id"]
["assigned_to","integer, USERS.id"]
["closed_by","integer, USERS.id","created_by или assigned_to"]
["priority","integer","0 - не задано, 1 - обычно, 2 - важно, 3 - критично"]
["status","integer","1 - новый, 5 - сделано."]
["time_spent","integer","Потраченное время в минутах"]
["create_date","integer","unixtime"]
["plan_date","integer","unixtime"]
["close_date","integer","unixtime"]
["close_comment","text"]
["json_close_file_ids","json","Массив"]
["chat_id","integer, CHATS.id","Один из чатов проекта. Может быть пусто.\nЕсли задано, то created_by и assigned_to должны иметь доступ к этому чату."]
[]
["MEETINGS",null,"Совещания"]
["id","integer"]
["project_id","integer, PROJECTS.id"]
["name","text"]
["description","text"]
["place","text"]
["created_by","integer, USERS.id"]
["meet_date","integer","unixtime"]
["chat_id","integer, CHATS.id","Один из чатов проекта. Может быть пусто."]
["is_cancel","integer, 0/1","Признак отменной встречи. В отличии от удаления, встреча остается в списке."]
[]
["FILES",null,"Файлы, отправленные в чаты, и вложения к задачам и совещаниям"]
["id","integer",null,"При прикреплении файлов к задаче или встрече определяется чат, к которому они относятся. Если чат не указан, то используется чат бекапа. Если и он не задан, то POST-метод .../attach вернет ошибку. Далее в базу вносится информация о файле и файл отправляется в указанный чат.\n\nБот мониторит сообщения с файлами в чатах.\nЕсли файл был отправлен пользователем, то он регистрирует его в таблице и, если задан чат бекапа, пересылает файл туда.\nЕсли файл был отправлен ботом, то определяется совпадает ли чат файла с одним из чатов, используемых для бекапа. Если да, то файл игнорируется. Если же чат отличен\n"]
["project_id","integer, PROJECTS.id"]
["chat_id","integer","Для скачивания файла будет использоваться file_id/access_hash. Поскольку access_hash может протухнуть или потребоваться доступ из другого бота, который получит свой access_hash, то требуется хранить и чат/сообщение, куда файл был сохранен, что позволит при необходимости получить новые file_id/access_hash."]
["message_id","integer"]
["file_id","integer"]
["access_hash","integer"]
["filename","text","Имя файла с расширением"]
["mime","text"]
["size","integer","В байтах"]
["caption","text","Если документ был отправлен в чате и при этом с подписью"]
["published_by","integer, USERS.id"]
["published","integer","unixtime"]
["parent_type","integer, 0/1/2/3","Совместно с parent_id определяет родительский объект для файла: это может быть задача, встреча или файл.\n\nОпределяет кем и зачем был отправлен этот файл:\n0 - в сообщении чата пользователем\n1 - ботом, как вложение для задачи \n2 - ботом, как вложение для встречи\n3 - ботом, как бекап-копия. В этом случае chat_id будет совпадать с CUSTOMERS.upload_chat_id"]
["parent_id","integer","В зависимости от parent_type:\n0 - поле не заполняется\n1 - значение из TASKS.id\n2 - значение из MEETINGS.id\n3 - значение из FILES.id"]
[]
["COMPANIES",null,"Компании-участники на проекте"]
["id","integer"]
["project_id","integer, PROJECTS.id"]
["name","text"]
["address","text"]
["email","text"]
["phone","text"]
["site","text"]
["description","text"]
["logo","text","base64"]
[]
["COMPANY_MAPPINGS",null,"Какие компании будут не видны каким на проекте для скрытия субподряда"]
["id","integer",null,"Для компании с company_id = N маскировка задается на каждом проекте индивидуально.\nЕсли маскировка не включена, то записей в таблице нет.\nЕсли включена, то точно будет строка, где show_to_id = N, означающая, что сотрудники из одной компании должны видеть друг друга. Другие строки задают компании, которым будет видна компания N, как она сама. Всем остальным эта компания будет отображаться как главная компания с is_own = 1."]
["project_id","integer, PROJECTS.id"]
["company_id","integer, COMPANIES.id"]
["show_as_id","integer, COMPANIES.id","Под какую компанию мимикрировать. По умолчанию PROJECTS.company_id"]
["show_to_id","integer, COMPANIES.id"]
[]
["Три таблицы для хранения связей meeting_users, company_users м chat_users"]