Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
- node:sqlite refuse `undefined` et les booléens : passer `null` / `0|1`.
- Synchro (`server/src/sync/`) : toute nouveauté passe par `pushInbox` avec une `external_key` unique ; la première synchro d'une source est « baselinée » (marquée lue) via la table `settings`.
- `pushInbox` remplit aussi `fresh` (entrées nouvelles et non lues) : c'est ce qui part sur ntfy en fin de `syncProject` (`sync/notify.js`). La CI ne génère une entrée qu'aux changements d'état (vert → rouge, rouge → vert).
- Forges (`server/src/sync/forges/`) : un adaptateur par forge (github, gitlab, gitea — Forgejo = gitea) avec la même interface (`fetchRepo`, `fetchCi`, `latestRelease`, `createIssue`, `listOwnerRepos`). Toujours passer par `forgeFor(db, project)` qui résout le token (comptes `config:forges` puis variables d'env). `whoami()` (compte du token) et `fetchMentions` (GitHub) remplissent `github_items.mine` (author, assignee, review, mention) pour les filtres « Me concernant » et la page « Mon GitHub » (`/api/my-github`) ; `fetchPrState` (GitHub) remplit `github_items.pr_state` pour ces PR, et les transitions sur les PR de l'utilisateur deviennent des entrées `pr_status`. Un bug venu du forum fermé par la synchro crée une entrée `forum_reply` (`items.forum_replied_at` une fois répondu). Sujets suivis : table `forum_watches` (`fetchTopic`, entrées `forum_followed`). CI GitHub : seuls les runs `push` / `merge_group` comptent, GitLab ignore les pipelines `schedule`. Checklist de release : `milestones.checklist`, modèle dans `config:release_checklist`. Noms historiques : la table `github_items` et la colonne `projects.github` contiennent les données de toutes les forges.
- Forges (`server/src/sync/forges/`) : un adaptateur par forge (github, gitlab, gitea — Forgejo = gitea) avec la même interface (`fetchRepo`, `fetchCi`, `latestRelease`, `createIssue`, `listOwnerRepos`). Toujours passer par `forgeFor(db, project)` qui résout le token (comptes `config:forges` puis variables d'env). `whoami()` (compte du token) et `fetchMentions` (GitHub) remplissent `github_items.mine` (author, assignee, review, mention) pour les filtres « Me concernant » et la page « Mon GitHub » (`/api/my-github`) ; `fetchPrState` (GitHub) remplit `github_items.pr_state` pour ces PR, et les transitions sur les PR de l'utilisateur deviennent des entrées `pr_status`. Un bug venu du forum fermé par la synchro crée une entrée `forum_reply` (`items.forum_replied_at` une fois répondu). Sujets suivis : table `forum_watches` (`fetchTopic`, entrées `forum_followed`). CI GitHub : seuls les runs `push` / `merge_group` comptent, GitLab ignore les pipelines `schedule`. Portée par projet : `projects.github_scope` (auto | all | mine) → `projects.mine_only` (recalculé par `refreshMineOnly` et à la synchro) ; toute requête qui compte ou liste les `github_items` passe par `VISIBLE_ITEM` (`server/src/visibility.js`). Checklist de release : `milestones.checklist`, modèle dans `config:release_checklist`. Noms historiques : la table `github_items` et la colonne `projects.github` contiennent les données de toutes les forges.
- Source de version `repo` = releases du dépôt du projet (toute forge) ; `github` = autre dépôt GitHub.
- Tâches planifiées (`server/src/jobs.js`, tick 60 s) : résumé hebdo ntfy (`insights.js`) et sauvegardes `VACUUM INTO` (`backup.js`, `BACKUP_DIR`). Le flux `/api/calendar.ics?token=` échappe à `APP_PASSWORD` (clé dans `config:calendar`). Statistiques : `fetchActivity` des forges, agrégées par `stats.js`.
- Pièces jointes (`server/src/uploads.js`) : fichiers dans `UPLOADS_DIR` (défaut `DATA_PATH/uploads`), référencés uniquement depuis le Markdown (`/api/uploads/<fichier>`), sans table ; les orphelins sont supprimés au moment de la sauvegarde. Côté front, `MarkdownInput` remplace `Input.TextArea` pour tout champ Markdown. Vue « Aujourd'hui » : colonne `items.focus_date` (`server/src/today.js`).
Expand Down
6 changes: 3 additions & 3 deletions README.en.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,8 @@ Self-hosted (Docker), single-user, all data in one SQLite file.
| **Projects grouped by category** | Freelance, Personal, Organisation (e.g. Gladys), Other — editable categories with colours. Status (idea, active, maintenance, paused, archived), client, tags, links, pinning. |
| **GitHub, GitLab, Gitea / Forgejo** | Each project points to a repository on github.com, gitlab.com or a self-hosted instance (GitLab, Gitea, Forgejo). One token per instance in **Settings → Forges and tokens**. |
| **Bulk repository import** | Lists the repositories of a user, organisation or group (filter, forks, archived) and creates the projects in one go, with category, status and release tracking. Repositories already tracked are skipped. |
| **Repository tracking** | Open issues and PRs / MRs, stars, last activity. "For me" filters (opened by you, assigned, review requested, mentioned — based on the token's account), by label, author or title, remembered per project: handy on a very active repository like Gladys. **New** ones land in the inbox; a "Track" button adds them to your bugs & tasks. |
| **My GitHub** | One page gathering, across all your projects, the reviews requested from you, your PRs, what is assigned to you, your mentions and your issues. Each PR shows its state: approved, changes requested, conflict with the main branch, CI. On your PRs, an approval, a change request, a conflict or a red CI lands in the inbox and on ntfy. |
| **Repository tracking** | Open issues and PRs / MRs, stars, last activity. "For me" filters (opened by you, assigned, review requested, mentioned — based on the token's account), by label, author or title, remembered per project: handy on a very active repository like Gladys. Per-project "Issues and PRs followed" setting: Auto (default) follows everything on your repositories and only what concerns you on other people's (counters, dashboard, stale list, notifications). **New** ones land in the inbox; a "Track" button adds them to your bugs & tasks. |
| **My GitHub** | One page gathering, across all your projects, the reviews requested from you, your PRs, what is assigned to you, your mentions and your issues. Each PR shows its state: approved, changes requested, conflict with the main branch, CI. One click turns it into a task with an explicit title ("Resolve the conflict: #3028…"). On your PRs, an approval, a change request, a conflict or a red CI lands in the inbox and on ntfy. |
| **Create an issue from a bug** | A bug reported on a forum becomes an issue on the repository (title, description, forum link, target version, label). Linked both ways: when the issue is closed, the bug is marked as done. |
| **CI status** | GitHub Actions (latest run of each workflow), GitLab pipelines, Gitea/Forgejo commit statuses (Actions, Woodpecker, Drone) on the default branch: green/red badge (only runs triggered by the code count: scheduled jobs and manually started workflows are ignored), dashboard alert, notification when CI breaks and when it is green again. |
| **Personal GitHub notifications** | Review requests, mentions, assignments, replies on your issues/PRs (e.g. to GladysAssistant/Gladys), attached to the matching tracked project. Requires a classic token with the `notifications` scope. |
Expand All @@ -38,7 +38,7 @@ Self-hosted (Docker), single-user, all data in one SQLite file.
| **Upstream version watch** | Latest release/tag of the repository (any forge), of another GitHub repository, of an npm package or a Docker Hub image, compared with the version *you* use/deploy → "update available" badge and notification. |
| **Bugs reported on forums** | **Discourse** forums (e.g. the [Gladys forum](https://community.gladysassistant.com): category, tag or search) and **RSS/Atom feeds** (keyword filter). One click turns a topic into a tracked bug. "Discourse: my mentions" source: only the posts that tag you (`@username`), with its own ntfy notification. When a bug that came from the forum is fixed, a ready-to-post message is offered ("fixed in version…"): copied, and the topic opens. **Followed topics**: every new reply of a topic (👁 button in the activity, or link pasted in the Activity tab) lands in the inbox and on ntfy. |
| **"Today" view** | Pick 3 to 5 bugs or tasks for the day (☀ in the lists, or from the view) and tick them off as you go; unfinished ones carry over to the next day. Alongside: overdue or due today items, GitHub review requests, suggestions (in progress, high priority), failing CI, time spent. |
| **Screenshots and attachments** | Paste (<kbd>Ctrl</kbd>+<kbd>V</kbd>) or drop a screenshot or a file into a bug description, a note or a spec: it is stored in `data/uploads/` and inserted as Markdown (images shown inline, other files linked). 25 MB maximum per file. |
| **Screenshots and attachments** | Paste (<kbd>Ctrl</kbd>+<kbd>V</kbd>) or drop a screenshot or a file into a bug description, a note or a spec: it is stored in `data/uploads/` and inserted as Markdown (images shown inline, other files linked). Images show as thumbnails below the field (click to enlarge) and “Preview” shows the rendered text. 25 MB maximum per file. |
| **Manual bugs & tasks** | Bug / feature / task / question, priority, status, due date, target version, external link. List or Kanban board (drag and drop). |
| **Specifications** | Markdown documents per project with a pre-filled template (context, goals, acceptance criteria…) and draft / in review / approved status. |
| **Notes** | Markdown notes per project or global, "Quick note" button everywhere in the app. |
Expand Down
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,8 @@ Auto-hébergé (Docker), mono-utilisateur, données dans un seul fichier SQLite.
| **Projets classés par catégories** | Freelance, Perso, Organisation (Gladys…), Autre — catégories modifiables avec couleur. Statut (idée, actif, maintenance, pause, archivé), client, tags, liens, épinglage. |
| **GitHub, GitLab, Gitea / Forgejo** | Chaque projet pointe vers un dépôt sur github.com, gitlab.com ou une instance auto-hébergée (GitLab, Gitea, Forgejo). Un token par instance dans **Paramètres → Forges et tokens**. |
| **Import de dépôts en masse** | Liste les dépôts d'un utilisateur, d'une organisation ou d'un groupe (filtre, forks, archivés) et crée les projets d'un coup avec catégorie, statut et suivi des releases. Les dépôts déjà suivis sont ignorés. |
| **Suivi des dépôts** | Issues et PR / MR ouvertes, étoiles, dernière activité. Filtres « Me concernant » (ouvert par toi, assigné, review demandée, mentionné — d'après le compte du token), par label, auteur ou titre, mémorisés par projet : pratique sur un dépôt très actif comme Gladys. Les **nouvelles** arrivent dans la boîte de réception ; un bouton « Suivre » les ajoute aux bugs & tâches. |
| **Mon GitHub** | Une page qui réunit, sur tous tes projets, les reviews qu'on te demande, tes PR, ce qui t'est assigné, tes mentions et tes issues. Chaque PR affiche son état : approuvée, changements demandés, conflit avec la branche principale, CI. Sur tes PR, une approbation, une demande de changements, un conflit ou une CI rouge arrive dans la boîte de réception et sur ntfy. |
| **Suivi des dépôts** | Issues et PR / MR ouvertes, étoiles, dernière activité. Filtres « Me concernant » (ouvert par toi, assigné, review demandée, mentionné — d'après le compte du token), par label, auteur ou titre, mémorisés par projet : pratique sur un dépôt très actif comme Gladys. Réglage par projet « Issues et PR suivies » : en mode Auto (par défaut), tout est suivi sur tes dépôts, et seulement ce qui te concerne sur ceux des autres (compteurs, tableau de bord, « En attente », notifications). Les **nouvelles** arrivent dans la boîte de réception ; un bouton « Suivre » les ajoute aux bugs & tâches. |
| **Mon GitHub** | Une page qui réunit, sur tous tes projets, les reviews qu'on te demande, tes PR, ce qui t'est assigné, tes mentions et tes issues. Chaque PR affiche son état : approuvée, changements demandés, conflit avec la branche principale, CI. Un clic en fait une tâche au titre explicite (« Résoudre le conflit : #3028… »). Sur tes PR, une approbation, une demande de changements, un conflit ou une CI rouge arrive dans la boîte de réception et sur ntfy. |
| **Créer une issue depuis un bug** | Un bug remonté par le forum devient une issue sur le dépôt (titre, description, lien du forum, version cible, label). Lien dans les deux sens : quand l'issue est fermée, le bug passe à « Terminé ». |
| **État de la CI** | GitHub Actions (dernier run de chaque workflow), pipelines GitLab, statuts de commit Gitea/Forgejo (Actions, Woodpecker, Drone) sur la branche principale : pastille verte/rouge (seuls les runs déclenchés par le code comptent : les tâches planifiées et les workflows lancés à la main sont ignorés), alerte au tableau de bord, notification quand la CI casse puis repasse au vert. |
| **Notifications GitHub perso** | Reviews demandées, mentions, assignations, réponses sur tes issues/PR (ex. vers GladysAssistant/Gladys), rattachées au projet suivi correspondant. Nécessite un token classique avec le scope `notifications`. |
Expand All @@ -37,7 +37,7 @@ Auto-hébergé (Docker), mono-utilisateur, données dans un seul fichier SQLite.
| **Veille des versions** | Dernière release/tag du dépôt (toute forge), d'un autre dépôt GitHub, d'un paquet npm ou d'une image Docker Hub, comparée à la version que *tu* utilises/déploies → badge « mise à jour disponible » et notification. |
| **Bugs remontés par un forum** | Forums **Discourse** (ex. [forum Gladys](https://community.gladysassistant.com) : catégorie, tag ou recherche) et **flux RSS/Atom** (filtre par mots-clés). Un clic transforme un sujet en bug suivi. Source « Discourse : mes mentions » : uniquement les messages qui te taguent (`@pseudo`), avec notification ntfy dédiée. Quand un bug venu du forum est corrigé, un message prêt à poster est proposé (« corrigé dans la version… ») : copié, et le sujet s'ouvre. **Sujets suivis** : chaque nouvelle réponse d'un sujet (bouton 👁 dans l'activité, ou lien collé dans l'onglet Activité) arrive dans la boîte de réception et sur ntfy. |
| **Vue « Aujourd'hui »** | Choisis 3 à 5 bugs ou tâches pour la journée (☀ dans les listes, ou depuis la vue) et coche-les au fil de l'eau ; ce qui n'est pas fini est reporté au lendemain. À côté : échéances dépassées ou du jour, reviews GitHub demandées, suggestions (en cours, prioritaires), CI en échec, temps passé. |
| **Captures et pièces jointes** | Colle (<kbd>Ctrl</kbd>+<kbd>V</kbd>) ou glisse une capture d'écran ou un fichier dans la description d'un bug, une note ou une spec : il est enregistré dans `data/uploads/` et inséré en Markdown (image affichée, autres fichiers en lien). 25 Mo maximum par fichier. |
| **Captures et pièces jointes** | Colle (<kbd>Ctrl</kbd>+<kbd>V</kbd>) ou glisse une capture d'écran ou un fichier dans la description d'un bug, une note ou une spec : il est enregistré dans `data/uploads/` et inséré en Markdown (image affichée, autres fichiers en lien). Les images apparaissent en miniatures sous le champ (clic pour agrandir) et « Prévisualiser » affiche le rendu. 25 Mo maximum par fichier. |
| **Bugs & tâches manuels** | Bug / fonctionnalité / tâche / question, priorité, statut, échéance, version cible, lien externe. Vue liste ou tableau Kanban (glisser-déposer). |
| **Spécifications** | Documents Markdown par projet avec modèle prérempli (contexte, objectifs, critères d'acceptation…) et statut brouillon / à relire / validée. |
| **Notes** | Notes Markdown par projet ou globales, bouton « Note rapide » partout dans l'app. |
Expand Down
8 changes: 7 additions & 1 deletion server/src/db.js
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,12 @@ const MIGRATIONS = [
-- Release checklist of a version: [{ label, done }].
ALTER TABLE milestones ADD COLUMN checklist TEXT;
`,
`
-- Which issues / PRs of the repository are followed: auto | all | mine.
ALTER TABLE projects ADD COLUMN github_scope TEXT NOT NULL DEFAULT 'auto';
-- Effective value (1 = only those that concern the user), kept up to date.
ALTER TABLE projects ADD COLUMN mine_only INTEGER NOT NULL DEFAULT 0;
`,
]

export function openDb(file = join(DATA_PATH, 'projectory.db')) {
Expand Down Expand Up @@ -223,7 +229,7 @@ export function decode(row) {
try { out[col] = JSON.parse(out[col]) } catch { /* keep raw */ }
}
}
for (const col of ['pinned', 'draft', 'notify']) if (col in out) out[col] = !!out[col]
for (const col of ['pinned', 'draft', 'notify', 'mine_only']) if (col in out) out[col] = !!out[col]
return out
}

Expand Down
3 changes: 2 additions & 1 deletion server/src/insights.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { VISIBLE_ITEM } from './visibility.js'
import { getConfig } from './db.js'
import { tr } from './i18n.js'
import { compareVersions } from './sync/http.js'
Expand All @@ -17,7 +18,7 @@ export function findStale(db, now = new Date()) {
const base = `SELECT g.id, g.project_id, g.type, g.number, g.title, g.url, g.author, g.comments, g.created_at, g.updated_at,
p.name AS project_name, p.forge
FROM github_items g JOIN projects p ON p.id = g.project_id
WHERE p.status != 'archived'`
WHERE p.status != 'archived' AND ${VISIBLE_ITEM}`
const issues = db.prepare(`${base} AND g.type = 'issue' AND g.comments = 0 AND g.created_at <= ?`).all(daysAgo(issue_days, now))
.map((r) => ({ ...r, reason: 'no_reply', age_days: ageDays(r.created_at, now) }))
const prs = db.prepare(`${base} AND g.type = 'pr' AND g.draft = 0 AND g.updated_at <= ?`).all(daysAgo(pr_days, now))
Expand Down
2 changes: 1 addition & 1 deletion server/src/routes/integrations.js
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,7 @@ export default async function integrationRoutes(app, { db }) {
project_id: g.project_id,
kind: req.body?.kind || (g.type === 'pr' ? 'task' : 'bug'),
priority: req.body?.priority || 'normal',
title: g.title,
title: String(req.body?.title || '').trim() || g.title,
source: 'github',
issue_number: g.type === 'issue' ? g.number : null,
issue_url: g.url,
Expand Down
7 changes: 4 additions & 3 deletions server/src/routes/overview.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { forgeContext } from '../sync/forges/index.js'
import { tr } from '../i18n.js'
import { findStale } from '../insights.js'
import { todayView } from '../today.js'
import { VISIBLE_ITEM } from '../visibility.js'

const REPO_SOURCES = "'github', 'gitlab', 'gitea'"
const INBOX_SQL = `SELECT x.*, p.name AS project_name FROM inbox x LEFT JOIN projects p ON p.id = x.project_id`
Expand Down Expand Up @@ -59,8 +60,8 @@ export default async function overviewRoutes(app, { db }) {
stats: {
projects: projects.length,
active: projects.filter((p) => p.status === 'active').length,
open_issues: count("SELECT count(*) n FROM github_items WHERE type = 'issue'"),
open_prs: count("SELECT count(*) n FROM github_items WHERE type = 'pr'"),
open_issues: count(`SELECT count(*) n FROM github_items g JOIN projects p ON p.id = g.project_id WHERE g.type = 'issue' AND p.status != 'archived' AND ${VISIBLE_ITEM}`),
open_prs: count(`SELECT count(*) n FROM github_items g JOIN projects p ON p.id = g.project_id WHERE g.type = 'pr' AND p.status != 'archived' AND ${VISIBLE_ITEM}`),
ci_failing: projects.filter((p) => p.ci === 'failure').length,
stale: findStale(db).length,
open_bugs: count("SELECT count(*) n FROM items WHERE kind = 'bug' AND status IN ('todo', 'in_progress')"),
Expand All @@ -80,7 +81,7 @@ export default async function overviewRoutes(app, { db }) {
stale: findStale(db).slice(0, 8),
recent_prs: db.prepare(
`SELECT g.*, p.name AS project_name FROM github_items g JOIN projects p ON p.id = g.project_id
WHERE g.type = 'pr' ORDER BY g.updated_at DESC LIMIT 8`
WHERE g.type = 'pr' AND ${VISIBLE_ITEM} ORDER BY g.updated_at DESC LIMIT 8`
).all().map(decode),
sync: syncState,
}
Expand Down
Loading
Loading