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

{"sheet":"API","index":0,"n_rows":61,"n_cols":3,"rows_kept":61,"flags":["formulas_cached_only"]}
["Метод","url","Описание"]
[null,"ADMIN /api/admin/"]
["POST","/auth/telegram","Вход. Создание сессии. "]
["POST","/auth/email","Вход. Создание сессии. "]
["POST","/auth/email/register","Регистрация нового клиента выполняется за два последовательных вызова"]
["POST","/auth/email/change-email","Смена email выполняется за ЧЕТЫРЕ последовательных вызова"]
["POST","/auth/email/change-password","Смена пароля выполняется за ДВА последовательных вызова.\n"]
["POST","POST","Восстановление доступа выполняется за ДВА последовательных вызова\n"]
["GET","/auth/logout","Выход. Удаление сессии."]
[]
["GET","/customer/profile","Получение данных профиля"]
["PUT","/customer/profile","Обновление профиля. Upload-чат задается по кнопке Telegram."]
["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","Удаление компании"]
["PUT","/project/:id/company/:id/user","Задание участников компании"]
[]
["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"]
["GET","/project/:id/user/reload","Перечитать пользователей из Telegram"]
["GET","/project/:id/chat","Список Telegram-чатов, привязанных к проекту, в которых участвует пользователь"]
[]
["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Возвращаемое значение массив document_id"]
[]
["GET","/project/:id/meeting","Список встреч проекта"]
["POST","/project/:id/meeting","Создание встречи в проекте"]
["PUT","/project/:id/meeting/:id","Обновление встречи"]
["PUT","/project/:id/meeting/:id/participants","Обновление списка участников встречи"]
["DELETE","/project/:id/meeting/:id","Удаление встречи"]
["POST","/project/:id/meeting/:id/attach","Загрузка документов и их прикрепление к встрече. \nВозвращаемое значение массив document_id"]
[]
["GET","/project/:id/document","Список документов в проекте"]
["GET","/project/:id/document/:id","Ссылка для скачивания документа"]
["DELETE","/project/:id/document/:id","Удаление вложения для задачи или встречи. Доступно только создателю."]
[]
["GET","/settings","Получение настроек miniapp у пользователя"]
["PUT","/settings","Сохранение настроек miniapp пользователя"]

{"sheet":"Структура базы данных","index":1,"n_rows":106,"n_cols":4,"rows_kept":106,"merged":[[3,2,5,2],[37,2,39,2],[56,3,67,3],[80,2,81,2],[82,2,85,2],[95,3,104,3],[105,0,105,2]],"flags":["formulas_cached_only"]}
["CUSTOMERS",null,"Администраторы системы"]
["id","integer"]
["name","text"]
["email","text","Для входа в систему может использоваться как пара 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","text"]
["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, FK"]
["name","text"]
["description","text"]
["logo","text","base64"]
["is_logo_bg","integer","0/1"]
["is_archived","integer","0/1"]
[]
["CHATS",null,"Чаты"]
["id","integer"]
["project_id","integer, FK"]
["name","text"]
["telegram_id","text","ID-telegram чата"]
["is_channel","integer","0/1"]
["bot_can_ban","integer"]
["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"]
["phone","text"]
["json_phone_projects","json","Список id проектов, где телефон показывается. По умолчанию []"]
["json_settings",null,"Пользовательские настройки, напр. интерфейса или часового пояса."]
[]
["USER_DETAILS",null,"Описание пользователей для проекта"]
["user_id","integer, FK"]
["project_id","integer"]
["fullname","text"]
["role","text","Роль"]
["department","text","Департамент"]
["is_blocked","0/1"]
[]
["TASKS",null,"Задачи"]
["id","integer, PK",null,"У задачи могут быть наблюдатели, видящие её у себя в списке, но не имеющие возможность изменить её. Наблюдатели могут скачивать документы, прикрепленные к задаче. Наблюдатели добавляются при создании задачи и могут быть отредактированы позже.\nЕсли пользователь теряет доступ к проекту и следовательно задаче, то другим участникам задачи приходит оповещение.\n\n\nЗакрыть задачу может только создатель или ответсвенный. \nИзменять задачу может только создатель."]
["project_id","integer, FK"]
["name"]
["created_by","integer, FK"]
["assigned_to","integer, FK"]
["closed_by","integer, FK","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"]
[]
["MEETINGS",null,"Совещания"]
["id","integer"]
["project_id","integer"]
["name","text"]
["description","text"]
["created_by","integer"]
["meet_date","integer","unixtime"]
[]
["DOCUMENTS",null,"Файлы, отправленные в чаты, и вложения к задачам и совещаниям"]
["id","integer"]
["project_id","integer"]
["origin_chat_id","integer","Исходные данные сообщения. Требуются для возможности перейти к нему из miniapp. Используется chat_id, а не id из Telegram, т.к. идентификатор Telegram может быть изменен при конвертации чата в канал."]
["origin_message_id","integer"]
["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"]
["caption","text","Если документ был отправлен в чате и при этом с подписью"]
["size","integer","В байтах"]
["published_by","integer"]
["parent_type","0/1/2","0 - был отправлен в сообщении чата, определяемым chat_id/message_id\n1/2 - документ был добавлен как вложение к задаче/встрече. chat_id/message_id в этом случае задают сообщение в чате, используемом для бекапа."]
["parent_id","integer","При parent_type = 1 или 2 - это id из таблицы tasks или meetings"]
["backup_state","integer","0 - не сохранен, 1 - копируется, 2 - скопирован в архив","Пока не используется"]
[]
["COMPANIES",null,"Компании на проекте","Клиент customer может заводит на проекте компании-участники. Потом добавляет в них пользователей.\n\nПосредством таблицы company_mappings можно указать как сотрудники одной компании видят ту или иную компанию на проекте. Может использоваться для скрытия субподряда."]
["id","integer"]
["project_id","integer"]
["name","text"]
["email","text"]
["phone","text"]
["site","text"]
["description","text"]
["logo","text","base64"]
[]
["Три таблицы для хранения связей meeting_users, company_users, chat_users и одна для хранения информации кому-кого-какой компанией показывать company_mappings"]

