Files
thoughtsync/frontend/src/router/index.ts
T
bvandeusenandClaude Opus 4.8 f325402902
CI & Build / Python lint (push) Successful in 2s
CI & Build / TypeScript typecheck (push) Successful in 6s
Desktop (Tauri) / Tauri desktop (Linux) (push) Failing after 9s
CI & Build / Python tests (push) Successful in 13s
CI & Build / Build & push image (push) Successful in 32s
desktop: robust startup + operation logging (portability troubleshooting)
There was essentially no logging — useless for proving the app renders across
different environments. Add real observability:

- tauri-plugin-log -> stdout (so `2>&1 | tee` captures a run) AND a persistent
  file in the app log dir (grabbable after the fact on any machine). Level Info.
- Startup diagnostics: app version, OS/arch, the Linux display/session stack
  (XDG_SESSION_TYPE, desktop, Wayland/X11, GDK_BACKEND), the WebKit render-
  hardening vars actually in effect, resolved log + data dirs, DB open/migrate
  result, and note/label counts.
- log_event command + a frontend logEvent() helper: boot line (data source +
  WebKit user-agent) from main.ts, first-route config/session/destination from
  the router guard, and — via the bridge invoke() wrapper — every failed Tauri
  command named with its error, so a broken basic function is self-identifying.

Task 2040.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FRgehjoz7Yv8LkUfADxACm
2026-07-25 10:18:06 -04:00

87 lines
3.0 KiB
TypeScript

import { createRouter, createWebHistory } from "vue-router";
import { useSessionStore } from "../stores/session";
import { useConfigStore } from "../stores/config";
import { logEvent } from "../desktop/bridge";
// One-time boot diagnostic: the first navigation is where config + session resolve,
// so it's the moment that tells us whether the app got past its startup gate.
let bootLogged = false;
const router = createRouter({
history: createWebHistory(),
routes: [
{
// Persistent authed shell (sidebar + top bar + search); children render in it.
path: "/",
component: () => import("../components/AppShell.vue"),
meta: { requiresAuth: true },
children: [
{ path: "", name: "board", component: () => import("../views/BoardView.vue") },
{ path: "archive", name: "archive", component: () => import("../views/BoardView.vue") },
{ path: "trash", name: "trash", component: () => import("../views/BoardView.vue") },
{ path: "label/:id", name: "label", component: () => import("../views/BoardView.vue") },
{ path: "search", name: "search", component: () => import("../views/SearchView.vue") },
{ path: "graph", name: "graph", component: () => import("../views/GraphView.vue") },
{ path: "reminders", name: "reminders", component: () => import("../views/RemindersView.vue") },
{ path: "timeline", name: "timeline", component: () => import("../views/TimelineView.vue") },
],
},
{
path: "/settings",
name: "settings",
component: () => import("../views/SettingsView.vue"),
meta: { requiresAuth: true, requiresAdmin: true },
},
{
// Per-user account: linked devices (native-client sync tokens). Any user.
path: "/account",
name: "account",
component: () => import("../views/AccountView.vue"),
meta: { requiresAuth: true },
},
{
path: "/login",
name: "login",
component: () => import("../views/LoginView.vue"),
meta: { guestOnly: true },
},
{
path: "/register",
name: "register",
component: () => import("../views/RegisterView.vue"),
meta: { guestOnly: true },
},
],
});
router.beforeEach(async (to) => {
const session = useSessionStore();
const config = useConfigStore();
await config.load();
if (!session.loaded) {
await session.fetchMe();
}
if (!bootLogged) {
bootLogged = true;
logEvent(
"info",
`first route: config(site=${config.siteName}) session(user=${session.user?.email ?? "none"}) -> ${String(to.name ?? to.path)}`,
);
}
if (to.meta.requiresAuth && !session.user) {
return { name: "login", query: to.fullPath !== "/" ? { redirect: to.fullPath } : undefined };
}
if (to.meta.requiresAdmin && !session.user?.is_admin) {
return { name: "board" };
}
if (to.name === "register" && !config.allowRegistration) {
return { name: "login" };
}
if (to.meta.guestOnly && session.user) {
return { name: "board" };
}
return true;
});
export default router;