{"sheet":"Данные","index":2,"n_rows":4,"n_cols":1,"rows_kept":4,"flags":["formulas_cached_only"]}
["Список доступных проектов для пользователя\n1. Из links выбираются группы, в которых участвует пользователь a_id = group_id and type = 20, где b_id = user_id\n2. Из links выбираются проекты, к которым эти группы привязаны: a_id = project_id and type = 10, где b_id = group_id\n3. Полученный результат соединяется с таблицей projects"]
["Проверка, что пользователь имеет доступ к проекту\n1. Из links выбираются группы, которые относятся к этому проекту: b_id = group_id and type = 10\n2. Проверяется, что в links есть строка, у которой type = 20 and a_id = один из group_id и b_id = user_id"]
["Список групп проекта\n1. Из links выбираются группы, которые относятся к этому проекту: b_id = group_id and type = 10\n2. Из tg_groups фильтруется информация по id, полученным в пп.1"]
["Список участников проекта\n1. Из links выбираются группы, которые относятся к этому проекту: b_id = group_id and type = 10\n2. Из links выбираются пользователи, которые участвуют в группах проекта: b_id = user_id and type = 20\n3. Добавляются бывшие участники: b_id = user_id and type = 21\n4. Для пользователя в links находятся компании, где он находится: a_id = company_id and type = 50 and b_id = :user_id\n5. ts_users выбираются профили из пп2 и 3, которые объединяются left join с profiles, отфильтрованному по customer_id = текущий владелец проекта и company_id = NULL или в списке из пп4.\n\nИтоговый результат: массив из элементов вида \n    {\n        id: telegramUserId, \n        nick: telegramName, \n        profiles: [\n              {id, fullname, ... company_id, company: ...}\n        ],\n        is_leave: true // для бывших участников проекта\n    }"]

{"sheet":"Разное","index":3,"n_rows":16,"n_cols":1,"rows_kept":16,"flags":["formulas_cached_only"]}
["В некоторых случая требуется оповещение от бота/miniapp. Оповещения можно кидать просто в чат с ботом, но может быть лучше сделать отдельный выпадающий список и иконку оповещений в miniapp.\n\nТипы оповещений\n1. Создатель или Ответсвенный за задачу покинул проект\n2. Задача изменила статус\n3. Задача была создана или удалена.\n4. Создано совещание, где пользователь указан как участник - создателю такое оповещение не надо. \n5. Предупреждение за час перед совещанием"]
["Возможно стоит иметь статусы задач отличные от Новый и Сделано/Готово, к примеру Закрыта, Отклонена, В работе, На проверке - см. iTasker на YouTube"]
["В историю Задачи можно добавлять записи пометив их в чате и сделав Reply боту, который спросит к какой задаче прикрепить. \nПри этом возможна ситуация, когда обсуждение задачи велось в чате недоступном для одного из участников. В этом случае текст должен иметь иконку замочка или что-то в этом духе.\nВо избежании удаления информации путем редактирования, в истории сохраняется не долько идентификаторы группы и сообщения в ней, но и текст сообщений.\nЧто делать если прикрепляемое сообщение файл?\n\nНадо ли наблюдателям дать возможность прикрепить свои сообщения к Задаче? "]
["В документах проекта можно отображать в том числе и вложения к задачам и совещаниям \nПо идее надо две опции - перейти к файлу и скачать его. Для вложений опция Перейти будет не доступна."]
["В описании задачи опциональный список, который можно крыжить см uTasks"]
["Приложение для руководителей, показывающих KPI сотрудников по задачам в разбивке по неделям/месяцам\nИли что-то для учета трудозатрат, если пользователи будут указывать их при закрытии задачи"]
["При закрытии задачи:\nВремя закрытия указывать автоматически или оставить возможность указать своё?\nМожет ли ответсвенный указать трудозатраты?\nКакие статусы доступны при закрытии? Если ответсвенный не сделал, то возможно у назначающего нужна возможность указать спецальный статус"]
["Кто может открыть задачу заново? "]
["Возможность запросить у бота Список дел \"На сегодня\" по всем проектам, в том числе и совещания\nИли лучше отдельным контролом \"Календарь\", где по клику будут выводится задачи и совещания на выбранную дату. А еще можно выбрать интервал."]
["Роуты API, отдающее списки, должны поддерживать фильтрацию на сервере, напр. /api/task\nМеханизм позволящий запрашивать что то в духе\nstatus in (0, 1) and create_date >= '11.11.2024' and create_date <= '11.12.2024'\nrowid=100:200&status=1,2&create_date=11.11.2024:11.12.2024\nто есть через запятую список значений, через двоеточие - диапазон, rowid - для разбиения результата по страницам"]
["Для задач: ответсвенный может перепоручить задачу другому?\nНовый ответсвенный из другой команды, то что делать?"]
["Если делать как в uTasks, то для выполнения задачи можно прокрыжить её прямо в списке. Если сразу отправлять оповещение создавшему и наблюдателю, то что делать с ложными срабатываниями, если пользователь ошибся и нажал не туда? Возможно надо добавить на крыж анимацию подтверждения, нажав на которую пользователь отменит выполнение задачи. "]
["Нужен ли какой API в админке для получения списка участников, компаний и групп у проекта?"]
[]
["Когда бота выгоняют из группы, то удалять запись из links с type = 10"]
["Адресная книга: фильтр по должности?"]