vibedoc 1.0.1 → 1.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.next/BUILD_ID +1 -1
- package/.next/app-build-manifest.json +23 -19
- package/.next/app-path-routes-manifest.json +1 -1
- package/.next/build-manifest.json +2 -2
- package/.next/prerender-manifest.js +1 -1
- package/.next/prerender-manifest.json +1 -1
- package/.next/server/app/(app)/activity/page_client-reference-manifest.js +1 -1
- package/.next/server/app/(app)/board/page_client-reference-manifest.js +1 -1
- package/.next/server/app/(app)/docs/page.js +1 -1
- package/.next/server/app/(app)/docs/page_client-reference-manifest.js +1 -1
- package/.next/server/app/(app)/memory/page_client-reference-manifest.js +1 -1
- package/.next/server/app/(app)/settings/page_client-reference-manifest.js +1 -1
- package/.next/server/app/(app)/setup/page.js +2 -1
- package/.next/server/app/(app)/setup/page.js.nft.json +1 -1
- package/.next/server/app/(app)/setup/page_client-reference-manifest.js +1 -1
- package/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
- package/.next/server/app/_not-found.html +1 -1
- package/.next/server/app/_not-found.rsc +1 -1
- package/.next/server/app/activity.html +1 -1
- package/.next/server/app/activity.rsc +2 -2
- package/.next/server/app/api/mcp/route.js +2 -2
- package/.next/server/app/api/mcp/route.js.nft.json +1 -1
- package/.next/server/app/api/setup/generate/route.js +7 -7
- package/.next/server/app/api/setup/generate/route.js.nft.json +1 -1
- package/.next/server/app/board.html +1 -1
- package/.next/server/app/board.rsc +2 -2
- package/.next/server/app/docs.html +1 -1
- package/.next/server/app/docs.rsc +3 -3
- package/.next/server/app/index.html +1 -1
- package/.next/server/app/index.rsc +1 -1
- package/.next/server/app/memory.html +1 -1
- package/.next/server/app/memory.rsc +2 -2
- package/.next/server/app/page_client-reference-manifest.js +1 -1
- package/.next/server/app/settings.html +1 -1
- package/.next/server/app/settings.rsc +2 -2
- package/.next/server/app/setup.html +1 -1
- package/.next/server/app/setup.rsc +3 -3
- package/.next/server/app-paths-manifest.json +10 -10
- package/.next/server/chunks/118.js +2107 -0
- package/.next/server/chunks/191.js +1558 -501
- package/.next/server/middleware-build-manifest.js +1 -1
- package/.next/server/pages/404.html +1 -1
- package/.next/server/pages/500.html +1 -1
- package/.next/server/pages-manifest.json +1 -1
- package/.next/server/server-reference-manifest.js +1 -1
- package/.next/server/server-reference-manifest.json +1 -1
- package/.next/static/chunks/5179-76391417caead0bc.js +1 -0
- package/.next/static/chunks/6441-8a1066f99fe4fead.js +1 -0
- package/.next/static/chunks/app/(app)/docs/{page-17670ed46c3594e6.js → page-f5615cefbd3d1c64.js} +1 -1
- package/.next/static/chunks/app/(app)/{layout-34b4046ccf919d3f.js → layout-ef459e6f184dba6b.js} +1 -1
- package/.next/static/chunks/app/(app)/setup/page-a47e3a9a44666f50.js +1 -0
- package/.next/static/css/48c54dd7bfa2411e.css +5 -0
- package/package.json +1 -1
- package/.next/server/chunks/661.js +0 -1050
- package/.next/static/chunks/845-f90ef49ed88a44a2.js +0 -1
- package/.next/static/chunks/app/(app)/setup/page-5fd7500bd578e730.js +0 -1
- package/.next/static/css/518ce8dddf398f57.css +0 -5
- /package/.next/static/{moF7Sng2pYdyIpULgHRjM → SozubT4AiNYJ3ynkRV0zo}/_buildManifest.js +0 -0
- /package/.next/static/{moF7Sng2pYdyIpULgHRjM → SozubT4AiNYJ3ynkRV0zo}/_ssgManifest.js +0 -0
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
exports.id=191,exports.ids=[191],exports.modules={1562:(e,t,a)=>{Promise.resolve().then(a.t.bind(a,9388,23)),Promise.resolve().then(a.t.bind(a,1152,23)),Promise.resolve().then(a.t.bind(a,2764,23)),Promise.resolve().then(a.t.bind(a,6894,23)),Promise.resolve().then(a.t.bind(a,3299,23)),Promise.resolve().then(a.t.bind(a,184,23))},9788:(e,t,a)=>{Promise.resolve().then(a.bind(a,151))},103:()=>{},151:(e,t,a)=>{"use strict";a.r(t),a.d(t,{default:()=>eh});var s=a(7486),r=a(618),n=a(6811),i=a(6266);function o(){return s.jsx("div",{className:"min-h-screen flex items-center justify-center",children:(0,s.jsxs)("div",{className:"text-center",children:[s.jsx("div",{className:"flex gap-1.5 justify-center mb-4",children:[0,1,2].map(e=>s.jsx("div",{className:"w-2 h-2 rounded-full bg-accent animate-pulse-dot",style:{animationDelay:`${.15*e}s`}},e))}),s.jsx("p",{className:"text-muted text-sm font-mono",children:"Loading project..."})]})})}var d=a(9228);function l({projects:e,activeProject:t,currentName:a,onSelect:r}){return(0,s.jsxs)(d.h_,{children:[s.jsx(d.$F,{asChild:!0,children:(0,s.jsxs)("button",{className:"flex items-center gap-1.5 px-3 py-1.5 rounded-md bg-surface2 border border-border text-sm hover:border-border2 transition-colors",children:[s.jsx("span",{className:"text-txt font-medium truncate max-w-[200px]",children:a||"Select project"}),s.jsx("span",{className:"text-muted text-xs",children:"▾"})]})}),s.jsx(d.AW,{className:"w-64 bg-surface border-border2 text-txt",align:"start",children:0===e.length?s.jsx("div",{className:"px-3 py-2 text-sm text-muted",children:"No projects found"}):e.map(e=>s.jsx(d.Xi,{onClick:()=>r(e.root),className:`cursor-pointer hover:bg-surface2 focus:bg-surface2 ${e.root===t?"text-accent":""}`,children:(0,s.jsxs)("div",{children:[s.jsx("div",{className:"font-medium",children:e.name}),s.jsx("div",{className:"text-xs text-muted truncate font-mono",children:e.root})]})},e.root))})]})}var c=a(5819);function u({board:e}){return(0,s.jsxs)("div",{className:"flex items-center gap-1.5",children:[(0,s.jsxs)(c.C,{variant:"secondary",className:"gap-1 text-xs font-mono text-amber",children:["\uD83D\uDD28 ",e["in-progress"]||0]}),(0,s.jsxs)(c.C,{variant:"secondary",className:"gap-1 text-xs font-mono text-muted",children:["\uD83D\uDCCB ",e.todo||0]}),(0,s.jsxs)(c.C,{variant:"secondary",className:"gap-1 text-xs font-mono text-teal",children:["✅ ",e.done||0]})]})}var m=a(5098);function p({active:e}){return(0,s.jsxs)("div",{className:"flex items-center gap-1.5 text-xs font-mono text-muted",children:[s.jsx("div",{className:(0,m.cn)("w-1.5 h-1.5 rounded-full transition-colors duration-500",e?"bg-teal shadow-[0_0_6px_#4fd8b4]":"bg-border2")}),s.jsx("span",{children:e?"live update":"connected"})]})}var f=a(8942),h=a(4039),b=a(1317),g=a(3068),x=a(2162),v=a(6637),y=a(2439),N=a(2153);let w=y.fC;y.xz,y.x8;let j=y.h_,k=r.forwardRef(({className:e,...t},a)=>s.jsx(y.aV,{className:(0,m.cn)("fixed inset-0 z-50 bg-black/80 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0",e),...t,ref:a}));k.displayName=y.aV.displayName;let C=(0,h.j)("fixed z-50 gap-4 bg-white p-6 shadow-lg transition ease-in-out data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:duration-300 data-[state=open]:duration-500 dark:bg-slate-950",{variants:{side:{top:"inset-x-0 top-0 border-b data-[state=closed]:slide-out-to-top data-[state=open]:slide-in-from-top",bottom:"inset-x-0 bottom-0 border-t data-[state=closed]:slide-out-to-bottom data-[state=open]:slide-in-from-bottom",left:"inset-y-0 left-0 h-full w-3/4 border-r data-[state=closed]:slide-out-to-left data-[state=open]:slide-in-from-left sm:max-w-sm",right:"inset-y-0 right-0 h-full w-3/4 border-l data-[state=closed]:slide-out-to-right data-[state=open]:slide-in-from-right sm:max-w-sm"}},defaultVariants:{side:"right"}}),R=r.forwardRef(({side:e="right",className:t,children:a,...r},n)=>(0,s.jsxs)(j,{children:[s.jsx(k,{}),(0,s.jsxs)(y.VY,{ref:n,className:(0,m.cn)(C({side:e}),t),...r,children:[a,(0,s.jsxs)(y.x8,{className:"absolute right-4 top-4 rounded-sm opacity-70 ring-offset-white transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-slate-950 focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-slate-100 dark:ring-offset-slate-950 dark:focus:ring-slate-300 dark:data-[state=open]:bg-slate-800",children:[s.jsx(N.Z,{className:"h-4 w-4"}),s.jsx("span",{className:"sr-only",children:"Close"})]})]})]}));R.displayName=y.VY.displayName;let E=({className:e,...t})=>s.jsx("div",{className:(0,m.cn)("flex flex-col space-y-2 text-center sm:text-left",e),...t});E.displayName="SheetHeader";let S=r.forwardRef(({className:e,...t},a)=>s.jsx(y.Dx,{ref:a,className:(0,m.cn)("text-lg font-semibold text-slate-950 dark:text-slate-50",e),...t}));S.displayName=y.Dx.displayName;let A=r.forwardRef(({className:e,...t},a)=>s.jsx(y.dk,{ref:a,className:(0,m.cn)("text-sm text-slate-500 dark:text-slate-400",e),...t}));function P({className:e,...t}){return s.jsx("div",{className:(0,m.cn)("animate-pulse rounded-md bg-slate-100 dark:bg-slate-800",e),...t})}A.displayName=y.dk.displayName;var T=a(5875);let D=r.createContext(null);function I(){let e=r.useContext(D);if(!e)throw Error("useSidebar must be used within a SidebarProvider.");return e}let _=r.forwardRef(({defaultOpen:e=!0,open:t,onOpenChange:a,className:n,style:i,children:o,...d},l)=>{let c=function(){let[e,t]=r.useState(void 0);return r.useEffect(()=>{let e=window.matchMedia("(max-width: 767px)"),a=()=>{t(window.innerWidth<768)};return e.addEventListener("change",a),t(window.innerWidth<768),()=>e.removeEventListener("change",a)},[]),!!e}(),[u,p]=r.useState(!1),[f,h]=r.useState(e),b=t??f,g=r.useCallback(e=>{let t="function"==typeof e?e(b):e;a?a(t):h(t),document.cookie=`sidebar_state=${t}; path=/; max-age=604800`},[a,b]),x=r.useCallback(()=>c?p(e=>!e):g(e=>!e),[c,g,p]);r.useEffect(()=>{let e=e=>{"b"===e.key&&(e.metaKey||e.ctrlKey)&&(e.preventDefault(),x())};return window.addEventListener("keydown",e),()=>window.removeEventListener("keydown",e)},[x]);let v=b?"expanded":"collapsed",y=r.useMemo(()=>({state:v,open:b,setOpen:g,isMobile:c,openMobile:u,setOpenMobile:p,toggleSidebar:x}),[v,b,g,c,u,p,x]);return s.jsx(D.Provider,{value:y,children:s.jsx(T.pn,{delayDuration:0,children:s.jsx("div",{style:{"--sidebar-width":"16rem","--sidebar-width-icon":"3rem",...i},className:(0,m.cn)("group/sidebar-wrapper flex min-h-svh w-full has-[[data-variant=inset]]:bg-sidebar",n),ref:l,...d,children:o})})})});_.displayName="SidebarProvider";let O=r.forwardRef(({side:e="left",variant:t="sidebar",collapsible:a="offcanvas",className:r,children:n,...i},o)=>{let{isMobile:d,state:l,openMobile:c,setOpenMobile:u}=I();return"none"===a?s.jsx("div",{className:(0,m.cn)("flex h-full w-[--sidebar-width] flex-col bg-sidebar text-sidebar-foreground",r),ref:o,...i,children:n}):d?s.jsx(w,{open:c,onOpenChange:u,...i,children:(0,s.jsxs)(R,{"data-sidebar":"sidebar","data-mobile":"true",className:"w-[--sidebar-width] bg-sidebar p-0 text-sidebar-foreground [&>button]:hidden",style:{"--sidebar-width":"18rem"},side:e,children:[(0,s.jsxs)(E,{className:"sr-only",children:[s.jsx(S,{children:"Sidebar"}),s.jsx(A,{children:"Displays the mobile sidebar."})]}),s.jsx("div",{className:"flex h-full w-full flex-col",children:n})]})}):(0,s.jsxs)("div",{ref:o,className:"group peer hidden text-sidebar-foreground md:block","data-state":l,"data-collapsible":"collapsed"===l?a:"","data-variant":t,"data-side":e,children:[s.jsx("div",{className:(0,m.cn)("relative w-[--sidebar-width] bg-transparent transition-[width] duration-200 ease-linear","group-data-[collapsible=offcanvas]:w-0","group-data-[side=right]:rotate-180","floating"===t||"inset"===t?"group-data-[collapsible=icon]:w-[calc(var(--sidebar-width-icon)_+_theme(spacing.4))]":"group-data-[collapsible=icon]:w-[--sidebar-width-icon]")}),s.jsx("div",{className:(0,m.cn)("fixed inset-y-0 z-10 hidden h-svh w-[--sidebar-width] transition-[left,right,width] duration-200 ease-linear md:flex","left"===e?"left-0 group-data-[collapsible=offcanvas]:left-[calc(var(--sidebar-width)*-1)]":"right-0 group-data-[collapsible=offcanvas]:right-[calc(var(--sidebar-width)*-1)]","floating"===t||"inset"===t?"p-2 group-data-[collapsible=icon]:w-[calc(var(--sidebar-width-icon)_+_theme(spacing.4)_+2px)]":"group-data-[collapsible=icon]:w-[--sidebar-width-icon] group-data-[side=left]:border-r group-data-[side=right]:border-l",r),...i,children:s.jsx("div",{"data-sidebar":"sidebar",className:"flex h-full w-full flex-col bg-sidebar group-data-[variant=floating]:rounded-lg group-data-[variant=floating]:border group-data-[variant=floating]:border-sidebar-border group-data-[variant=floating]:shadow",children:n})})]})});O.displayName="Sidebar";let z=r.forwardRef(({className:e,onClick:t,...a},r)=>{let{toggleSidebar:n}=I();return(0,s.jsxs)(g.z,{ref:r,"data-sidebar":"trigger",variant:"ghost",size:"icon",className:(0,m.cn)("h-7 w-7",e),onClick:e=>{t?.(e),n()},...a,children:[s.jsx(b.Z,{}),s.jsx("span",{className:"sr-only",children:"Toggle Sidebar"})]})});z.displayName="SidebarTrigger",r.forwardRef(({className:e,...t},a)=>{let{toggleSidebar:r}=I();return s.jsx("button",{ref:a,"data-sidebar":"rail","aria-label":"Toggle Sidebar",tabIndex:-1,onClick:r,title:"Toggle Sidebar",className:(0,m.cn)("absolute inset-y-0 z-20 hidden w-4 -translate-x-1/2 transition-all ease-linear after:absolute after:inset-y-0 after:left-1/2 after:w-[2px] hover:after:bg-sidebar-border group-data-[side=left]:-right-4 group-data-[side=right]:left-0 sm:flex","[[data-side=left]_&]:cursor-w-resize [[data-side=right]_&]:cursor-e-resize","[[data-side=left][data-state=collapsed]_&]:cursor-e-resize [[data-side=right][data-state=collapsed]_&]:cursor-w-resize","group-data-[collapsible=offcanvas]:translate-x-0 group-data-[collapsible=offcanvas]:after:left-full group-data-[collapsible=offcanvas]:hover:bg-sidebar","[[data-side=left][data-collapsible=offcanvas]_&]:-right-2","[[data-side=right][data-collapsible=offcanvas]_&]:-left-2",e),...t})}).displayName="SidebarRail";let M=r.forwardRef(({className:e,...t},a)=>s.jsx("main",{ref:a,className:(0,m.cn)("relative flex w-full flex-1 flex-col bg-white dark:bg-slate-950","md:peer-data-[variant=inset]:m-2 md:peer-data-[state=collapsed]:peer-data-[variant=inset]:ml-2 md:peer-data-[variant=inset]:ml-0 md:peer-data-[variant=inset]:rounded-xl md:peer-data-[variant=inset]:shadow",e),...t}));M.displayName="SidebarInset",r.forwardRef(({className:e,...t},a)=>s.jsx(x.I,{ref:a,"data-sidebar":"input",className:(0,m.cn)("h-8 w-full bg-white shadow-none focus-visible:ring-2 focus-visible:ring-sidebar-ring dark:bg-slate-950",e),...t})).displayName="SidebarInput";let U=r.forwardRef(({className:e,...t},a)=>s.jsx("div",{ref:a,"data-sidebar":"header",className:(0,m.cn)("flex flex-col gap-2 p-2",e),...t}));U.displayName="SidebarHeader",r.forwardRef(({className:e,...t},a)=>s.jsx("div",{ref:a,"data-sidebar":"footer",className:(0,m.cn)("flex flex-col gap-2 p-2",e),...t})).displayName="SidebarFooter";let L=r.forwardRef(({className:e,...t},a)=>s.jsx(v.Z,{ref:a,"data-sidebar":"separator",className:(0,m.cn)("mx-2 w-auto bg-sidebar-border",e),...t}));L.displayName="SidebarSeparator";let q=r.forwardRef(({className:e,...t},a)=>s.jsx("div",{ref:a,"data-sidebar":"content",className:(0,m.cn)("flex min-h-0 flex-1 flex-col gap-2 overflow-auto group-data-[collapsible=icon]:overflow-hidden",e),...t}));q.displayName="SidebarContent";let B=r.forwardRef(({className:e,...t},a)=>s.jsx("div",{ref:a,"data-sidebar":"group",className:(0,m.cn)("relative flex w-full min-w-0 flex-col p-2",e),...t}));B.displayName="SidebarGroup";let K=r.forwardRef(({className:e,asChild:t=!1,...a},r)=>{let n=t?f.g7:"div";return s.jsx(n,{ref:r,"data-sidebar":"group-label",className:(0,m.cn)("flex h-8 shrink-0 items-center rounded-md px-2 text-xs font-medium text-sidebar-foreground/70 outline-none ring-sidebar-ring transition-[margin,opacity] duration-200 ease-linear focus-visible:ring-2 [&>svg]:size-4 [&>svg]:shrink-0","group-data-[collapsible=icon]:-mt-8 group-data-[collapsible=icon]:opacity-0",e),...a})});K.displayName="SidebarGroupLabel",r.forwardRef(({className:e,asChild:t=!1,...a},r)=>{let n=t?f.g7:"button";return s.jsx(n,{ref:r,"data-sidebar":"group-action",className:(0,m.cn)("absolute right-3 top-3.5 flex aspect-square w-5 items-center justify-center rounded-md p-0 text-sidebar-foreground outline-none ring-sidebar-ring transition-transform hover:bg-sidebar-accent hover:text-sidebar-accent-foreground focus-visible:ring-2 [&>svg]:size-4 [&>svg]:shrink-0","after:absolute after:-inset-2 after:md:hidden","group-data-[collapsible=icon]:hidden",e),...a})}).displayName="SidebarGroupAction";let F=r.forwardRef(({className:e,...t},a)=>s.jsx("div",{ref:a,"data-sidebar":"group-content",className:(0,m.cn)("w-full text-sm",e),...t}));F.displayName="SidebarGroupContent";let G=r.forwardRef(({className:e,...t},a)=>s.jsx("ul",{ref:a,"data-sidebar":"menu",className:(0,m.cn)("flex w-full min-w-0 flex-col gap-1",e),...t}));G.displayName="SidebarMenu";let V=r.forwardRef(({className:e,...t},a)=>s.jsx("li",{ref:a,"data-sidebar":"menu-item",className:(0,m.cn)("group/menu-item relative",e),...t}));V.displayName="SidebarMenuItem";let Z=(0,h.j)("peer/menu-button flex w-full items-center gap-2 overflow-hidden rounded-md p-2 text-left text-sm outline-none ring-sidebar-ring transition-[width,height,padding] hover:bg-sidebar-accent hover:text-sidebar-accent-foreground focus-visible:ring-2 active:bg-sidebar-accent active:text-sidebar-accent-foreground disabled:pointer-events-none disabled:opacity-50 group-has-[[data-sidebar=menu-action]]/menu-item:pr-8 aria-disabled:pointer-events-none aria-disabled:opacity-50 data-[active=true]:bg-sidebar-accent data-[active=true]:font-medium data-[active=true]:text-sidebar-accent-foreground data-[state=open]:hover:bg-sidebar-accent data-[state=open]:hover:text-sidebar-accent-foreground group-data-[collapsible=icon]:!size-8 group-data-[collapsible=icon]:!p-2 [&>span:last-child]:truncate [&>svg]:size-4 [&>svg]:shrink-0",{variants:{variant:{default:"hover:bg-sidebar-accent hover:text-sidebar-accent-foreground",outline:"bg-white shadow-[0_0_0_1px_hsl(var(--sidebar-border))] hover:bg-sidebar-accent hover:text-sidebar-accent-foreground hover:shadow-[0_0_0_1px_hsl(var(--sidebar-accent))] dark:bg-slate-950"},size:{default:"h-8 text-sm",sm:"h-7 text-xs",lg:"h-12 text-sm group-data-[collapsible=icon]:!p-0"}},defaultVariants:{variant:"default",size:"default"}}),$=r.forwardRef(({asChild:e=!1,isActive:t=!1,variant:a="default",size:r="default",tooltip:n,className:i,...o},d)=>{let l=e?f.g7:"button",{isMobile:c,state:u}=I(),p=s.jsx(l,{ref:d,"data-sidebar":"menu-button","data-size":r,"data-active":t,className:(0,m.cn)(Z({variant:a,size:r}),i),...o});return n?("string"==typeof n&&(n={children:n}),(0,s.jsxs)(T.u,{children:[s.jsx(T.aJ,{asChild:!0,children:p}),s.jsx(T._v,{side:"right",align:"center",hidden:"collapsed"!==u||c,...n})]})):p});function W({summary:e,projects:t,activeProject:a,liveIndicator:r,onProjectChange:n}){return(0,s.jsxs)("header",{className:"h-12 border-b border-border flex items-center px-4 gap-4 flex-shrink-0 bg-surface/80 backdrop-blur-sm sticky top-0 z-50",children:[s.jsx(z,{className:"-ml-1"}),s.jsx(v.Z,{orientation:"vertical",className:"mr-2 h-4"}),(0,s.jsxs)("div",{className:"flex items-center gap-2 flex-shrink-0",children:[s.jsx("div",{className:"w-6 h-6 rounded-md bg-gradient-to-br from-accent to-teal flex items-center justify-center text-xs",children:"⬡"}),s.jsx("span",{className:"font-mono text-xs text-muted tracking-widest uppercase",children:"VibeDoc"})]}),s.jsx(l,{projects:t,activeProject:a,currentName:e?.name||"",onSelect:n}),e&&s.jsx(u,{board:e.tasks.board}),s.jsx("div",{className:"flex-1"}),s.jsx(p,{active:r}),(0,s.jsxs)("div",{className:"hidden md:flex items-center gap-1.5 px-2 py-1 rounded bg-surface2 border border-border",children:[s.jsx("span",{className:"text-xs font-mono text-muted",children:"MCP"}),s.jsx("code",{className:"text-xs font-mono text-accent",children:"localhost:3000/api/mcp"})]})]})}$.displayName="SidebarMenuButton",r.forwardRef(({className:e,asChild:t=!1,showOnHover:a=!1,...r},n)=>{let i=t?f.g7:"button";return s.jsx(i,{ref:n,"data-sidebar":"menu-action",className:(0,m.cn)("absolute right-1 top-1.5 flex aspect-square w-5 items-center justify-center rounded-md p-0 text-sidebar-foreground outline-none ring-sidebar-ring transition-transform hover:bg-sidebar-accent hover:text-sidebar-accent-foreground focus-visible:ring-2 peer-hover/menu-button:text-sidebar-accent-foreground [&>svg]:size-4 [&>svg]:shrink-0","after:absolute after:-inset-2 after:md:hidden","peer-data-[size=sm]/menu-button:top-1","peer-data-[size=default]/menu-button:top-1.5","peer-data-[size=lg]/menu-button:top-2.5","group-data-[collapsible=icon]:hidden",a&&"group-focus-within/menu-item:opacity-100 group-hover/menu-item:opacity-100 data-[state=open]:opacity-100 peer-data-[active=true]/menu-button:text-sidebar-accent-foreground md:opacity-0",e),...r})}).displayName="SidebarMenuAction",r.forwardRef(({className:e,...t},a)=>s.jsx("div",{ref:a,"data-sidebar":"menu-badge",className:(0,m.cn)("pointer-events-none absolute right-1 flex h-5 min-w-5 select-none items-center justify-center rounded-md px-1 text-xs font-medium tabular-nums text-sidebar-foreground","peer-hover/menu-button:text-sidebar-accent-foreground peer-data-[active=true]/menu-button:text-sidebar-accent-foreground","peer-data-[size=sm]/menu-button:top-1","peer-data-[size=default]/menu-button:top-1.5","peer-data-[size=lg]/menu-button:top-2.5","group-data-[collapsible=icon]:hidden",e),...t})).displayName="SidebarMenuBadge",r.forwardRef(({className:e,showIcon:t=!1,...a},n)=>{let i=r.useMemo(()=>`${Math.floor(40*Math.random())+50}%`,[]);return(0,s.jsxs)("div",{ref:n,"data-sidebar":"menu-skeleton",className:(0,m.cn)("flex h-8 items-center gap-2 rounded-md px-2",e),...a,children:[t&&s.jsx(P,{className:"size-4 rounded-md","data-sidebar":"menu-skeleton-icon"}),s.jsx(P,{className:"h-4 max-w-[--skeleton-width] flex-1","data-sidebar":"menu-skeleton-text",style:{"--skeleton-width":i}})]})}).displayName="SidebarMenuSkeleton",r.forwardRef(({className:e,...t},a)=>s.jsx("ul",{ref:a,"data-sidebar":"menu-sub",className:(0,m.cn)("mx-3.5 flex min-w-0 translate-x-px flex-col gap-1 border-l border-sidebar-border px-2.5 py-0.5","group-data-[collapsible=icon]:hidden",e),...t})).displayName="SidebarMenuSub",r.forwardRef(({...e},t)=>s.jsx("li",{ref:t,...e})).displayName="SidebarMenuSubItem",r.forwardRef(({asChild:e=!1,size:t="md",isActive:a,className:r,...n},i)=>{let o=e?f.g7:"a";return s.jsx(o,{ref:i,"data-sidebar":"menu-sub-button","data-size":t,"data-active":a,className:(0,m.cn)("flex h-7 min-w-0 -translate-x-px items-center gap-2 overflow-hidden rounded-md px-2 text-sidebar-foreground outline-none ring-sidebar-ring hover:bg-sidebar-accent hover:text-sidebar-accent-foreground focus-visible:ring-2 active:bg-sidebar-accent active:text-sidebar-accent-foreground disabled:pointer-events-none disabled:opacity-50 aria-disabled:pointer-events-none aria-disabled:opacity-50 [&>span:last-child]:truncate [&>svg]:size-4 [&>svg]:shrink-0 [&>svg]:text-sidebar-accent-foreground","data-[active=true]:bg-sidebar-accent data-[active=true]:text-sidebar-accent-foreground","sm"===t&&"text-xs","md"===t&&"text-sm","group-data-[collapsible=icon]:hidden",r),...n})}).displayName="SidebarMenuSubButton";var J=a(3596),H=a(7987),Y=a(9529),X=a(8673),Q=a(5314),ee=a(6034),et=a(771),ea=a(4119),es=a(7834),er=a(8165);let en=[{href:"/board",icon:J.Z,label:"Board"},{href:"/docs",icon:H.Z,label:"Docs"},{href:"/activity",icon:Y.Z,label:"Activity"},{href:"/memory",icon:X.Z,label:"Memory"},{href:"/settings",icon:Q.Z,label:"Settings"}],ei=[{status:"in-progress",icon:ee.Z,label:"Active"},{status:"blocked",icon:et.Z,label:"Blocked"},{status:"todo",icon:ea.Z,label:"Todo"},{status:"done",icon:es.Z,label:"Done"}];function eo({board:e}){let t=(0,n.usePathname)();return(0,s.jsxs)(O,{collapsible:"icon",children:[s.jsx(U,{children:(0,s.jsxs)("div",{className:"flex items-center gap-2 px-2 py-1",children:[s.jsx("div",{className:"w-6 h-6 rounded-md bg-gradient-to-br from-accent to-teal flex items-center justify-center text-xs flex-shrink-0",children:"⬡"}),s.jsx("span",{className:"font-mono text-xs text-muted tracking-widest uppercase group-data-[collapsible=icon]:hidden",children:"VibeDoc"})]})}),(0,s.jsxs)(q,{children:[s.jsx(B,{children:s.jsx(F,{children:s.jsx(G,{children:en.map(({href:e,icon:a,label:r})=>s.jsx(V,{children:s.jsx($,{asChild:!0,isActive:t.startsWith(e),tooltip:r,children:(0,s.jsxs)(er.default,{href:e,children:[s.jsx(a,{}),s.jsx("span",{children:r})]})})},e))})})}),e&&(0,s.jsxs)(s.Fragment,{children:[s.jsx(L,{}),(0,s.jsxs)(B,{children:[s.jsx(K,{children:"Board"}),s.jsx(F,{children:s.jsx(G,{children:ei.map(({status:t,icon:a,label:r})=>{let n=e[t]?.length||0;return s.jsx(V,{children:(0,s.jsxs)($,{tooltip:`${r}: ${n}`,children:[s.jsx(a,{}),s.jsx("span",{children:r}),s.jsx("span",{className:"ml-auto font-mono text-xs",children:n})]})},t)})})})]})]})]})]})}var ed=a(2126),el=a(194),ec=a(9516),eu=a(8650),em=a(2119);function ep({open:e,onClose:t,onOpenDoc:a,onNewDoc:i,rootParam:o}){let d=(0,n.useRouter)(),[l,c]=(0,r.useState)(""),[u,p]=(0,r.useState)([]),[f,h]=(0,r.useState)(0),b=[{label:"New Doc",icon:ed.Z,action:()=>{i?.(),t()}},{label:"Go to Board",icon:J.Z,action:()=>{d.push("/board"),t()}},{label:"Go to Activity",icon:el.Z,action:()=>{d.push("/activity"),t()}},{label:"Go to Memory",icon:X.Z,action:()=>{d.push("/memory"),t()}}];function g(e){a(e.path),t()}let v=""===l;return s.jsx(eu.Vq,{open:e,onOpenChange:e=>{e||t()},children:(0,s.jsxs)(eu.cZ,{className:"max-w-lg p-0 overflow-hidden bg-surface border-border gap-0",children:[s.jsx(eu.$N,{className:"sr-only",children:"Command Palette"}),(0,s.jsxs)("div",{className:"flex items-center px-4 h-12",children:[s.jsx(ec.Z,{className:"h-4 w-4 text-muted shrink-0 mr-3"}),s.jsx(x.I,{autoFocus:!0,value:l,onChange:e=>c(e.target.value),onKeyDown:function(e){let t=u.length>0,a=t?u.length:b.length;"ArrowDown"===e.key?(e.preventDefault(),h(e=>Math.min(e+1,a-1))):"ArrowUp"===e.key?(e.preventDefault(),h(e=>Math.max(e-1,0))):"Enter"===e.key&&(t&&u[f]?g(u[f]):!t&&l.length<2&&b[f]&&b[f].action())},placeholder:"Search docs…",className:"border-0 bg-transparent h-full text-sm shadow-none focus-visible:ring-0 px-0 placeholder:text-muted"})]}),s.jsx("div",{className:"border-t border-border"}),(0,s.jsxs)(em.x,{className:"max-h-72",children:[v&&s.jsx("div",{className:"py-1",children:b.map((e,t)=>(0,s.jsxs)("button",{onClick:e.action,onMouseEnter:()=>h(t),className:(0,m.cn)("flex items-center gap-3 w-full px-4 py-2 text-sm text-left transition-colors",f===t?"bg-accent/10 text-txt":"text-muted hover:text-txt"),children:[s.jsx(e.icon,{className:"h-4 w-4 shrink-0"}),e.label]},e.label))}),!v&&u.length>0&&s.jsx("div",{className:"py-1",children:u.map((e,t)=>(0,s.jsxs)("button",{onClick:()=>g(e),onMouseEnter:()=>h(t),className:(0,m.cn)("flex items-center justify-between w-full px-4 py-2 text-sm text-left transition-colors",f===t?"bg-accent/10":"hover:bg-accent/5"),children:[s.jsx("span",{className:"font-medium text-txt truncate",children:e.name}),e.section&&s.jsx("span",{className:"text-xs text-muted ml-3 shrink-0 truncate max-w-[40%]",children:e.section})]},e.path))}),!v&&l.length>=2&&0===u.length&&s.jsx("div",{className:"px-4 py-6 text-center text-sm text-muted",children:"No docs found"})]})]})})}var ef=a(9195);function eh({children:e}){return s.jsx(i.w,{children:s.jsx(eg,{children:e})})}let eb=[{key:"Cmd+K",description:"Open command palette"},{key:"b",description:"Go to Board"},{key:"d",description:"Go to Docs"},{key:"a",description:"Go to Activity"},{key:"m",description:"Go to Memory"},{key:"/",description:"Focus doc search"},{key:"?",description:"Toggle this help"},{key:"Esc",description:"Close panel / modal"}];function eg({children:e}){let{loading:t,summary:a,projects:d,activeProject:l,liveIndicator:c,onProjectChange:u,board:m,openDoc:p,rootParam:f}=(0,i.q)();(0,n.useRouter)(),(0,n.usePathname)();let[h,b]=(0,r.useState)(!1),[g,x]=(0,r.useState)(!1),[v,y]=(0,r.useState)(!1);return t?s.jsx(o,{}):(0,s.jsxs)(_,{children:[s.jsx(eo,{board:m}),(0,s.jsxs)(M,{children:[s.jsx(W,{summary:a,projects:d,activeProject:l,liveIndicator:c,onProjectChange:u}),s.jsx("main",{className:"flex-1 overflow-y-auto",children:e}),s.jsx(ep,{open:g,onClose:()=>x(!1),onOpenDoc:p,onNewDoc:()=>{x(!1),y(!0)},rootParam:f}),s.jsx(ef.t,{open:v,onOpenChange:y,rootParam:f,onDocCreated:async e=>{await p(e)}}),h&&(0,s.jsxs)(s.Fragment,{children:[s.jsx("div",{className:"fixed inset-0 z-50 bg-black/60",onClick:()=>b(!1)}),(0,s.jsxs)("div",{className:"fixed z-50 top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 w-80 bg-surface border border-border rounded-xl shadow-2xl p-5",children:[(0,s.jsxs)("div",{className:"flex items-center justify-between mb-4",children:[s.jsx("span",{className:"font-display text-sm font-semibold text-txt",children:"Keyboard shortcuts"}),s.jsx("button",{onClick:()=>b(!1),className:"text-muted hover:text-txt transition-colors text-lg leading-none",children:"\xd7"})]}),s.jsx("table",{className:"w-full text-xs",children:s.jsx("tbody",{children:eb.map(({key:e,description:t})=>(0,s.jsxs)("tr",{className:"border-t border-border first:border-0",children:[s.jsx("td",{className:"py-1.5 pr-4",children:s.jsx("kbd",{className:"font-mono bg-surface2 border border-border rounded px-1.5 py-0.5 text-accent",children:e})}),s.jsx("td",{className:"py-1.5 text-muted",children:t})]},e))})})]})]})]})]})}},9195:(e,t,a)=>{"use strict";a.d(t,{t:()=>f});var s=a(7486),r=a(618),n=a(9421),i=a(4987),o=a(5098),d=a(8650),l=a(3068),c=a(2162),u=a(2119);let m=new Date().toISOString().split("T")[0],p=[{id:"blank",name:"Blank Document",description:"Empty markdown file",defaultPath:"docs/untitled.md",content:"# Untitled\n\n"},{id:"claude-md",name:"CLAUDE.md",description:"AI agent instructions for Claude Code",defaultPath:"CLAUDE.md",content:`# {{PROJECT_NAME}} — Agent Instructions
|
|
1
|
+
exports.id=191,exports.ids=[191],exports.modules={1562:(e,t,a)=>{Promise.resolve().then(a.t.bind(a,9388,23)),Promise.resolve().then(a.t.bind(a,1152,23)),Promise.resolve().then(a.t.bind(a,2764,23)),Promise.resolve().then(a.t.bind(a,6894,23)),Promise.resolve().then(a.t.bind(a,3299,23)),Promise.resolve().then(a.t.bind(a,184,23))},9788:(e,t,a)=>{Promise.resolve().then(a.bind(a,151))},103:()=>{},151:(e,t,a)=>{"use strict";a.r(t),a.d(t,{default:()=>ef});var s=a(7486),r=a(618),i=a(6811),n=a(6266);function o(){return s.jsx("div",{className:"min-h-screen flex items-center justify-center",children:(0,s.jsxs)("div",{className:"text-center",children:[s.jsx("div",{className:"flex gap-1.5 justify-center mb-4",children:[0,1,2].map(e=>s.jsx("div",{className:"w-2 h-2 rounded-full bg-accent animate-pulse-dot",style:{animationDelay:`${.15*e}s`}},e))}),s.jsx("p",{className:"text-muted text-sm font-mono",children:"Loading project..."})]})})}var d=a(9228);function l({projects:e,activeProject:t,currentName:a,onSelect:r}){return(0,s.jsxs)(d.h_,{children:[s.jsx(d.$F,{asChild:!0,children:(0,s.jsxs)("button",{className:"flex items-center gap-1.5 px-3 py-1.5 rounded-md bg-surface2 border border-border text-sm hover:border-border2 transition-colors",children:[s.jsx("span",{className:"text-txt font-medium truncate max-w-[200px]",children:a||"Select project"}),s.jsx("span",{className:"text-muted text-xs",children:"▾"})]})}),s.jsx(d.AW,{className:"w-64 bg-surface border-border2 text-txt",align:"start",children:0===e.length?s.jsx("div",{className:"px-3 py-2 text-sm text-muted",children:"No projects found"}):e.map(e=>s.jsx(d.Xi,{onClick:()=>r(e.root),className:`cursor-pointer hover:bg-surface2 focus:bg-surface2 ${e.root===t?"text-accent":""}`,children:(0,s.jsxs)("div",{children:[s.jsx("div",{className:"font-medium",children:e.name}),s.jsx("div",{className:"text-xs text-muted truncate font-mono",children:e.root})]})},e.root))})]})}var c=a(5819);function u({board:e}){return(0,s.jsxs)("div",{className:"flex items-center gap-1.5",children:[(0,s.jsxs)(c.C,{variant:"secondary",className:"gap-1 text-xs font-mono text-amber",children:["\uD83D\uDD28 ",e["in-progress"]||0]}),(0,s.jsxs)(c.C,{variant:"secondary",className:"gap-1 text-xs font-mono text-muted",children:["\uD83D\uDCCB ",e.todo||0]}),(0,s.jsxs)(c.C,{variant:"secondary",className:"gap-1 text-xs font-mono text-teal",children:["✅ ",e.done||0]})]})}var p=a(5098);function m({active:e}){return(0,s.jsxs)("div",{className:"flex items-center gap-1.5 text-xs font-mono text-muted",children:[s.jsx("div",{className:(0,p.cn)("w-1.5 h-1.5 rounded-full transition-colors duration-500",e?"bg-teal shadow-[0_0_6px_#4fd8b4]":"bg-border2")}),s.jsx("span",{children:e?"live update":"connected"})]})}var h=a(8942),f=a(4039),g=a(1317),b=a(3068),x=a(2162),y=a(6637),v=a(2439),w=a(2153);let k=v.fC;v.xz,v.x8;let N=v.h_,C=r.forwardRef(({className:e,...t},a)=>s.jsx(v.aV,{className:(0,p.cn)("fixed inset-0 z-50 bg-black/80 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0",e),...t,ref:a}));C.displayName=v.aV.displayName;let R=(0,f.j)("fixed z-50 gap-4 bg-white p-6 shadow-lg transition ease-in-out data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:duration-300 data-[state=open]:duration-500 dark:bg-slate-950",{variants:{side:{top:"inset-x-0 top-0 border-b data-[state=closed]:slide-out-to-top data-[state=open]:slide-in-from-top",bottom:"inset-x-0 bottom-0 border-t data-[state=closed]:slide-out-to-bottom data-[state=open]:slide-in-from-bottom",left:"inset-y-0 left-0 h-full w-3/4 border-r data-[state=closed]:slide-out-to-left data-[state=open]:slide-in-from-left sm:max-w-sm",right:"inset-y-0 right-0 h-full w-3/4 border-l data-[state=closed]:slide-out-to-right data-[state=open]:slide-in-from-right sm:max-w-sm"}},defaultVariants:{side:"right"}}),E=r.forwardRef(({side:e="right",className:t,children:a,...r},i)=>(0,s.jsxs)(N,{children:[s.jsx(C,{}),(0,s.jsxs)(v.VY,{ref:i,className:(0,p.cn)(R({side:e}),t),...r,children:[a,(0,s.jsxs)(v.x8,{className:"absolute right-4 top-4 rounded-sm opacity-70 ring-offset-white transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-slate-950 focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-slate-100 dark:ring-offset-slate-950 dark:focus:ring-slate-300 dark:data-[state=open]:bg-slate-800",children:[s.jsx(w.Z,{className:"h-4 w-4"}),s.jsx("span",{className:"sr-only",children:"Close"})]})]})]}));E.displayName=v.VY.displayName;let S=({className:e,...t})=>s.jsx("div",{className:(0,p.cn)("flex flex-col space-y-2 text-center sm:text-left",e),...t});S.displayName="SheetHeader";let j=r.forwardRef(({className:e,...t},a)=>s.jsx(v.Dx,{ref:a,className:(0,p.cn)("text-lg font-semibold text-slate-950 dark:text-slate-50",e),...t}));j.displayName=v.Dx.displayName;let P=r.forwardRef(({className:e,...t},a)=>s.jsx(v.dk,{ref:a,className:(0,p.cn)("text-sm text-slate-500 dark:text-slate-400",e),...t}));function A({className:e,...t}){return s.jsx("div",{className:(0,p.cn)("animate-pulse rounded-md bg-slate-100 dark:bg-slate-800",e),...t})}P.displayName=v.dk.displayName;var _=a(5875);let T=r.createContext(null);function D(){let e=r.useContext(T);if(!e)throw Error("useSidebar must be used within a SidebarProvider.");return e}let I=r.forwardRef(({defaultOpen:e=!0,open:t,onOpenChange:a,className:i,style:n,children:o,...d},l)=>{let c=function(){let[e,t]=r.useState(void 0);return r.useEffect(()=>{let e=window.matchMedia("(max-width: 767px)"),a=()=>{t(window.innerWidth<768)};return e.addEventListener("change",a),t(window.innerWidth<768),()=>e.removeEventListener("change",a)},[]),!!e}(),[u,m]=r.useState(!1),[h,f]=r.useState(e),g=t??h,b=r.useCallback(e=>{let t="function"==typeof e?e(g):e;a?a(t):f(t),document.cookie=`sidebar_state=${t}; path=/; max-age=604800`},[a,g]),x=r.useCallback(()=>c?m(e=>!e):b(e=>!e),[c,b,m]);r.useEffect(()=>{let e=e=>{"b"===e.key&&(e.metaKey||e.ctrlKey)&&(e.preventDefault(),x())};return window.addEventListener("keydown",e),()=>window.removeEventListener("keydown",e)},[x]);let y=g?"expanded":"collapsed",v=r.useMemo(()=>({state:y,open:g,setOpen:b,isMobile:c,openMobile:u,setOpenMobile:m,toggleSidebar:x}),[y,g,b,c,u,m,x]);return s.jsx(T.Provider,{value:v,children:s.jsx(_.pn,{delayDuration:0,children:s.jsx("div",{style:{"--sidebar-width":"16rem","--sidebar-width-icon":"3rem",...n},className:(0,p.cn)("group/sidebar-wrapper flex min-h-svh w-full has-[[data-variant=inset]]:bg-sidebar",i),ref:l,...d,children:o})})})});I.displayName="SidebarProvider";let O=r.forwardRef(({side:e="left",variant:t="sidebar",collapsible:a="offcanvas",className:r,children:i,...n},o)=>{let{isMobile:d,state:l,openMobile:c,setOpenMobile:u}=D();return"none"===a?s.jsx("div",{className:(0,p.cn)("flex h-full w-[--sidebar-width] flex-col bg-sidebar text-sidebar-foreground",r),ref:o,...n,children:i}):d?s.jsx(k,{open:c,onOpenChange:u,...n,children:(0,s.jsxs)(E,{"data-sidebar":"sidebar","data-mobile":"true",className:"w-[--sidebar-width] bg-sidebar p-0 text-sidebar-foreground [&>button]:hidden",style:{"--sidebar-width":"18rem"},side:e,children:[(0,s.jsxs)(S,{className:"sr-only",children:[s.jsx(j,{children:"Sidebar"}),s.jsx(P,{children:"Displays the mobile sidebar."})]}),s.jsx("div",{className:"flex h-full w-full flex-col",children:i})]})}):(0,s.jsxs)("div",{ref:o,className:"group peer hidden text-sidebar-foreground md:block","data-state":l,"data-collapsible":"collapsed"===l?a:"","data-variant":t,"data-side":e,children:[s.jsx("div",{className:(0,p.cn)("relative w-[--sidebar-width] bg-transparent transition-[width] duration-200 ease-linear","group-data-[collapsible=offcanvas]:w-0","group-data-[side=right]:rotate-180","floating"===t||"inset"===t?"group-data-[collapsible=icon]:w-[calc(var(--sidebar-width-icon)_+_theme(spacing.4))]":"group-data-[collapsible=icon]:w-[--sidebar-width-icon]")}),s.jsx("div",{className:(0,p.cn)("fixed inset-y-0 z-10 hidden h-svh w-[--sidebar-width] transition-[left,right,width] duration-200 ease-linear md:flex","left"===e?"left-0 group-data-[collapsible=offcanvas]:left-[calc(var(--sidebar-width)*-1)]":"right-0 group-data-[collapsible=offcanvas]:right-[calc(var(--sidebar-width)*-1)]","floating"===t||"inset"===t?"p-2 group-data-[collapsible=icon]:w-[calc(var(--sidebar-width-icon)_+_theme(spacing.4)_+2px)]":"group-data-[collapsible=icon]:w-[--sidebar-width-icon] group-data-[side=left]:border-r group-data-[side=right]:border-l",r),...n,children:s.jsx("div",{"data-sidebar":"sidebar",className:"flex h-full w-full flex-col bg-sidebar group-data-[variant=floating]:rounded-lg group-data-[variant=floating]:border group-data-[variant=floating]:border-sidebar-border group-data-[variant=floating]:shadow",children:i})})]})});O.displayName="Sidebar";let M=r.forwardRef(({className:e,onClick:t,...a},r)=>{let{toggleSidebar:i}=D();return(0,s.jsxs)(b.z,{ref:r,"data-sidebar":"trigger",variant:"ghost",size:"icon",className:(0,p.cn)("h-7 w-7",e),onClick:e=>{t?.(e),i()},...a,children:[s.jsx(g.Z,{}),s.jsx("span",{className:"sr-only",children:"Toggle Sidebar"})]})});M.displayName="SidebarTrigger",r.forwardRef(({className:e,...t},a)=>{let{toggleSidebar:r}=D();return s.jsx("button",{ref:a,"data-sidebar":"rail","aria-label":"Toggle Sidebar",tabIndex:-1,onClick:r,title:"Toggle Sidebar",className:(0,p.cn)("absolute inset-y-0 z-20 hidden w-4 -translate-x-1/2 transition-all ease-linear after:absolute after:inset-y-0 after:left-1/2 after:w-[2px] hover:after:bg-sidebar-border group-data-[side=left]:-right-4 group-data-[side=right]:left-0 sm:flex","[[data-side=left]_&]:cursor-w-resize [[data-side=right]_&]:cursor-e-resize","[[data-side=left][data-state=collapsed]_&]:cursor-e-resize [[data-side=right][data-state=collapsed]_&]:cursor-w-resize","group-data-[collapsible=offcanvas]:translate-x-0 group-data-[collapsible=offcanvas]:after:left-full group-data-[collapsible=offcanvas]:hover:bg-sidebar","[[data-side=left][data-collapsible=offcanvas]_&]:-right-2","[[data-side=right][data-collapsible=offcanvas]_&]:-left-2",e),...t})}).displayName="SidebarRail";let L=r.forwardRef(({className:e,...t},a)=>s.jsx("main",{ref:a,className:(0,p.cn)("relative flex w-full flex-1 flex-col bg-white dark:bg-slate-950","md:peer-data-[variant=inset]:m-2 md:peer-data-[state=collapsed]:peer-data-[variant=inset]:ml-2 md:peer-data-[variant=inset]:ml-0 md:peer-data-[variant=inset]:rounded-xl md:peer-data-[variant=inset]:shadow",e),...t}));L.displayName="SidebarInset",r.forwardRef(({className:e,...t},a)=>s.jsx(x.I,{ref:a,"data-sidebar":"input",className:(0,p.cn)("h-8 w-full bg-white shadow-none focus-visible:ring-2 focus-visible:ring-sidebar-ring dark:bg-slate-950",e),...t})).displayName="SidebarInput";let U=r.forwardRef(({className:e,...t},a)=>s.jsx("div",{ref:a,"data-sidebar":"header",className:(0,p.cn)("flex flex-col gap-2 p-2",e),...t}));U.displayName="SidebarHeader",r.forwardRef(({className:e,...t},a)=>s.jsx("div",{ref:a,"data-sidebar":"footer",className:(0,p.cn)("flex flex-col gap-2 p-2",e),...t})).displayName="SidebarFooter";let z=r.forwardRef(({className:e,...t},a)=>s.jsx(y.Z,{ref:a,"data-sidebar":"separator",className:(0,p.cn)("mx-2 w-auto bg-sidebar-border",e),...t}));z.displayName="SidebarSeparator";let G=r.forwardRef(({className:e,...t},a)=>s.jsx("div",{ref:a,"data-sidebar":"content",className:(0,p.cn)("flex min-h-0 flex-1 flex-col gap-2 overflow-auto group-data-[collapsible=icon]:overflow-hidden",e),...t}));G.displayName="SidebarContent";let q=r.forwardRef(({className:e,...t},a)=>s.jsx("div",{ref:a,"data-sidebar":"group",className:(0,p.cn)("relative flex w-full min-w-0 flex-col p-2",e),...t}));q.displayName="SidebarGroup";let B=r.forwardRef(({className:e,asChild:t=!1,...a},r)=>{let i=t?h.g7:"div";return s.jsx(i,{ref:r,"data-sidebar":"group-label",className:(0,p.cn)("flex h-8 shrink-0 items-center rounded-md px-2 text-xs font-medium text-sidebar-foreground/70 outline-none ring-sidebar-ring transition-[margin,opacity] duration-200 ease-linear focus-visible:ring-2 [&>svg]:size-4 [&>svg]:shrink-0","group-data-[collapsible=icon]:-mt-8 group-data-[collapsible=icon]:opacity-0",e),...a})});B.displayName="SidebarGroupLabel",r.forwardRef(({className:e,asChild:t=!1,...a},r)=>{let i=t?h.g7:"button";return s.jsx(i,{ref:r,"data-sidebar":"group-action",className:(0,p.cn)("absolute right-3 top-3.5 flex aspect-square w-5 items-center justify-center rounded-md p-0 text-sidebar-foreground outline-none ring-sidebar-ring transition-transform hover:bg-sidebar-accent hover:text-sidebar-accent-foreground focus-visible:ring-2 [&>svg]:size-4 [&>svg]:shrink-0","after:absolute after:-inset-2 after:md:hidden","group-data-[collapsible=icon]:hidden",e),...a})}).displayName="SidebarGroupAction";let W=r.forwardRef(({className:e,...t},a)=>s.jsx("div",{ref:a,"data-sidebar":"group-content",className:(0,p.cn)("w-full text-sm",e),...t}));W.displayName="SidebarGroupContent";let F=r.forwardRef(({className:e,...t},a)=>s.jsx("ul",{ref:a,"data-sidebar":"menu",className:(0,p.cn)("flex w-full min-w-0 flex-col gap-1",e),...t}));F.displayName="SidebarMenu";let H=r.forwardRef(({className:e,...t},a)=>s.jsx("li",{ref:a,"data-sidebar":"menu-item",className:(0,p.cn)("group/menu-item relative",e),...t}));H.displayName="SidebarMenuItem";let K=(0,f.j)("peer/menu-button flex w-full items-center gap-2 overflow-hidden rounded-md p-2 text-left text-sm outline-none ring-sidebar-ring transition-[width,height,padding] hover:bg-sidebar-accent hover:text-sidebar-accent-foreground focus-visible:ring-2 active:bg-sidebar-accent active:text-sidebar-accent-foreground disabled:pointer-events-none disabled:opacity-50 group-has-[[data-sidebar=menu-action]]/menu-item:pr-8 aria-disabled:pointer-events-none aria-disabled:opacity-50 data-[active=true]:bg-sidebar-accent data-[active=true]:font-medium data-[active=true]:text-sidebar-accent-foreground data-[state=open]:hover:bg-sidebar-accent data-[state=open]:hover:text-sidebar-accent-foreground group-data-[collapsible=icon]:!size-8 group-data-[collapsible=icon]:!p-2 [&>span:last-child]:truncate [&>svg]:size-4 [&>svg]:shrink-0",{variants:{variant:{default:"hover:bg-sidebar-accent hover:text-sidebar-accent-foreground",outline:"bg-white shadow-[0_0_0_1px_hsl(var(--sidebar-border))] hover:bg-sidebar-accent hover:text-sidebar-accent-foreground hover:shadow-[0_0_0_1px_hsl(var(--sidebar-accent))] dark:bg-slate-950"},size:{default:"h-8 text-sm",sm:"h-7 text-xs",lg:"h-12 text-sm group-data-[collapsible=icon]:!p-0"}},defaultVariants:{variant:"default",size:"default"}}),$=r.forwardRef(({asChild:e=!1,isActive:t=!1,variant:a="default",size:r="default",tooltip:i,className:n,...o},d)=>{let l=e?h.g7:"button",{isMobile:c,state:u}=D(),m=s.jsx(l,{ref:d,"data-sidebar":"menu-button","data-size":r,"data-active":t,className:(0,p.cn)(K({variant:a,size:r}),n),...o});return i?("string"==typeof i&&(i={children:i}),(0,s.jsxs)(_.u,{children:[s.jsx(_.aJ,{asChild:!0,children:m}),s.jsx(_._v,{side:"right",align:"center",hidden:"collapsed"!==u||c,...i})]})):m});function V({summary:e,projects:t,activeProject:a,liveIndicator:r,onProjectChange:i}){return(0,s.jsxs)("header",{className:"h-12 border-b border-border flex items-center px-4 gap-4 flex-shrink-0 bg-surface/80 backdrop-blur-sm sticky top-0 z-50",children:[s.jsx(M,{className:"-ml-1"}),s.jsx(y.Z,{orientation:"vertical",className:"mr-2 h-4"}),(0,s.jsxs)("div",{className:"flex items-center gap-2 flex-shrink-0",children:[s.jsx("div",{className:"w-6 h-6 rounded-md bg-gradient-to-br from-accent to-teal flex items-center justify-center text-xs",children:"⬡"}),s.jsx("span",{className:"font-mono text-xs text-muted tracking-widest uppercase",children:"VibeDoc"})]}),s.jsx(l,{projects:t,activeProject:a,currentName:e?.name||"",onSelect:i}),e&&s.jsx(u,{board:e.tasks.board}),s.jsx("div",{className:"flex-1"}),s.jsx(m,{active:r}),(0,s.jsxs)("div",{className:"hidden md:flex items-center gap-1.5 px-2 py-1 rounded bg-surface2 border border-border",children:[s.jsx("span",{className:"text-xs font-mono text-muted",children:"MCP"}),s.jsx("code",{className:"text-xs font-mono text-accent",children:"localhost:3000/api/mcp"})]})]})}$.displayName="SidebarMenuButton",r.forwardRef(({className:e,asChild:t=!1,showOnHover:a=!1,...r},i)=>{let n=t?h.g7:"button";return s.jsx(n,{ref:i,"data-sidebar":"menu-action",className:(0,p.cn)("absolute right-1 top-1.5 flex aspect-square w-5 items-center justify-center rounded-md p-0 text-sidebar-foreground outline-none ring-sidebar-ring transition-transform hover:bg-sidebar-accent hover:text-sidebar-accent-foreground focus-visible:ring-2 peer-hover/menu-button:text-sidebar-accent-foreground [&>svg]:size-4 [&>svg]:shrink-0","after:absolute after:-inset-2 after:md:hidden","peer-data-[size=sm]/menu-button:top-1","peer-data-[size=default]/menu-button:top-1.5","peer-data-[size=lg]/menu-button:top-2.5","group-data-[collapsible=icon]:hidden",a&&"group-focus-within/menu-item:opacity-100 group-hover/menu-item:opacity-100 data-[state=open]:opacity-100 peer-data-[active=true]/menu-button:text-sidebar-accent-foreground md:opacity-0",e),...r})}).displayName="SidebarMenuAction",r.forwardRef(({className:e,...t},a)=>s.jsx("div",{ref:a,"data-sidebar":"menu-badge",className:(0,p.cn)("pointer-events-none absolute right-1 flex h-5 min-w-5 select-none items-center justify-center rounded-md px-1 text-xs font-medium tabular-nums text-sidebar-foreground","peer-hover/menu-button:text-sidebar-accent-foreground peer-data-[active=true]/menu-button:text-sidebar-accent-foreground","peer-data-[size=sm]/menu-button:top-1","peer-data-[size=default]/menu-button:top-1.5","peer-data-[size=lg]/menu-button:top-2.5","group-data-[collapsible=icon]:hidden",e),...t})).displayName="SidebarMenuBadge",r.forwardRef(({className:e,showIcon:t=!1,...a},i)=>{let n=r.useMemo(()=>`${Math.floor(40*Math.random())+50}%`,[]);return(0,s.jsxs)("div",{ref:i,"data-sidebar":"menu-skeleton",className:(0,p.cn)("flex h-8 items-center gap-2 rounded-md px-2",e),...a,children:[t&&s.jsx(A,{className:"size-4 rounded-md","data-sidebar":"menu-skeleton-icon"}),s.jsx(A,{className:"h-4 max-w-[--skeleton-width] flex-1","data-sidebar":"menu-skeleton-text",style:{"--skeleton-width":n}})]})}).displayName="SidebarMenuSkeleton",r.forwardRef(({className:e,...t},a)=>s.jsx("ul",{ref:a,"data-sidebar":"menu-sub",className:(0,p.cn)("mx-3.5 flex min-w-0 translate-x-px flex-col gap-1 border-l border-sidebar-border px-2.5 py-0.5","group-data-[collapsible=icon]:hidden",e),...t})).displayName="SidebarMenuSub",r.forwardRef(({...e},t)=>s.jsx("li",{ref:t,...e})).displayName="SidebarMenuSubItem",r.forwardRef(({asChild:e=!1,size:t="md",isActive:a,className:r,...i},n)=>{let o=e?h.g7:"a";return s.jsx(o,{ref:n,"data-sidebar":"menu-sub-button","data-size":t,"data-active":a,className:(0,p.cn)("flex h-7 min-w-0 -translate-x-px items-center gap-2 overflow-hidden rounded-md px-2 text-sidebar-foreground outline-none ring-sidebar-ring hover:bg-sidebar-accent hover:text-sidebar-accent-foreground focus-visible:ring-2 active:bg-sidebar-accent active:text-sidebar-accent-foreground disabled:pointer-events-none disabled:opacity-50 aria-disabled:pointer-events-none aria-disabled:opacity-50 [&>span:last-child]:truncate [&>svg]:size-4 [&>svg]:shrink-0 [&>svg]:text-sidebar-accent-foreground","data-[active=true]:bg-sidebar-accent data-[active=true]:text-sidebar-accent-foreground","sm"===t&&"text-xs","md"===t&&"text-sm","group-data-[collapsible=icon]:hidden",r),...i})}).displayName="SidebarMenuSubButton";var Y=a(3596),J=a(7987),Z=a(9529),X=a(8673),Q=a(5314),ee=a(6034),et=a(771),ea=a(4119),es=a(7834),er=a(8165);let ei=[{href:"/board",icon:Y.Z,label:"Board"},{href:"/docs",icon:J.Z,label:"Docs"},{href:"/activity",icon:Z.Z,label:"Activity"},{href:"/memory",icon:X.Z,label:"Memory"},{href:"/settings",icon:Q.Z,label:"Settings"}],en=[{status:"in-progress",icon:ee.Z,label:"Active"},{status:"blocked",icon:et.Z,label:"Blocked"},{status:"todo",icon:ea.Z,label:"Todo"},{status:"done",icon:es.Z,label:"Done"}];function eo({board:e}){let t=(0,i.usePathname)();return(0,s.jsxs)(O,{collapsible:"icon",children:[s.jsx(U,{children:(0,s.jsxs)("div",{className:"flex items-center gap-2 px-2 py-1",children:[s.jsx("div",{className:"w-6 h-6 rounded-md bg-gradient-to-br from-accent to-teal flex items-center justify-center text-xs flex-shrink-0",children:"⬡"}),s.jsx("span",{className:"font-mono text-xs text-muted tracking-widest uppercase group-data-[collapsible=icon]:hidden",children:"VibeDoc"})]})}),(0,s.jsxs)(G,{children:[s.jsx(q,{children:s.jsx(W,{children:s.jsx(F,{children:ei.map(({href:e,icon:a,label:r})=>s.jsx(H,{children:s.jsx($,{asChild:!0,isActive:t.startsWith(e),tooltip:r,children:(0,s.jsxs)(er.default,{href:e,children:[s.jsx(a,{}),s.jsx("span",{children:r})]})})},e))})})}),e&&(0,s.jsxs)(s.Fragment,{children:[s.jsx(z,{}),(0,s.jsxs)(q,{children:[s.jsx(B,{children:"Board"}),s.jsx(W,{children:s.jsx(F,{children:en.map(({status:t,icon:a,label:r})=>{let i=e[t]?.length||0;return s.jsx(H,{children:(0,s.jsxs)($,{tooltip:`${r}: ${i}`,children:[s.jsx(a,{}),s.jsx("span",{children:r}),s.jsx("span",{className:"ml-auto font-mono text-xs",children:i})]})},t)})})})]})]})]})]})}var ed=a(2126),el=a(194),ec=a(9516),eu=a(8650),ep=a(2119);function em({open:e,onClose:t,onOpenDoc:a,onNewDoc:n,rootParam:o}){let d=(0,i.useRouter)(),[l,c]=(0,r.useState)(""),[u,m]=(0,r.useState)([]),[h,f]=(0,r.useState)(0),g=[{label:"New Doc",icon:ed.Z,action:()=>{n?.(),t()}},{label:"Go to Board",icon:Y.Z,action:()=>{d.push("/board"),t()}},{label:"Go to Activity",icon:el.Z,action:()=>{d.push("/activity"),t()}},{label:"Go to Memory",icon:X.Z,action:()=>{d.push("/memory"),t()}}];function b(e){a(e.path),t()}let y=""===l;return s.jsx(eu.Vq,{open:e,onOpenChange:e=>{e||t()},children:(0,s.jsxs)(eu.cZ,{className:"max-w-lg p-0 overflow-hidden bg-surface border-border gap-0",children:[s.jsx(eu.$N,{className:"sr-only",children:"Command Palette"}),(0,s.jsxs)("div",{className:"flex items-center px-4 h-12",children:[s.jsx(ec.Z,{className:"h-4 w-4 text-muted shrink-0 mr-3"}),s.jsx(x.I,{autoFocus:!0,value:l,onChange:e=>c(e.target.value),onKeyDown:function(e){let t=u.length>0,a=t?u.length:g.length;"ArrowDown"===e.key?(e.preventDefault(),f(e=>Math.min(e+1,a-1))):"ArrowUp"===e.key?(e.preventDefault(),f(e=>Math.max(e-1,0))):"Enter"===e.key&&(t&&u[h]?b(u[h]):!t&&l.length<2&&g[h]&&g[h].action())},placeholder:"Search docs…",className:"border-0 bg-transparent h-full text-sm shadow-none focus-visible:ring-0 px-0 placeholder:text-muted"})]}),s.jsx("div",{className:"border-t border-border"}),(0,s.jsxs)(ep.x,{className:"max-h-72",children:[y&&s.jsx("div",{className:"py-1",children:g.map((e,t)=>(0,s.jsxs)("button",{onClick:e.action,onMouseEnter:()=>f(t),className:(0,p.cn)("flex items-center gap-3 w-full px-4 py-2 text-sm text-left transition-colors",h===t?"bg-accent/10 text-txt":"text-muted hover:text-txt"),children:[s.jsx(e.icon,{className:"h-4 w-4 shrink-0"}),e.label]},e.label))}),!y&&u.length>0&&s.jsx("div",{className:"py-1",children:u.map((e,t)=>(0,s.jsxs)("button",{onClick:()=>b(e),onMouseEnter:()=>f(t),className:(0,p.cn)("flex items-center justify-between w-full px-4 py-2 text-sm text-left transition-colors",h===t?"bg-accent/10":"hover:bg-accent/5"),children:[s.jsx("span",{className:"font-medium text-txt truncate",children:e.name}),e.section&&s.jsx("span",{className:"text-xs text-muted ml-3 shrink-0 truncate max-w-[40%]",children:e.section})]},e.path))}),!y&&l.length>=2&&0===u.length&&s.jsx("div",{className:"px-4 py-6 text-center text-sm text-muted",children:"No docs found"})]})]})})}var eh=a(9239);function ef({children:e}){return s.jsx(n.w,{children:s.jsx(eb,{children:e})})}let eg=[{key:"Cmd+K",description:"Open command palette"},{key:"b",description:"Go to Board"},{key:"d",description:"Go to Docs"},{key:"a",description:"Go to Activity"},{key:"m",description:"Go to Memory"},{key:"/",description:"Focus doc search"},{key:"?",description:"Toggle this help"},{key:"Esc",description:"Close panel / modal"}];function eb({children:e}){let{loading:t,summary:a,projects:d,activeProject:l,liveIndicator:c,onProjectChange:u,board:p,openDoc:m,rootParam:h}=(0,n.q)();(0,i.useRouter)(),(0,i.usePathname)();let[f,g]=(0,r.useState)(!1),[b,x]=(0,r.useState)(!1),[y,v]=(0,r.useState)(!1);return t?s.jsx(o,{}):(0,s.jsxs)(I,{children:[s.jsx(eo,{board:p}),(0,s.jsxs)(L,{children:[s.jsx(V,{summary:a,projects:d,activeProject:l,liveIndicator:c,onProjectChange:u}),s.jsx("main",{className:"flex-1 overflow-y-auto",children:e}),s.jsx(em,{open:b,onClose:()=>x(!1),onOpenDoc:m,onNewDoc:()=>{x(!1),v(!0)},rootParam:h}),s.jsx(eh.t,{open:y,onOpenChange:v,rootParam:h,onDocCreated:async e=>{await m(e)}}),f&&(0,s.jsxs)(s.Fragment,{children:[s.jsx("div",{className:"fixed inset-0 z-50 bg-black/60",onClick:()=>g(!1)}),(0,s.jsxs)("div",{className:"fixed z-50 top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 w-80 bg-surface border border-border rounded-xl shadow-2xl p-5",children:[(0,s.jsxs)("div",{className:"flex items-center justify-between mb-4",children:[s.jsx("span",{className:"font-display text-sm font-semibold text-txt",children:"Keyboard shortcuts"}),s.jsx("button",{onClick:()=>g(!1),className:"text-muted hover:text-txt transition-colors text-lg leading-none",children:"\xd7"})]}),s.jsx("table",{className:"w-full text-xs",children:s.jsx("tbody",{children:eg.map(({key:e,description:t})=>(0,s.jsxs)("tr",{className:"border-t border-border first:border-0",children:[s.jsx("td",{className:"py-1.5 pr-4",children:s.jsx("kbd",{className:"font-mono bg-surface2 border border-border rounded px-1.5 py-0.5 text-accent",children:e})}),s.jsx("td",{className:"py-1.5 text-muted",children:t})]},e))})})]})]})]})]})}},9239:(e,t,a)=>{"use strict";a.d(t,{t:()=>m});var s=a(7486),r=a(618),i=a(9421),n=a(4987),o=a(5098),d=a(8650),l=a(3068),c=a(2162),u=a(2119),p=a(8508);function m({open:e,onOpenChange:t,rootParam:a,onDocCreated:m}){let[h,f]=(0,r.useState)(1),[g,b]=(0,r.useState)(null),[x,y]=(0,r.useState)(""),[v,w]=(0,r.useState)(""),[k,N]=(0,r.useState)(!1);async function C(){if(g&&x.trim()){w(""),N(!0);try{let e=await fetch(`/api/docs${a}`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({path:x.trim(),content:g.content})});if(409===e.status){w("File already exists"),N(!1);return}if(!e.ok){let t=await e.json();w(t.error||"Failed to create file"),N(!1);return}t(!1),m(x.trim())}catch{w("Network error"),N(!1)}}}return s.jsx(d.Vq,{open:e,onOpenChange:t,children:(0,s.jsxs)(d.cZ,{className:"max-w-2xl bg-surface border-border",children:[s.jsx(d.fK,{children:s.jsx(d.$N,{className:"text-txt text-sm font-semibold",children:1===h?"Choose a template":"Confirm file path"})}),1===h&&s.jsx(u.x,{className:"max-h-[420px]",children:s.jsx("div",{className:"grid grid-cols-3 gap-2 p-1",children:p.x.map(e=>(0,s.jsxs)("button",{onClick:()=>{b(e),y(e.defaultPath),w(""),f(2)},className:(0,o.cn)("flex flex-col items-start gap-1.5 p-3 rounded-lg border border-border text-left","bg-surface2 hover:bg-surface2/80 hover:border-accent/50 transition-colors"),children:[(0,s.jsxs)("div",{className:"flex items-center gap-2",children:[s.jsx(i.Z,{className:"h-3.5 w-3.5 text-accent shrink-0"}),s.jsx("span",{className:"text-xs font-medium text-txt",children:e.name})]}),s.jsx("p",{className:"text-[11px] text-muted leading-relaxed",children:e.description}),s.jsx("p",{className:"text-[10px] text-muted/60 font-mono truncate w-full",children:e.defaultPath})]},e.id))})}),2===h&&g&&(0,s.jsxs)("div",{className:"space-y-4",children:[(0,s.jsxs)("div",{className:"flex items-start gap-3 p-3 rounded-lg bg-surface2 border border-border",children:[s.jsx(i.Z,{className:"h-4 w-4 text-accent shrink-0 mt-0.5"}),(0,s.jsxs)("div",{children:[s.jsx("p",{className:"text-xs font-medium text-txt",children:g.name}),s.jsx("p",{className:"text-[11px] text-muted mt-0.5",children:g.description})]})]}),(0,s.jsxs)("div",{className:"space-y-1.5",children:[s.jsx("label",{className:"text-[11px] font-medium text-muted uppercase tracking-wider",children:"File path"}),s.jsx(c.I,{autoFocus:!0,value:x,onChange:e=>{y(e.target.value),w("")},onKeyDown:e=>{"Enter"===e.key&&C()},placeholder:"docs/my-document.md",className:"h-8 text-xs bg-surface2 border-border font-mono"}),v&&s.jsx("p",{className:"text-[11px] text-red-400",children:v})]}),(0,s.jsxs)("div",{className:"flex items-center justify-between pt-1",children:[(0,s.jsxs)(l.z,{variant:"ghost",size:"sm",onClick:()=>f(1),className:"h-7 text-xs text-muted hover:text-txt gap-1.5",children:[s.jsx(n.Z,{className:"h-3 w-3"}),"Back"]}),s.jsx(l.z,{size:"sm",onClick:C,disabled:k||!x.trim(),className:"h-7 text-xs bg-accent hover:bg-accent/90 text-white",children:k?"Creating…":"Create"})]})]})]})})}},5819:(e,t,a)=>{"use strict";a.d(t,{C:()=>o});var s=a(7486);a(618);var r=a(4039),i=a(5098);let n=(0,r.j)("inline-flex items-center rounded-full border border-slate-200 px-2.5 py-0.5 text-xs font-semibold transition-colors focus:outline-none focus:ring-2 focus:ring-slate-950 focus:ring-offset-2 dark:border-slate-800 dark:focus:ring-slate-300",{variants:{variant:{default:"border-transparent bg-slate-900 text-slate-50 hover:bg-slate-900/80 dark:bg-slate-50 dark:text-slate-900 dark:hover:bg-slate-50/80",secondary:"border-transparent bg-slate-100 text-slate-900 hover:bg-slate-100/80 dark:bg-slate-800 dark:text-slate-50 dark:hover:bg-slate-800/80",destructive:"border-transparent bg-red-500 text-slate-50 hover:bg-red-500/80 dark:bg-red-900 dark:text-slate-50 dark:hover:bg-red-900/80",outline:"text-slate-950 dark:text-slate-50"}},defaultVariants:{variant:"default"}});function o({className:e,variant:t,...a}){return s.jsx("div",{className:(0,i.cn)(n({variant:t}),e),...a})}},3068:(e,t,a)=>{"use strict";a.d(t,{z:()=>l});var s=a(7486),r=a(618),i=a(8942),n=a(4039),o=a(5098);let d=(0,n.j)("inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium ring-offset-white transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-slate-950 focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0 dark:ring-offset-slate-950 dark:focus-visible:ring-slate-300",{variants:{variant:{default:"bg-slate-900 text-slate-50 hover:bg-slate-900/90 dark:bg-slate-50 dark:text-slate-900 dark:hover:bg-slate-50/90",destructive:"bg-red-500 text-slate-50 hover:bg-red-500/90 dark:bg-red-900 dark:text-slate-50 dark:hover:bg-red-900/90",outline:"border border-slate-200 bg-white hover:bg-slate-100 hover:text-slate-900 dark:border-slate-800 dark:bg-slate-950 dark:hover:bg-slate-800 dark:hover:text-slate-50",secondary:"bg-slate-100 text-slate-900 hover:bg-slate-100/80 dark:bg-slate-800 dark:text-slate-50 dark:hover:bg-slate-800/80",ghost:"hover:bg-slate-100 hover:text-slate-900 dark:hover:bg-slate-800 dark:hover:text-slate-50",link:"text-slate-900 underline-offset-4 hover:underline dark:text-slate-50"},size:{default:"h-10 px-4 py-2",sm:"h-9 rounded-md px-3",lg:"h-11 rounded-md px-8",icon:"h-10 w-10"}},defaultVariants:{variant:"default",size:"default"}}),l=r.forwardRef(({className:e,variant:t,size:a,asChild:r=!1,...n},l)=>{let c=r?i.g7:"button";return s.jsx(c,{className:(0,o.cn)(d({variant:t,size:a,className:e})),ref:l,...n})});l.displayName="Button"},8650:(e,t,a)=>{"use strict";a.d(t,{$N:()=>m,Vq:()=>d,cZ:()=>u,fK:()=>p});var s=a(7486),r=a(618),i=a(2439),n=a(2153),o=a(5098);let d=i.fC;i.xz;let l=i.h_;i.x8;let c=r.forwardRef(({className:e,...t},a)=>s.jsx(i.aV,{ref:a,className:(0,o.cn)("fixed inset-0 z-50 bg-black/80 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0",e),...t}));c.displayName=i.aV.displayName;let u=r.forwardRef(({className:e,children:t,...a},r)=>(0,s.jsxs)(l,{children:[s.jsx(c,{}),(0,s.jsxs)(i.VY,{ref:r,className:(0,o.cn)("fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border border-slate-200 bg-white p-6 shadow-lg duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] sm:rounded-lg dark:border-slate-800 dark:bg-slate-950",e),...a,children:[t,(0,s.jsxs)(i.x8,{className:"absolute right-4 top-4 rounded-sm opacity-70 ring-offset-white transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-slate-950 focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-slate-100 data-[state=open]:text-slate-500 dark:ring-offset-slate-950 dark:focus:ring-slate-300 dark:data-[state=open]:bg-slate-800 dark:data-[state=open]:text-slate-400",children:[s.jsx(n.Z,{className:"h-4 w-4"}),s.jsx("span",{className:"sr-only",children:"Close"})]})]})]}));u.displayName=i.VY.displayName;let p=({className:e,...t})=>s.jsx("div",{className:(0,o.cn)("flex flex-col space-y-1.5 text-center sm:text-left",e),...t});p.displayName="DialogHeader";let m=r.forwardRef(({className:e,...t},a)=>s.jsx(i.Dx,{ref:a,className:(0,o.cn)("text-lg font-semibold leading-none tracking-tight",e),...t}));m.displayName=i.Dx.displayName,r.forwardRef(({className:e,...t},a)=>s.jsx(i.dk,{ref:a,className:(0,o.cn)("text-sm text-slate-500 dark:text-slate-400",e),...t})).displayName=i.dk.displayName},9228:(e,t,a)=>{"use strict";a.d(t,{$F:()=>u,AW:()=>p,Xi:()=>m,h_:()=>c});var s=a(7486),r=a(618),i=a(79),n=a(8953),o=a(9644),d=a(3399),l=a(5098);let c=i.fC,u=i.xz;i.ZA,i.Uv,i.Tr,i.Ee,r.forwardRef(({className:e,inset:t,children:a,...r},o)=>(0,s.jsxs)(i.fF,{ref:o,className:(0,l.cn)("flex cursor-default select-none items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-none focus:bg-slate-100 data-[state=open]:bg-slate-100 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0 dark:focus:bg-slate-800 dark:data-[state=open]:bg-slate-800",t&&"pl-8",e),...r,children:[a,s.jsx(n.Z,{className:"ml-auto"})]})).displayName=i.fF.displayName,r.forwardRef(({className:e,...t},a)=>s.jsx(i.tu,{ref:a,className:(0,l.cn)("z-50 min-w-[8rem] overflow-hidden rounded-md border border-slate-200 bg-white p-1 text-slate-950 shadow-lg data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 origin-[--radix-dropdown-menu-content-transform-origin] dark:border-slate-800 dark:bg-slate-950 dark:text-slate-50",e),...t})).displayName=i.tu.displayName;let p=r.forwardRef(({className:e,sideOffset:t=4,...a},r)=>s.jsx(i.Uv,{children:s.jsx(i.VY,{ref:r,sideOffset:t,className:(0,l.cn)("z-50 max-h-[var(--radix-dropdown-menu-content-available-height)] min-w-[8rem] overflow-y-auto overflow-x-hidden rounded-md border border-slate-200 bg-white p-1 text-slate-950 shadow-md data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 origin-[--radix-dropdown-menu-content-transform-origin] dark:border-slate-800 dark:bg-slate-950 dark:text-slate-50",e),...a})}));p.displayName=i.VY.displayName;let m=r.forwardRef(({className:e,inset:t,...a},r)=>s.jsx(i.ck,{ref:r,className:(0,l.cn)("relative flex cursor-default select-none items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-none transition-colors focus:bg-slate-100 focus:text-slate-900 data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0 dark:focus:bg-slate-800 dark:focus:text-slate-50",t&&"pl-8",e),...a}));m.displayName=i.ck.displayName,r.forwardRef(({className:e,children:t,checked:a,...r},n)=>(0,s.jsxs)(i.oC,{ref:n,className:(0,l.cn)("relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none transition-colors focus:bg-slate-100 focus:text-slate-900 data-[disabled]:pointer-events-none data-[disabled]:opacity-50 dark:focus:bg-slate-800 dark:focus:text-slate-50",e),checked:a,...r,children:[s.jsx("span",{className:"absolute left-2 flex h-3.5 w-3.5 items-center justify-center",children:s.jsx(i.wU,{children:s.jsx(o.Z,{className:"h-4 w-4"})})}),t]})).displayName=i.oC.displayName,r.forwardRef(({className:e,children:t,...a},r)=>(0,s.jsxs)(i.Rk,{ref:r,className:(0,l.cn)("relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none transition-colors focus:bg-slate-100 focus:text-slate-900 data-[disabled]:pointer-events-none data-[disabled]:opacity-50 dark:focus:bg-slate-800 dark:focus:text-slate-50",e),...a,children:[s.jsx("span",{className:"absolute left-2 flex h-3.5 w-3.5 items-center justify-center",children:s.jsx(i.wU,{children:s.jsx(d.Z,{className:"h-2 w-2 fill-current"})})}),t]})).displayName=i.Rk.displayName,r.forwardRef(({className:e,inset:t,...a},r)=>s.jsx(i.__,{ref:r,className:(0,l.cn)("px-2 py-1.5 text-sm font-semibold",t&&"pl-8",e),...a})).displayName=i.__.displayName,r.forwardRef(({className:e,...t},a)=>s.jsx(i.Z0,{ref:a,className:(0,l.cn)("-mx-1 my-1 h-px bg-slate-100 dark:bg-slate-800",e),...t})).displayName=i.Z0.displayName},2162:(e,t,a)=>{"use strict";a.d(t,{I:()=>n});var s=a(7486),r=a(618),i=a(5098);let n=r.forwardRef(({className:e,type:t,...a},r)=>s.jsx("input",{type:t,className:(0,i.cn)("flex h-10 w-full rounded-md border border-slate-200 bg-white px-3 py-2 text-base ring-offset-white file:border-0 file:bg-transparent file:text-sm file:font-medium file:text-slate-950 placeholder:text-slate-500 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-slate-950 focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 md:text-sm dark:border-slate-800 dark:bg-slate-950 dark:ring-offset-slate-950 dark:file:text-slate-50 dark:placeholder:text-slate-400 dark:focus-visible:ring-slate-300",e),ref:r,...a}));n.displayName="Input"},2119:(e,t,a)=>{"use strict";a.d(t,{x:()=>o});var s=a(7486),r=a(618),i=a(7051),n=a(5098);let o=r.forwardRef(({className:e,children:t,...a},r)=>(0,s.jsxs)(i.fC,{ref:r,className:(0,n.cn)("relative overflow-hidden",e),...a,children:[s.jsx(i.l_,{className:"h-full w-full rounded-[inherit]",children:t}),s.jsx(d,{}),s.jsx(i.Ns,{})]}));o.displayName=i.fC.displayName;let d=r.forwardRef(({className:e,orientation:t="vertical",...a},r)=>s.jsx(i.gb,{ref:r,orientation:t,className:(0,n.cn)("flex touch-none select-none transition-colors","vertical"===t&&"h-full w-2.5 border-l border-l-transparent p-[1px]","horizontal"===t&&"h-2.5 flex-col border-t border-t-transparent p-[1px]",e),...a,children:s.jsx(i.q4,{className:"relative flex-1 rounded-full bg-slate-200 dark:bg-slate-800"})}));d.displayName=i.gb.displayName},6637:(e,t,a)=>{"use strict";a.d(t,{Z:()=>o});var s=a(7486),r=a(618),i=a(7168),n=a(5098);let o=r.forwardRef(({className:e,orientation:t="horizontal",decorative:a=!0,...r},o)=>s.jsx(i.f,{ref:o,decorative:a,orientation:t,className:(0,n.cn)("shrink-0 bg-slate-200 dark:bg-slate-800","horizontal"===t?"h-[1px] w-full":"h-full w-[1px]",e),...r}));o.displayName=i.f.displayName},5875:(e,t,a)=>{"use strict";a.d(t,{_v:()=>c,aJ:()=>l,pn:()=>o,u:()=>d});var s=a(7486),r=a(618),i=a(6448),n=a(5098);let o=i.zt,d=i.fC,l=i.xz,c=r.forwardRef(({className:e,sideOffset:t=4,...a},r)=>s.jsx(i.VY,{ref:r,sideOffset:t,className:(0,n.cn)("z-50 overflow-hidden rounded-md border border-slate-200 bg-white px-3 py-1.5 text-sm text-slate-950 shadow-md animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 origin-[--radix-tooltip-content-transform-origin] dark:border-slate-800 dark:bg-slate-950 dark:text-slate-50",e),...a}));c.displayName=i.VY.displayName},6266:(e,t,a)=>{"use strict";a.d(t,{q:()=>o,w:()=>d});var s=a(7486),r=a(618),i=a(6811);let n=(0,r.createContext)(null);function o(){let e=(0,r.useContext)(n);if(!e)throw Error("useApp must be used inside AppProvider");return e}function d({children:e}){let t=(0,i.useRouter)(),[a,o]=(0,r.useState)([]),[d,l]=(0,r.useState)(""),[c,u]=(0,r.useState)(null),[p,m]=(0,r.useState)(null),[h,f]=(0,r.useState)([]),[g,b]=(0,r.useState)(!0),[x,y]=(0,r.useState)(!1),[v,w]=(0,r.useState)(null);(0,r.useRef)(null);let k=d?`?root=${encodeURIComponent(d)}`:"",N=(0,r.useCallback)(async e=>{let t=e||d;if(!t)return;let a=`?root=${encodeURIComponent(t)}`;try{let[e,t,s]=await Promise.all([fetch(`/api/summary${a}`).then(e=>e.json()),fetch(`/api/tasks${a}`).then(e=>e.json()),fetch(`/api/activity${a}&limit=30`).then(e=>e.json())]);u(e),m(t.board),f(Array.isArray(s)?s:[])}catch{}b(!1)},[d]),C=(0,r.useCallback)(async(e,t)=>{m(a=>{let s;if(!a)return a;let r=structuredClone(a);for(let a of Object.keys(r)){let i=r[a].findIndex(t=>t.id===e);-1!==i&&(s={...r[a][i],status:t},r[a]=r[a].filter(t=>t.id!==e))}return s&&r[t]&&(r[t]=[s,...r[t]]),r});try{await fetch(`/api/tasks${k}`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({taskId:e,status:t,actor:"human"})}),N()}catch{N()}},[k,N]),R=(0,r.useCallback)(async e=>{let a=await fetch(`/api/docs${k}&read=${encodeURIComponent(e)}`);w(await a.json()),t.push("/docs")},[k,t]);return s.jsx(n.Provider,{value:{projects:a,activeProject:d,summary:c,board:p,activity:h,liveIndicator:x,loading:g,selectedDoc:v,setSelectedDoc:w,rootParam:k,onProjectChange:function(e){l(e),N(e)},refresh:N,moveTask:C,openDoc:R},children:e})}},8508:(e,t,a)=>{"use strict";a.d(t,{x:()=>o});let s=[{id:"claude-md",name:"CLAUDE.md",description:"AI agent instructions for Claude Code",defaultPath:"CLAUDE.md",category:"ai-agent",content:`# {{PROJECT_NAME}} — Agent Instructions
|
|
2
2
|
|
|
3
3
|
## What this is
|
|
4
4
|
{{DESCRIPTION}}
|
|
@@ -12,7 +12,7 @@ exports.id=191,exports.ids=[191],exports.modules={1562:(e,t,a)=>{Promise.resolve
|
|
|
12
12
|
## Commands
|
|
13
13
|
\`\`\`bash
|
|
14
14
|
# Install dependencies
|
|
15
|
-
|
|
15
|
+
{{PACKAGE_MANAGER}} install
|
|
16
16
|
|
|
17
17
|
# Start development
|
|
18
18
|
npm run dev
|
|
@@ -24,10 +24,15 @@ npm run build
|
|
|
24
24
|
npm test
|
|
25
25
|
\`\`\`
|
|
26
26
|
|
|
27
|
-
##
|
|
28
|
-
-
|
|
29
|
-
-
|
|
30
|
-
-
|
|
27
|
+
## Architecture
|
|
28
|
+
- Primary language: {{PRIMARY_LANGUAGE}}
|
|
29
|
+
- Deployment: {{DEPLOYMENT_PLATFORM}}
|
|
30
|
+
- Key directories: \`src/\`, \`docs/\`, \`tests/\`
|
|
31
|
+
- See \`docs/architecture/overview.md\` for full details
|
|
32
|
+
|
|
33
|
+
## Read before coding
|
|
34
|
+
- @docs/architecture/overview.md
|
|
35
|
+
- @CONTRIBUTING.md
|
|
31
36
|
|
|
32
37
|
## Key conventions
|
|
33
38
|
{{CONVENTIONS}}
|
|
@@ -36,11 +41,18 @@ npm test
|
|
|
36
41
|
{{KEY_FEATURES}}
|
|
37
42
|
|
|
38
43
|
## Non-negotiables
|
|
39
|
-
-
|
|
44
|
+
- Always run \`npm run build\` before marking a task done — build must pass
|
|
45
|
+
- Never use localStorage — causes SSR/client mismatch
|
|
46
|
+
- Never commit secrets or credentials
|
|
40
47
|
- Maintain test coverage
|
|
41
48
|
- Follow security best practices
|
|
42
|
-
|
|
43
|
-
|
|
49
|
+
|
|
50
|
+
## Code style
|
|
51
|
+
- Follow existing patterns before introducing new abstractions
|
|
52
|
+
- Keep modules small and focused
|
|
53
|
+
- Write tests for business logic
|
|
54
|
+
- Prefer explicit over implicit
|
|
55
|
+
`},{id:"agents-md",name:"AGENTS.md",description:"AI agent instructions (multi-agent / OpenAI)",defaultPath:"AGENTS.md",category:"ai-agent",content:`# {{PROJECT_NAME}} — Agent Instructions
|
|
44
56
|
|
|
45
57
|
## Overview
|
|
46
58
|
{{DESCRIPTION}}
|
|
@@ -63,7 +75,7 @@ npm test
|
|
|
63
75
|
- Follow existing code patterns
|
|
64
76
|
- Write tests for new features
|
|
65
77
|
- Never commit secrets or credentials
|
|
66
|
-
`},{id:"gemini-md",name:"GEMINI.md",description:"AI agent instructions for Gemini CLI",defaultPath:"GEMINI.md",content:`# {{PROJECT_NAME}} — Gemini Agent Instructions
|
|
78
|
+
`},{id:"gemini-md",name:"GEMINI.md",description:"AI agent instructions for Gemini CLI",defaultPath:"GEMINI.md",category:"ai-agent",content:`# {{PROJECT_NAME}} — Gemini Agent Instructions
|
|
67
79
|
|
|
68
80
|
## What this is
|
|
69
81
|
{{DESCRIPTION}}
|
|
@@ -93,7 +105,7 @@ npm test
|
|
|
93
105
|
- Follow existing code patterns
|
|
94
106
|
- Write tests for new features
|
|
95
107
|
- Never commit secrets or credentials
|
|
96
|
-
`},{id:"cursorrules",name:".cursorrules",description:"Cursor IDE rules for AI assistance",defaultPath:".cursorrules",content:`# {{PROJECT_NAME}} — Cursor Rules
|
|
108
|
+
`},{id:"cursorrules",name:".cursorrules",description:"Cursor IDE rules for AI assistance",defaultPath:".cursorrules",category:"ai-agent",content:`# {{PROJECT_NAME}} — Cursor Rules
|
|
97
109
|
|
|
98
110
|
## Project overview
|
|
99
111
|
{{DESCRIPTION}}
|
|
@@ -115,7 +127,7 @@ npm test
|
|
|
115
127
|
- Don't break existing tests
|
|
116
128
|
- Don't commit secrets or credentials
|
|
117
129
|
- Don't over-engineer simple solutions
|
|
118
|
-
`},{id:"windsurfrules",name:".windsurfrules",description:"Windsurf IDE rules for AI assistance",defaultPath:".windsurfrules",content:`# {{PROJECT_NAME}} — Windsurf Rules
|
|
130
|
+
`},{id:"windsurfrules",name:".windsurfrules",description:"Windsurf IDE rules for AI assistance",defaultPath:".windsurfrules",category:"ai-agent",content:`# {{PROJECT_NAME}} — Windsurf Rules
|
|
119
131
|
|
|
120
132
|
## Project overview
|
|
121
133
|
{{DESCRIPTION}}
|
|
@@ -135,7 +147,7 @@ npm test
|
|
|
135
147
|
- Don't introduce breaking changes
|
|
136
148
|
- Don't commit secrets or credentials
|
|
137
149
|
- Maintain test coverage
|
|
138
|
-
`},{id:"copilot-instructions",name:"Copilot Instructions",description:"GitHub Copilot custom instructions",defaultPath:".github/copilot-instructions.md",content:`# GitHub Copilot Instructions — {{PROJECT_NAME}}
|
|
150
|
+
`},{id:"copilot-instructions",name:"Copilot Instructions",description:"GitHub Copilot custom instructions",defaultPath:".github/copilot-instructions.md",category:"ai-agent",content:`# GitHub Copilot Instructions — {{PROJECT_NAME}}
|
|
139
151
|
|
|
140
152
|
## Project overview
|
|
141
153
|
{{DESCRIPTION}}
|
|
@@ -159,727 +171,1041 @@ npm test
|
|
|
159
171
|
- Write tests for all new functionality
|
|
160
172
|
- Maintain existing test coverage
|
|
161
173
|
- Use the project's established testing patterns
|
|
162
|
-
`},{id:"
|
|
174
|
+
`}],r=[{id:"contributing",name:"CONTRIBUTING.md",description:"Contribution guidelines",defaultPath:"CONTRIBUTING.md",category:"github",content:`# Contributing to {{PROJECT_NAME}}
|
|
163
175
|
|
|
164
|
-
|
|
165
|
-
**Last updated:** {{DATE}}
|
|
166
|
-
**Author:**
|
|
167
|
-
**Stakeholders:**
|
|
176
|
+
Thank you for your interest in contributing!
|
|
168
177
|
|
|
169
|
-
##
|
|
170
|
-
{{DESCRIPTION}}
|
|
178
|
+
## Getting started
|
|
171
179
|
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
-
|
|
180
|
+
1. Fork the repository
|
|
181
|
+
2. Clone your fork: \`git clone {{REPO_URL}}\`
|
|
182
|
+
3. Create a feature branch: \`git checkout -b feat/your-feature\`
|
|
183
|
+
4. Make your changes
|
|
184
|
+
5. Submit a pull request
|
|
175
185
|
|
|
176
|
-
##
|
|
177
|
-
-
|
|
178
|
-
-
|
|
186
|
+
## Branch naming
|
|
179
187
|
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
|
188
|
+
| Type | Pattern | Example |
|
|
189
|
+
|------|---------|---------|
|
|
190
|
+
| Feature | \`feat/<description>\` | \`feat/user-auth\` |
|
|
191
|
+
| Fix | \`fix/<description>\` | \`fix/login-crash\` |
|
|
192
|
+
| Chore | \`chore/<description>\` | \`chore/update-deps\` |
|
|
193
|
+
| Docs | \`docs/<description>\` | \`docs/api-guide\` |
|
|
194
|
+
| Refactor | \`refactor/<description>\` | \`refactor/auth-module\` |
|
|
195
|
+
| Release | \`release/<version>\` | \`release/v1.2.0\` |
|
|
184
196
|
|
|
185
|
-
##
|
|
197
|
+
## Commit conventions
|
|
186
198
|
|
|
187
|
-
|
|
188
|
-
{{KEY_FEATURES}}
|
|
199
|
+
We use [Conventional Commits](https://conventionalcommits.org):
|
|
189
200
|
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
201
|
+
| Type | When to use |
|
|
202
|
+
|------|------------|
|
|
203
|
+
| \`feat\` | New feature |
|
|
204
|
+
| \`fix\` | Bug fix |
|
|
205
|
+
| \`docs\` | Documentation only |
|
|
206
|
+
| \`refactor\` | Code change that's neither fix nor feature |
|
|
207
|
+
| \`test\` | Adding or updating tests |
|
|
208
|
+
| \`chore\` | Build process, dependencies, tooling |
|
|
209
|
+
| \`perf\` | Performance improvement |
|
|
210
|
+
| \`ci\` | CI/CD changes |
|
|
211
|
+
|
|
212
|
+
Examples:
|
|
213
|
+
\`\`\`
|
|
214
|
+
feat: add user authentication
|
|
215
|
+
fix: resolve login redirect issue
|
|
216
|
+
docs: update API reference
|
|
217
|
+
chore: upgrade dependencies
|
|
218
|
+
feat!: redesign auth API (breaking change — note the !)
|
|
219
|
+
\`\`\`
|
|
195
220
|
|
|
196
|
-
##
|
|
197
|
-
| Metric | Current | Target |
|
|
198
|
-
|--------|---------|--------|
|
|
199
|
-
| | | |
|
|
221
|
+
## PR size guidance
|
|
200
222
|
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
|
223
|
+
| Size | Lines changed | Guidance |
|
|
224
|
+
|------|--------------|---------|
|
|
225
|
+
| Small | < 400 lines | Ideal — fast to review |
|
|
226
|
+
| Medium | 400–800 lines | Acceptable — add extra context in description |
|
|
227
|
+
| Large | > 800 lines | Needs discussion before opening — split if possible |
|
|
205
228
|
|
|
206
|
-
|
|
207
|
-
-
|
|
208
|
-
`},{id:"architecture-overview",name:"Architecture Overview",description:"System architecture doc",defaultPath:"docs/architecture/overview.md",content:`# Architecture Overview — {{PROJECT_NAME}}
|
|
229
|
+
Large PRs slow down the team and increase the chance of missed issues. When in doubt, split.
|
|
209
230
|
|
|
210
|
-
|
|
231
|
+
## Pull request process
|
|
211
232
|
|
|
212
|
-
|
|
213
|
-
|
|
233
|
+
1. Fill out the PR template completely
|
|
234
|
+
2. Ensure all CI checks pass
|
|
235
|
+
3. Request review from at least one maintainer
|
|
236
|
+
4. Address all review comments
|
|
237
|
+
5. Squash commits before merge
|
|
214
238
|
|
|
215
|
-
##
|
|
216
|
-
{{TECH_STACK}}
|
|
239
|
+
## Code review checklist
|
|
217
240
|
|
|
218
|
-
|
|
241
|
+
**Author:**
|
|
242
|
+
- [ ] Self-reviewed the diff before requesting review
|
|
243
|
+
- [ ] PR description explains the "why", not just the "what"
|
|
244
|
+
- [ ] Tests added/updated and passing
|
|
245
|
+
- [ ] No secrets or credentials in code
|
|
246
|
+
- [ ] Breaking changes noted in PR description
|
|
219
247
|
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
248
|
+
**Reviewer:**
|
|
249
|
+
- [ ] Code is correct and handles edge cases
|
|
250
|
+
- [ ] No obvious performance issues
|
|
251
|
+
- [ ] Tests are meaningful (not just coverage padding)
|
|
252
|
+
- [ ] Naming is clear and consistent with the codebase
|
|
253
|
+
- [ ] Documentation updated if public API changed
|
|
226
254
|
|
|
227
|
-
##
|
|
255
|
+
## Code style
|
|
256
|
+
{{CONVENTIONS}}
|
|
228
257
|
|
|
229
|
-
|
|
230
|
-
|-----------|---------------|------|
|
|
231
|
-
| | | |
|
|
258
|
+
## Reporting bugs
|
|
232
259
|
|
|
233
|
-
|
|
260
|
+
Open an issue with:
|
|
261
|
+
- Description of the bug
|
|
262
|
+
- Steps to reproduce
|
|
263
|
+
- Expected vs actual behavior
|
|
264
|
+
- Environment details
|
|
265
|
+
`},{id:"security",name:"SECURITY.md",description:"Security policy and vulnerability reporting",defaultPath:"SECURITY.md",category:"github",content:`# Security Policy — {{PROJECT_NAME}}
|
|
234
266
|
|
|
235
|
-
|
|
236
|
-
2.
|
|
237
|
-
3.
|
|
267
|
+
## Supported versions
|
|
238
268
|
|
|
239
|
-
|
|
240
|
-
|
|
269
|
+
| Version | Supported |
|
|
270
|
+
|---------|-----------|
|
|
271
|
+
| latest | ✅ |
|
|
272
|
+
| < 1.0 | ❌ |
|
|
241
273
|
|
|
242
|
-
##
|
|
243
|
-
- Authentication:
|
|
244
|
-
- Authorization:
|
|
245
|
-
- Data validation:
|
|
246
|
-
- Secrets management:
|
|
274
|
+
## Reporting a vulnerability
|
|
247
275
|
|
|
248
|
-
|
|
249
|
-
-
|
|
250
|
-
`},{id:"api-reference",name:"API Reference",description:"API endpoints reference",defaultPath:"docs/api-reference.md",content:`# API Reference — {{PROJECT_NAME}}
|
|
276
|
+
**Please do not report security vulnerabilities through public GitHub issues.**
|
|
251
277
|
|
|
252
|
-
|
|
278
|
+
To report a security issue, email: **security@example.com**
|
|
253
279
|
|
|
254
|
-
|
|
280
|
+
You may optionally encrypt your report using our PGP key (key ID: \`0x00000000\`, available on keys.openpgp.org).
|
|
255
281
|
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
282
|
+
Include:
|
|
283
|
+
- Description of the vulnerability
|
|
284
|
+
- Steps to reproduce
|
|
285
|
+
- Potential impact
|
|
286
|
+
- Any suggested mitigations
|
|
259
287
|
|
|
260
|
-
|
|
288
|
+
You will receive a response within **48 hours**. We will:
|
|
289
|
+
1. Confirm receipt of your report
|
|
290
|
+
2. Investigate and assess the issue
|
|
291
|
+
3. Release a fix or mitigation
|
|
292
|
+
4. Credit you in the release notes (unless you prefer anonymity)
|
|
261
293
|
|
|
262
|
-
|
|
294
|
+
## Vulnerability SLAs
|
|
263
295
|
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
296
|
+
| Severity | Fix SLA |
|
|
297
|
+
|----------|---------|
|
|
298
|
+
| Critical | 48 hours |
|
|
299
|
+
| High | 7 days |
|
|
300
|
+
| Medium | 30 days |
|
|
301
|
+
| Low | 90 days |
|
|
267
302
|
|
|
268
|
-
|
|
303
|
+
Dependabot alerts for **critical** vulnerabilities must be resolved within 48 hours. Run \`npm audit\` in CI on every PR.
|
|
269
304
|
|
|
270
|
-
|
|
271
|
-
- **Headers:** \`X-RateLimit-Limit\`, \`X-RateLimit-Remaining\`, \`X-RateLimit-Reset\`
|
|
305
|
+
## Secrets rotation schedule
|
|
272
306
|
|
|
273
|
-
|
|
307
|
+
| Secret | Rotation | Owner |
|
|
308
|
+
|--------|----------|-------|
|
|
309
|
+
| JWT signing key | Every 90 days | Platform team |
|
|
310
|
+
| Database passwords | Every 180 days | Platform team |
|
|
311
|
+
| API keys (third-party) | On staff change | Security team |
|
|
312
|
+
| Deploy tokens | Every 90 days | DevOps |
|
|
274
313
|
|
|
275
|
-
|
|
314
|
+
## OWASP Top 10 checklist
|
|
276
315
|
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
316
|
+
- [ ] **A01 Broken Access Control** — Enforce authorization on every endpoint; deny by default
|
|
317
|
+
- [ ] **A02 Cryptographic Failures** — Use TLS everywhere; never store plaintext secrets; use bcrypt/argon2 for passwords
|
|
318
|
+
- [ ] **A03 Injection** — Use parameterized queries; validate and sanitize all input
|
|
319
|
+
- [ ] **A04 Insecure Design** — Threat model new features; use principle of least privilege
|
|
320
|
+
- [ ] **A05 Security Misconfiguration** — Harden defaults; disable unused features; set security headers
|
|
321
|
+
- [ ] **A06 Vulnerable Components** — Run \`npm audit\` in CI; automate with Dependabot
|
|
322
|
+
- [ ] **A07 Auth Failures** — Implement MFA; lock accounts after failed attempts; use secure session management
|
|
323
|
+
- [ ] **A08 Software Integrity Failures** — Verify checksums; use lockfiles; pin CI action versions
|
|
324
|
+
- [ ] **A09 Logging Failures** — Log auth events, access failures; never log secrets or PII
|
|
325
|
+
- [ ] **A10 SSRF** — Validate and allowlist URLs for any server-side requests
|
|
280
326
|
|
|
281
|
-
##
|
|
327
|
+
## Security best practices
|
|
282
328
|
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
| 429 | Too many requests |
|
|
291
|
-
| 500 | Internal server error |
|
|
329
|
+
When contributing to this project:
|
|
330
|
+
- Never commit secrets, tokens, or credentials
|
|
331
|
+
- Use environment variables for all sensitive configuration
|
|
332
|
+
- Validate and sanitize all user input
|
|
333
|
+
- Follow the principle of least privilege
|
|
334
|
+
- Keep dependencies up to date
|
|
335
|
+
`},{id:"pr-template",name:"PR Template",description:"Pull request template",defaultPath:".github/pull_request_template.md",category:"github",content:`## Description
|
|
292
336
|
|
|
293
|
-
|
|
337
|
+
<!-- Briefly describe the changes and why they were made -->
|
|
294
338
|
|
|
295
|
-
|
|
339
|
+
## Type of change
|
|
296
340
|
|
|
297
|
-
|
|
341
|
+
- [ ] Bug fix (non-breaking change that fixes an issue)
|
|
342
|
+
- [ ] New feature (non-breaking change that adds functionality)
|
|
343
|
+
- [ ] Breaking change (fix or feature that would cause existing functionality to change)
|
|
344
|
+
- [ ] Documentation update
|
|
345
|
+
- [ ] Refactor / code cleanup
|
|
346
|
+
- [ ] Dependency update
|
|
298
347
|
|
|
299
|
-
|
|
300
|
-
- \`limit\` (integer, default 20) — items per page
|
|
301
|
-
- \`cursor\` (string) — pagination cursor
|
|
348
|
+
## Related issues
|
|
302
349
|
|
|
303
|
-
|
|
304
|
-
\`\`\`json
|
|
305
|
-
{
|
|
306
|
-
"data": [],
|
|
307
|
-
"cursor": null,
|
|
308
|
-
"total": 0
|
|
309
|
-
}
|
|
310
|
-
\`\`\`
|
|
350
|
+
Closes #
|
|
311
351
|
|
|
312
|
-
|
|
352
|
+
## How to test
|
|
313
353
|
|
|
314
|
-
|
|
354
|
+
1.
|
|
355
|
+
2.
|
|
356
|
+
3.
|
|
315
357
|
|
|
316
|
-
|
|
317
|
-
\`\`\`json
|
|
318
|
-
{}
|
|
319
|
-
\`\`\`
|
|
358
|
+
## Screenshots / recordings
|
|
320
359
|
|
|
321
|
-
|
|
322
|
-
\`\`\`json
|
|
323
|
-
{}
|
|
324
|
-
\`\`\`
|
|
325
|
-
`},{id:"runbook",name:"Runbook",description:"Operational runbook",defaultPath:"docs/runbook.md",content:`# Runbook — {{PROJECT_NAME}}
|
|
360
|
+
<!-- If applicable, add screenshots or screen recordings -->
|
|
326
361
|
|
|
327
|
-
|
|
362
|
+
## Checklist
|
|
328
363
|
|
|
329
|
-
|
|
330
|
-
|
|
364
|
+
- [ ] My code follows the project's style guidelines
|
|
365
|
+
- [ ] I have performed a self-review of my changes
|
|
366
|
+
- [ ] I have added tests that prove my fix or feature works
|
|
367
|
+
- [ ] New and existing unit tests pass locally
|
|
368
|
+
- [ ] I have updated documentation if needed
|
|
369
|
+
- [ ] No secrets or credentials are included
|
|
370
|
+
`},{id:"bug-report",name:"Bug Report Template",description:"GitHub issue template for bugs",defaultPath:".github/ISSUE_TEMPLATE/bug_report.md",category:"github",content:`---
|
|
371
|
+
name: Bug report
|
|
372
|
+
about: Create a report to help us improve
|
|
373
|
+
labels: bug
|
|
374
|
+
---
|
|
331
375
|
|
|
332
|
-
##
|
|
376
|
+
## Describe the bug
|
|
333
377
|
|
|
334
|
-
|
|
335
|
-
|--------|--------|
|
|
336
|
-
| Availability | 99.9% |
|
|
337
|
-
| P95 latency | < 500ms |
|
|
338
|
-
| Error rate | < 0.1% |
|
|
378
|
+
A clear and concise description of what the bug is.
|
|
339
379
|
|
|
340
|
-
##
|
|
380
|
+
## Steps to reproduce
|
|
341
381
|
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
| Staging | | Pre-release testing |
|
|
346
|
-
| Development | | Local dev |
|
|
382
|
+
1. Go to '...'
|
|
383
|
+
2. Click on '...'
|
|
384
|
+
3. See error
|
|
347
385
|
|
|
348
|
-
##
|
|
386
|
+
## Expected behavior
|
|
349
387
|
|
|
350
|
-
|
|
351
|
-
|-------|-----------|----------|--------|
|
|
352
|
-
| | | | |
|
|
388
|
+
A clear and concise description of what you expected to happen.
|
|
353
389
|
|
|
354
|
-
##
|
|
390
|
+
## Actual behavior
|
|
355
391
|
|
|
356
|
-
|
|
357
|
-
|------|------|---------|
|
|
358
|
-
| Primary | | |
|
|
359
|
-
| Secondary | | |
|
|
392
|
+
What actually happened.
|
|
360
393
|
|
|
361
|
-
##
|
|
394
|
+
## Screenshots
|
|
362
395
|
|
|
363
|
-
|
|
396
|
+
If applicable, add screenshots to help explain your problem.
|
|
364
397
|
|
|
365
|
-
|
|
366
|
-
2.
|
|
367
|
-
3.
|
|
398
|
+
## Environment
|
|
368
399
|
|
|
369
|
-
|
|
400
|
+
- OS: [e.g. macOS 14]
|
|
401
|
+
- Browser: [e.g. Chrome 120]
|
|
402
|
+
- Version: [e.g. 1.2.3]
|
|
403
|
+
- Node.js: [e.g. 20.x]
|
|
370
404
|
|
|
371
|
-
|
|
372
|
-
2.
|
|
373
|
-
3.
|
|
405
|
+
## Additional context
|
|
374
406
|
|
|
375
|
-
|
|
407
|
+
Add any other context about the problem here.
|
|
408
|
+
`},{id:"feature-request",name:"Feature Request Template",description:"GitHub issue template for features",defaultPath:".github/ISSUE_TEMPLATE/feature_request.md",category:"github",content:`---
|
|
409
|
+
name: Feature request
|
|
410
|
+
about: Suggest an idea for this project
|
|
411
|
+
labels: enhancement
|
|
412
|
+
---
|
|
376
413
|
|
|
377
|
-
|
|
378
|
-
1. Check application logs
|
|
379
|
-
2. Check downstream dependencies
|
|
380
|
-
3. Review recent deploys
|
|
414
|
+
## Problem
|
|
381
415
|
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
2. Check cache hit rates
|
|
385
|
-
3. Review resource utilization
|
|
416
|
+
Is your feature request related to a problem? Please describe.
|
|
417
|
+
A clear and concise description of what the problem is.
|
|
386
418
|
|
|
387
|
-
##
|
|
419
|
+
## Proposed solution
|
|
388
420
|
|
|
389
|
-
|
|
390
|
-
2. Team lead
|
|
391
|
-
3. Engineering manager
|
|
392
|
-
`},{id:"adr",name:"Architecture Decision",description:"Architecture Decision Record",defaultPath:"docs/architecture/decisions/ADR-001.md",content:`# ADR-001: Title
|
|
421
|
+
A clear and concise description of what you want to happen.
|
|
393
422
|
|
|
394
|
-
|
|
395
|
-
**Date:** {{DATE}}
|
|
396
|
-
**Deciders:**
|
|
423
|
+
## Alternatives considered
|
|
397
424
|
|
|
398
|
-
|
|
399
|
-
What is the issue that we're seeing that is motivating this decision or change?
|
|
425
|
+
A clear and concise description of any alternative solutions or features you've considered.
|
|
400
426
|
|
|
401
|
-
##
|
|
402
|
-
What is the change that we're proposing and/or doing?
|
|
427
|
+
## Implementation notes
|
|
403
428
|
|
|
404
|
-
|
|
405
|
-
Why did we choose this option?
|
|
429
|
+
Any thoughts on how this might be implemented?
|
|
406
430
|
|
|
407
|
-
##
|
|
408
|
-
- **Option A:** Description — pros/cons
|
|
409
|
-
- **Option B:** Description — pros/cons
|
|
431
|
+
## Additional context
|
|
410
432
|
|
|
411
|
-
|
|
433
|
+
Add any other context, mockups, or screenshots about the feature request here.
|
|
434
|
+
`}],i=[{id:"changelog",name:"CHANGELOG.md",description:"Keep a Changelog format",defaultPath:"CHANGELOG.md",category:"process",content:`# Changelog — {{PROJECT_NAME}}
|
|
412
435
|
|
|
413
|
-
|
|
436
|
+
All notable changes to this project will be documented in this file.
|
|
437
|
+
|
|
438
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
439
|
+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
440
|
+
|
|
441
|
+
## [Unreleased]
|
|
442
|
+
|
|
443
|
+
### Added
|
|
414
444
|
-
|
|
415
445
|
|
|
416
|
-
###
|
|
446
|
+
### Changed
|
|
417
447
|
-
|
|
418
448
|
|
|
419
|
-
###
|
|
449
|
+
### Fixed
|
|
420
450
|
-
|
|
421
|
-
`},{id:"meeting-notes",name:"Meeting Notes",description:"Meeting notes template",defaultPath:`docs/meetings/${m}.md`,content:`# Meeting Notes — ${m}
|
|
422
451
|
|
|
423
|
-
|
|
424
|
-
|
|
452
|
+
### Removed
|
|
453
|
+
-
|
|
425
454
|
|
|
426
|
-
##
|
|
455
|
+
## [1.0.0] — {{DATE}}
|
|
427
456
|
|
|
428
|
-
|
|
429
|
-
|
|
457
|
+
### Added
|
|
458
|
+
- Initial release
|
|
459
|
+
`},{id:"deployment",name:"DEPLOYMENT.md",description:"Deployment guide and procedures",defaultPath:"DEPLOYMENT.md",category:"process",content:`# Deployment Guide — {{PROJECT_NAME}}
|
|
430
460
|
|
|
431
|
-
|
|
461
|
+
**Last updated:** {{DATE}}
|
|
432
462
|
|
|
433
|
-
##
|
|
463
|
+
## Environments
|
|
434
464
|
|
|
435
|
-
|
|
465
|
+
| Environment | URL | Branch | Auto-deploy |
|
|
466
|
+
|-------------|-----|--------|-------------|
|
|
467
|
+
| Production | | \`main\` | No |
|
|
468
|
+
| Staging | | \`develop\` | Yes |
|
|
469
|
+
| Preview | | PRs | Yes |
|
|
436
470
|
|
|
437
|
-
|
|
438
|
-
|--------|-------|-----|
|
|
439
|
-
| | | |
|
|
471
|
+
## Prerequisites
|
|
440
472
|
|
|
441
|
-
|
|
442
|
-
|
|
473
|
+
- Access to deployment platform
|
|
474
|
+
- Environment variables configured (see \`.env.example\`)
|
|
475
|
+
- CI/CD pipeline passing
|
|
476
|
+
|
|
477
|
+
## Deploy to production
|
|
478
|
+
|
|
479
|
+
\`\`\`bash
|
|
480
|
+
# 1. Ensure tests pass
|
|
481
|
+
npm test
|
|
482
|
+
|
|
483
|
+
# 2. Build and verify
|
|
484
|
+
npm run build
|
|
485
|
+
|
|
486
|
+
# 3. Merge to main
|
|
487
|
+
git checkout main && git merge develop
|
|
488
|
+
|
|
489
|
+
# 4. Tag the release
|
|
490
|
+
git tag v1.x.x && git push --tags
|
|
491
|
+
\`\`\`
|
|
492
|
+
|
|
493
|
+
## Environment variables
|
|
494
|
+
|
|
495
|
+
| Variable | Required | Description |
|
|
496
|
+
|----------|----------|-------------|
|
|
497
|
+
| | Yes | |
|
|
498
|
+
|
|
499
|
+
## Rollback procedure
|
|
500
|
+
|
|
501
|
+
1. Identify the last stable release tag
|
|
502
|
+
2. \`git checkout <tag>\`
|
|
503
|
+
3. Redeploy the previous version
|
|
504
|
+
4. Verify the rollback with smoke tests
|
|
505
|
+
|
|
506
|
+
## Smoke tests
|
|
507
|
+
|
|
508
|
+
After every deploy, verify:
|
|
509
|
+
- [ ] App loads at production URL
|
|
510
|
+
- [ ] Auth flow works
|
|
511
|
+
- [ ] Core features functional
|
|
512
|
+
- [ ] No error spikes in monitoring
|
|
513
|
+
|
|
514
|
+
## Contacts
|
|
515
|
+
|
|
516
|
+
| Role | Contact |
|
|
517
|
+
|------|---------|
|
|
518
|
+
| On-call | |
|
|
519
|
+
| Release manager | |
|
|
520
|
+
`},{id:"testing",name:"TESTING.md",description:"Testing strategy and guide",defaultPath:"TESTING.md",category:"process",content:`# Testing Guide — {{PROJECT_NAME}}
|
|
443
521
|
|
|
444
522
|
**Last updated:** {{DATE}}
|
|
445
523
|
|
|
446
|
-
##
|
|
447
|
-
{{DESCRIPTION}}
|
|
524
|
+
## Test pyramid
|
|
448
525
|
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
526
|
+
\`\`\`
|
|
527
|
+
/\\
|
|
528
|
+
/E2E\\ 10% — Critical user flows only
|
|
529
|
+
/------\\
|
|
530
|
+
/Integr. \\ 20% — API, DB, service boundaries
|
|
531
|
+
/----------\\
|
|
532
|
+
/ Unit \\ 70% — Functions, logic, utilities
|
|
533
|
+
/______________\\
|
|
534
|
+
\`\`\`
|
|
453
535
|
|
|
454
|
-
##
|
|
455
|
-
- [ ] Clone the repository
|
|
456
|
-
- [ ] Set up local development environment
|
|
457
|
-
- [ ] Run the app locally
|
|
458
|
-
- [ ] Read the architecture overview
|
|
459
|
-
- [ ] Meet the team
|
|
536
|
+
## Test strategy
|
|
460
537
|
|
|
461
|
-
|
|
538
|
+
| Layer | Type | Tool | Coverage target |
|
|
539
|
+
|-------|------|------|----------------|
|
|
540
|
+
| Unit | Functions/logic | {{TEST_FRAMEWORK}} | 80%+ |
|
|
541
|
+
| Integration | API/DB | {{TEST_FRAMEWORK}} | 70%+ |
|
|
542
|
+
| E2E | User flows | Playwright | Key paths |
|
|
543
|
+
|
|
544
|
+
## Coverage targets by directory
|
|
545
|
+
|
|
546
|
+
| Directory | Target | Rationale |
|
|
547
|
+
|-----------|--------|-----------|
|
|
548
|
+
| \`src/lib/\` | 90%+ | Core business logic |
|
|
549
|
+
| \`src/api/\` | 80%+ | API handlers |
|
|
550
|
+
| \`src/components/\` | 60%+ | UI — focus on logic, not rendering |
|
|
551
|
+
| \`src/utils/\` | 90%+ | Pure utility functions |
|
|
552
|
+
|
|
553
|
+
## Running tests
|
|
462
554
|
|
|
463
555
|
\`\`\`bash
|
|
464
|
-
#
|
|
465
|
-
|
|
466
|
-
cd {{PROJECT_NAME}}
|
|
556
|
+
# Run all tests
|
|
557
|
+
npm test
|
|
467
558
|
|
|
468
|
-
#
|
|
469
|
-
npm
|
|
559
|
+
# Run with coverage
|
|
560
|
+
npm run test:coverage
|
|
470
561
|
|
|
471
|
-
#
|
|
472
|
-
|
|
562
|
+
# Run E2E tests
|
|
563
|
+
npm run test:e2e
|
|
473
564
|
|
|
474
|
-
#
|
|
475
|
-
npm run
|
|
565
|
+
# Watch mode
|
|
566
|
+
npm run test:watch
|
|
476
567
|
\`\`\`
|
|
477
568
|
|
|
478
|
-
##
|
|
479
|
-
{{TECH_STACK}}
|
|
569
|
+
## Writing tests
|
|
480
570
|
|
|
481
|
-
|
|
482
|
-
- Recommended: VS Code or Cursor
|
|
483
|
-
- Install recommended extensions (see \`.vscode/extensions.json\`)
|
|
484
|
-
- Enable format on save
|
|
571
|
+
### Unit test example
|
|
485
572
|
|
|
486
|
-
|
|
573
|
+
\`\`\`typescript
|
|
574
|
+
describe('MyFunction', () => {
|
|
575
|
+
it('should return expected value', () => {
|
|
576
|
+
expect(myFunction(input)).toBe(expected)
|
|
577
|
+
})
|
|
578
|
+
})
|
|
579
|
+
\`\`\`
|
|
580
|
+
|
|
581
|
+
### Integration test guidelines
|
|
582
|
+
- Use a real database (not mocks) for DB tests
|
|
583
|
+
- Reset state between tests
|
|
584
|
+
- Test happy path and error cases
|
|
487
585
|
|
|
586
|
+
### E2E test guidelines
|
|
587
|
+
- Cover critical user journeys
|
|
588
|
+
- Use stable selectors (\`data-testid\`)
|
|
589
|
+
- Run against staging environment
|
|
590
|
+
|
|
591
|
+
### Playwright config example
|
|
592
|
+
|
|
593
|
+
\`\`\`typescript
|
|
594
|
+
// playwright.config.ts
|
|
595
|
+
import { defineConfig, devices } from '@playwright/test'
|
|
596
|
+
|
|
597
|
+
export default defineConfig({
|
|
598
|
+
testDir: './e2e',
|
|
599
|
+
fullyParallel: true,
|
|
600
|
+
forbidOnly: !!process.env.CI,
|
|
601
|
+
retries: process.env.CI ? 2 : 0,
|
|
602
|
+
reporter: 'html',
|
|
603
|
+
use: {
|
|
604
|
+
baseURL: process.env.PLAYWRIGHT_BASE_URL ?? 'http://localhost:3000',
|
|
605
|
+
trace: 'on-first-retry',
|
|
606
|
+
},
|
|
607
|
+
projects: [
|
|
608
|
+
{name: 'chromium', use: {...devices['Desktop Chrome']}},
|
|
609
|
+
{name: 'Mobile Safari', use: {...devices['iPhone 13']}},
|
|
610
|
+
],
|
|
611
|
+
webServer: {
|
|
612
|
+
command: 'npm run dev',
|
|
613
|
+
url: 'http://localhost:3000',
|
|
614
|
+
reuseExistingServer: !process.env.CI,
|
|
615
|
+
},
|
|
616
|
+
})
|
|
488
617
|
\`\`\`
|
|
489
|
-
|
|
618
|
+
|
|
619
|
+
## Flaky test policy
|
|
620
|
+
|
|
621
|
+
1. **Quarantine immediately** — tag with \`@flaky\` and skip in CI (\`test.skip\`)
|
|
622
|
+
2. **Create a ticket** — track as a P2 bug with a 2-week SLA to fix
|
|
623
|
+
3. **Root cause** — common causes: timing issues, shared state, network calls
|
|
624
|
+
4. **Fix or delete** — flaky tests are worse than no tests (false confidence)
|
|
625
|
+
|
|
626
|
+
Quarantine example:
|
|
627
|
+
\`\`\`typescript
|
|
628
|
+
test.skip('flaky: timing issue with animation', async ({ page }) => {
|
|
629
|
+
// TODO: fix by waiting for animation end event instead of sleep
|
|
630
|
+
})
|
|
490
631
|
\`\`\`
|
|
491
632
|
|
|
492
|
-
##
|
|
633
|
+
## Test organization
|
|
634
|
+
|
|
635
|
+
\`\`\`
|
|
636
|
+
src/
|
|
637
|
+
__tests__/ # Unit tests
|
|
638
|
+
__integration__/ # Integration tests
|
|
639
|
+
e2e/ # E2E tests
|
|
640
|
+
\`\`\`
|
|
641
|
+
|
|
642
|
+
## CI/CD
|
|
643
|
+
|
|
644
|
+
Tests run automatically on every PR. PRs cannot merge with failing tests.
|
|
645
|
+
`},{id:"glossary",name:"Glossary",description:"Project terminology reference",defaultPath:"docs/glossary.md",category:"process",content:`# Glossary — {{PROJECT_NAME}}
|
|
646
|
+
|
|
647
|
+
**Last updated:** {{DATE}}
|
|
648
|
+
|
|
649
|
+
This document defines terms used throughout the project documentation and codebase.
|
|
650
|
+
|
|
651
|
+
## Terms
|
|
652
|
+
|
|
653
|
+
| Term | Definition |
|
|
654
|
+
|------|------------|
|
|
655
|
+
| | |
|
|
656
|
+
|
|
657
|
+
## Acronyms
|
|
658
|
+
|
|
659
|
+
| Acronym | Full form | Meaning |
|
|
660
|
+
|---------|-----------|---------|
|
|
661
|
+
| | | |
|
|
662
|
+
|
|
663
|
+
## Domain concepts
|
|
664
|
+
|
|
665
|
+
<!-- Add domain-specific concepts here -->
|
|
666
|
+
|
|
667
|
+
---
|
|
668
|
+
|
|
669
|
+
*Keep this document updated as new terminology is introduced.*
|
|
670
|
+
`}],n=new Date().toISOString().split("T")[0],o=[...s,...r,...i,{id:"prd",name:"PRD",description:"Product requirements document",defaultPath:"docs/prd.md",category:"technical",content:`# Product Requirements — {{PROJECT_NAME}}
|
|
671
|
+
|
|
672
|
+
**Status:** Draft
|
|
673
|
+
**Last updated:** {{DATE}}
|
|
674
|
+
**Author:**
|
|
675
|
+
**Stakeholders:**
|
|
676
|
+
|
|
677
|
+
## Problem statement
|
|
678
|
+
{{DESCRIPTION}}
|
|
679
|
+
|
|
680
|
+
## Goals
|
|
681
|
+
-
|
|
493
682
|
-
|
|
494
683
|
|
|
495
|
-
##
|
|
684
|
+
## Non-goals
|
|
685
|
+
-
|
|
686
|
+
-
|
|
496
687
|
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
688
|
+
## User stories
|
|
689
|
+
| As a... | I want to... | So that... |
|
|
690
|
+
|---------|--------------|------------|
|
|
691
|
+
| user | | |
|
|
692
|
+
|
|
693
|
+
## Requirements
|
|
694
|
+
|
|
695
|
+
### Functional
|
|
696
|
+
{{KEY_FEATURES}}
|
|
697
|
+
|
|
698
|
+
### Non-functional
|
|
699
|
+
- Performance:
|
|
700
|
+
- Security:
|
|
701
|
+
- Reliability:
|
|
702
|
+
- Scalability:
|
|
703
|
+
|
|
704
|
+
## Success metrics
|
|
705
|
+
| Metric | Current | Target |
|
|
706
|
+
|--------|---------|--------|
|
|
707
|
+
| | | |
|
|
708
|
+
|
|
709
|
+
## Timeline
|
|
710
|
+
| Milestone | Target date |
|
|
711
|
+
|-----------|-------------|
|
|
712
|
+
| | |
|
|
713
|
+
|
|
714
|
+
## Open questions
|
|
715
|
+
-
|
|
716
|
+
`},{id:"architecture-overview",name:"Architecture Overview",description:"System architecture doc",defaultPath:"docs/architecture/overview.md",category:"technical",content:`# Architecture Overview — {{PROJECT_NAME}}
|
|
717
|
+
|
|
718
|
+
**Last updated:** {{DATE}}
|
|
719
|
+
|
|
720
|
+
## Summary
|
|
721
|
+
{{DESCRIPTION}}
|
|
722
|
+
|
|
723
|
+
## Tech stack
|
|
724
|
+
{{TECH_STACK}}
|
|
725
|
+
|
|
726
|
+
## System diagram
|
|
727
|
+
|
|
728
|
+
### Context (C4 Level 1)
|
|
729
|
+
|
|
730
|
+
\`\`\`mermaid
|
|
731
|
+
graph TB
|
|
732
|
+
User["User"] --> System["{{PROJECT_NAME}}"]
|
|
733
|
+
System --> ExternalAPI["External APIs"]
|
|
734
|
+
System --> DB["Database"]
|
|
500
735
|
\`\`\`
|
|
501
736
|
|
|
502
|
-
###
|
|
503
|
-
|
|
504
|
-
|
|
737
|
+
### Container (C4 Level 2)
|
|
738
|
+
|
|
739
|
+
\`\`\`mermaid
|
|
740
|
+
graph TB
|
|
741
|
+
Client["Web Client<br/>(Browser)"] --> API["API Server<br/>(Node.js)"]
|
|
742
|
+
API --> DB["Database<br/>(PostgreSQL)"]
|
|
743
|
+
API --> Cache["Cache<br/>(Redis)"]
|
|
744
|
+
API --> Queue["Job Queue"]
|
|
505
745
|
\`\`\`
|
|
506
746
|
|
|
507
|
-
##
|
|
747
|
+
## Components
|
|
508
748
|
|
|
509
|
-
|
|
|
510
|
-
|
|
511
|
-
|
|
|
749
|
+
| Component | Responsibility | Tech |
|
|
750
|
+
|-----------|---------------|------|
|
|
751
|
+
| | | |
|
|
512
752
|
|
|
513
|
-
##
|
|
514
|
-
- Architecture overview: \`docs/architecture/overview.md\`
|
|
515
|
-
- API reference: \`docs/api-reference.md\`
|
|
516
|
-
- Runbook: \`docs/runbook.md\`
|
|
517
|
-
`},{id:"contributing",name:"CONTRIBUTING.md",description:"Contribution guidelines",defaultPath:"CONTRIBUTING.md",content:`# Contributing to {{PROJECT_NAME}}
|
|
753
|
+
## Data flow
|
|
518
754
|
|
|
519
|
-
|
|
755
|
+
1.
|
|
756
|
+
2.
|
|
757
|
+
3.
|
|
520
758
|
|
|
521
|
-
##
|
|
759
|
+
## Key decisions
|
|
522
760
|
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
4. Make your changes
|
|
527
|
-
5. Submit a pull request
|
|
761
|
+
| Decision | Chosen | Alternative | Rationale |
|
|
762
|
+
|----------|--------|-------------|-----------|
|
|
763
|
+
| | | | |
|
|
528
764
|
|
|
529
|
-
##
|
|
765
|
+
## ADR log
|
|
530
766
|
|
|
531
|
-
|
|
|
532
|
-
|
|
533
|
-
|
|
|
534
|
-
| Fix | \`fix/<description>\` | \`fix/login-crash\` |
|
|
535
|
-
| Chore | \`chore/<description>\` | \`chore/update-deps\` |
|
|
536
|
-
| Docs | \`docs/<description>\` | \`docs/api-guide\` |
|
|
767
|
+
| ADR | Title | Status | Date |
|
|
768
|
+
|-----|-------|--------|------|
|
|
769
|
+
| 001 | | Accepted | {{DATE}} |
|
|
537
770
|
|
|
538
|
-
##
|
|
771
|
+
## Non-goals
|
|
772
|
+
|
|
773
|
+
- <!-- What this system explicitly does NOT do -->
|
|
774
|
+
|
|
775
|
+
## Security considerations
|
|
776
|
+
- Authentication:
|
|
777
|
+
- Authorization:
|
|
778
|
+
- Data validation:
|
|
779
|
+
- Secrets management:
|
|
780
|
+
|
|
781
|
+
## Scalability notes
|
|
782
|
+
-
|
|
783
|
+
`},{id:"api-reference",name:"API Reference",description:"API endpoints reference",defaultPath:"docs/api-reference.md",category:"technical",content:`# API Reference — {{PROJECT_NAME}}
|
|
784
|
+
|
|
785
|
+
**Last updated:** {{DATE}}
|
|
539
786
|
|
|
540
|
-
|
|
787
|
+
## Base URL
|
|
541
788
|
|
|
542
789
|
\`\`\`
|
|
543
|
-
|
|
544
|
-
fix: resolve login redirect issue
|
|
545
|
-
docs: update API reference
|
|
546
|
-
chore: upgrade dependencies
|
|
790
|
+
https://api.example.com/v1
|
|
547
791
|
\`\`\`
|
|
548
792
|
|
|
549
|
-
##
|
|
793
|
+
## Versioning
|
|
550
794
|
|
|
551
|
-
|
|
552
|
-
2. Ensure all CI checks pass
|
|
553
|
-
3. Request review from at least one maintainer
|
|
554
|
-
4. Address all review comments
|
|
555
|
-
5. Squash commits before merge
|
|
795
|
+
This API uses URL-based versioning (\`/v1/\`, \`/v2/\`, etc.).
|
|
556
796
|
|
|
557
|
-
|
|
797
|
+
- The current stable version is \`v1\`.
|
|
798
|
+
- Deprecated versions are supported for 12 months after a new version is released.
|
|
799
|
+
- Breaking changes always increment the major version.
|
|
558
800
|
|
|
559
|
-
|
|
560
|
-
- [ ] Tests added/updated
|
|
561
|
-
- [ ] Documentation updated if needed
|
|
562
|
-
- [ ] No secrets or credentials in code
|
|
563
|
-
- [ ] Breaking changes documented
|
|
801
|
+
## Authentication
|
|
564
802
|
|
|
565
|
-
|
|
566
|
-
{{CONVENTIONS}}
|
|
803
|
+
All requests require a bearer token in the Authorization header:
|
|
567
804
|
|
|
568
|
-
|
|
805
|
+
\`\`\`
|
|
806
|
+
Authorization: Bearer <token>
|
|
807
|
+
\`\`\`
|
|
569
808
|
|
|
570
|
-
|
|
571
|
-
- Description of the bug
|
|
572
|
-
- Steps to reproduce
|
|
573
|
-
- Expected vs actual behavior
|
|
574
|
-
- Environment details
|
|
575
|
-
`},{id:"security",name:"SECURITY.md",description:"Security policy and vulnerability reporting",defaultPath:"SECURITY.md",content:`# Security Policy — {{PROJECT_NAME}}
|
|
809
|
+
### Token refresh
|
|
576
810
|
|
|
577
|
-
|
|
811
|
+
Tokens expire after 1 hour. Refresh using:
|
|
578
812
|
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
| < 1.0 | ❌ |
|
|
813
|
+
\`\`\`
|
|
814
|
+
POST /auth/refresh
|
|
815
|
+
Content-Type: application/json
|
|
583
816
|
|
|
584
|
-
|
|
817
|
+
{"refreshToken": "<refresh_token>"}
|
|
818
|
+
\`\`\`
|
|
585
819
|
|
|
586
|
-
**
|
|
820
|
+
**Response:**
|
|
821
|
+
\`\`\`json
|
|
822
|
+
{"accessToken": "...", "refreshToken": "...", "expiresIn": 3600}
|
|
823
|
+
\`\`\`
|
|
587
824
|
|
|
588
|
-
|
|
825
|
+
## Rate limiting
|
|
589
826
|
|
|
590
|
-
|
|
591
|
-
-
|
|
592
|
-
- Steps to reproduce
|
|
593
|
-
- Potential impact
|
|
594
|
-
- Any suggested mitigations
|
|
827
|
+
- **Limit:** 1000 requests/hour per API key
|
|
828
|
+
- **Headers:** \`X-RateLimit-Limit\`, \`X-RateLimit-Remaining\`, \`X-RateLimit-Reset\`
|
|
595
829
|
|
|
596
|
-
|
|
597
|
-
1. Confirm receipt of your report
|
|
598
|
-
2. Investigate and assess the issue
|
|
599
|
-
3. Release a fix or mitigation
|
|
600
|
-
4. Credit you in the release notes (unless you prefer anonymity)
|
|
830
|
+
## Pagination
|
|
601
831
|
|
|
602
|
-
|
|
832
|
+
List endpoints support cursor-based pagination:
|
|
603
833
|
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
- Validate and sanitize all user input
|
|
608
|
-
- Follow the principle of least privilege
|
|
609
|
-
- Keep dependencies up to date
|
|
610
|
-
`},{id:"pr-template",name:"PR Template",description:"Pull request template",defaultPath:".github/pull_request_template.md",content:`## Description
|
|
834
|
+
\`\`\`
|
|
835
|
+
GET /resources?cursor=<cursor>&limit=20
|
|
836
|
+
\`\`\`
|
|
611
837
|
|
|
612
|
-
|
|
838
|
+
## Error format
|
|
613
839
|
|
|
614
|
-
|
|
840
|
+
All errors follow a standard envelope:
|
|
615
841
|
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
-
|
|
620
|
-
|
|
621
|
-
|
|
842
|
+
\`\`\`json
|
|
843
|
+
{
|
|
844
|
+
"code": "VALIDATION_ERROR",
|
|
845
|
+
"message": "Human-readable description",
|
|
846
|
+
"details": [{"field": "email", "issue": "invalid format"}]
|
|
847
|
+
}
|
|
848
|
+
\`\`\`
|
|
622
849
|
|
|
623
|
-
##
|
|
850
|
+
## Error codes
|
|
624
851
|
|
|
625
|
-
|
|
852
|
+
| Code | Meaning |
|
|
853
|
+
|------|---------|
|
|
854
|
+
| 400 | Bad request — invalid parameters |
|
|
855
|
+
| 401 | Unauthorized — missing or invalid token |
|
|
856
|
+
| 403 | Forbidden — insufficient permissions |
|
|
857
|
+
| 404 | Not found |
|
|
858
|
+
| 422 | Unprocessable entity — validation error |
|
|
859
|
+
| 429 | Too many requests |
|
|
860
|
+
| 500 | Internal server error |
|
|
626
861
|
|
|
627
|
-
##
|
|
862
|
+
## Webhooks
|
|
628
863
|
|
|
629
|
-
|
|
630
|
-
2.
|
|
631
|
-
3.
|
|
864
|
+
### Signature verification
|
|
632
865
|
|
|
633
|
-
|
|
866
|
+
All webhook payloads are signed with HMAC-SHA256. Verify the signature:
|
|
634
867
|
|
|
635
|
-
|
|
868
|
+
\`\`\`
|
|
869
|
+
X-Webhook-Signature: sha256=<hmac_hex>
|
|
870
|
+
\`\`\`
|
|
636
871
|
|
|
637
|
-
|
|
872
|
+
\`\`\`typescript
|
|
873
|
+
import crypto from 'crypto'
|
|
874
|
+
|
|
875
|
+
function verifyWebhook(payload: string, signature: string, secret: string): boolean {
|
|
876
|
+
const expected = crypto
|
|
877
|
+
.createHmac('sha256', secret)
|
|
878
|
+
.update(payload)
|
|
879
|
+
.digest('hex')
|
|
880
|
+
return crypto.timingSafeEqual(
|
|
881
|
+
Buffer.from(\`sha256=\${expected}\`),
|
|
882
|
+
Buffer.from(signature)
|
|
883
|
+
)
|
|
884
|
+
}
|
|
885
|
+
\`\`\`
|
|
638
886
|
|
|
639
|
-
|
|
640
|
-
- [ ] I have performed a self-review of my changes
|
|
641
|
-
- [ ] I have added tests that prove my fix or feature works
|
|
642
|
-
- [ ] New and existing unit tests pass locally
|
|
643
|
-
- [ ] I have updated documentation if needed
|
|
644
|
-
- [ ] No secrets or credentials are included
|
|
645
|
-
`},{id:"bug-report",name:"Bug Report Template",description:"GitHub issue template for bugs",defaultPath:".github/ISSUE_TEMPLATE/bug_report.md",content:`---
|
|
646
|
-
name: Bug report
|
|
647
|
-
about: Create a report to help us improve
|
|
648
|
-
labels: bug
|
|
649
|
-
---
|
|
887
|
+
## Endpoints
|
|
650
888
|
|
|
651
|
-
|
|
889
|
+
### GET /resource
|
|
652
890
|
|
|
653
|
-
|
|
891
|
+
**Description:** List resources
|
|
654
892
|
|
|
655
|
-
|
|
893
|
+
**Query parameters:**
|
|
894
|
+
- \`limit\` (integer, default 20) — items per page
|
|
895
|
+
- \`cursor\` (string) — pagination cursor
|
|
656
896
|
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
897
|
+
**Response:**
|
|
898
|
+
\`\`\`json
|
|
899
|
+
{
|
|
900
|
+
"data": [],
|
|
901
|
+
"cursor": null,
|
|
902
|
+
"total": 0
|
|
903
|
+
}
|
|
904
|
+
\`\`\`
|
|
660
905
|
|
|
661
|
-
|
|
906
|
+
### POST /resource
|
|
662
907
|
|
|
663
|
-
|
|
908
|
+
**Description:** Create a resource
|
|
664
909
|
|
|
665
|
-
|
|
910
|
+
**Request body:**
|
|
911
|
+
\`\`\`json
|
|
912
|
+
{}
|
|
913
|
+
\`\`\`
|
|
666
914
|
|
|
667
|
-
|
|
915
|
+
**Response:**
|
|
916
|
+
\`\`\`json
|
|
917
|
+
{}
|
|
918
|
+
\`\`\`
|
|
919
|
+
`},{id:"runbook",name:"Runbook",description:"Operational runbook",defaultPath:"docs/runbook.md",category:"technical",content:`# Runbook — {{PROJECT_NAME}}
|
|
668
920
|
|
|
669
|
-
|
|
921
|
+
**Last updated:** {{DATE}}
|
|
670
922
|
|
|
671
|
-
|
|
923
|
+
## Overview
|
|
924
|
+
{{DESCRIPTION}}
|
|
672
925
|
|
|
673
|
-
##
|
|
926
|
+
## SLOs
|
|
674
927
|
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
928
|
+
| Metric | Target |
|
|
929
|
+
|--------|--------|
|
|
930
|
+
| Availability | 99.9% |
|
|
931
|
+
| P95 latency | < 500ms |
|
|
932
|
+
| Error rate | < 0.1% |
|
|
679
933
|
|
|
680
|
-
##
|
|
934
|
+
## Environments
|
|
681
935
|
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
---
|
|
936
|
+
| Env | URL | Purpose |
|
|
937
|
+
|-----|-----|---------|
|
|
938
|
+
| Production | | Live traffic |
|
|
939
|
+
| Staging | | Pre-release testing |
|
|
940
|
+
| Development | | Local dev |
|
|
688
941
|
|
|
689
|
-
##
|
|
942
|
+
## Alerting
|
|
690
943
|
|
|
691
|
-
|
|
692
|
-
|
|
944
|
+
| Alert | Threshold | Severity | Action |
|
|
945
|
+
|-------|-----------|----------|--------|
|
|
946
|
+
| | | | |
|
|
693
947
|
|
|
694
|
-
##
|
|
948
|
+
## On-call contacts
|
|
695
949
|
|
|
696
|
-
|
|
950
|
+
| Role | Name | Contact |
|
|
951
|
+
|------|------|---------|
|
|
952
|
+
| Primary | | |
|
|
953
|
+
| Secondary | | |
|
|
697
954
|
|
|
698
|
-
##
|
|
955
|
+
## Escalation matrix
|
|
699
956
|
|
|
700
|
-
|
|
957
|
+
| Time since incident | Contact | Method |
|
|
958
|
+
|--------------------|---------|--------|
|
|
959
|
+
| 0–15 min | On-call engineer | PagerDuty / phone |
|
|
960
|
+
| 15–30 min | Team lead | Slack + phone |
|
|
961
|
+
| 30+ min | Engineering manager | Phone + email |
|
|
701
962
|
|
|
702
|
-
##
|
|
963
|
+
## Procedures
|
|
703
964
|
|
|
704
|
-
|
|
965
|
+
### Deploy
|
|
705
966
|
|
|
706
|
-
|
|
967
|
+
1.
|
|
968
|
+
2.
|
|
969
|
+
3.
|
|
707
970
|
|
|
708
|
-
|
|
709
|
-
`},{id:"changelog",name:"CHANGELOG.md",description:"Keep a Changelog format",defaultPath:"CHANGELOG.md",content:`# Changelog — {{PROJECT_NAME}}
|
|
971
|
+
### Rollback
|
|
710
972
|
|
|
711
|
-
|
|
973
|
+
**When to rollback:**
|
|
712
974
|
|
|
713
|
-
|
|
714
|
-
|
|
975
|
+
| Signal | Action |
|
|
976
|
+
|--------|--------|
|
|
977
|
+
| Error rate > 1% after deploy | Immediate rollback |
|
|
978
|
+
| P95 latency doubled | Rollback if no fix in 15 min |
|
|
979
|
+
| Health check failing | Immediate rollback |
|
|
980
|
+
| Critical bug reported | Rollback within 30 min |
|
|
715
981
|
|
|
716
|
-
|
|
982
|
+
**Rollback steps:**
|
|
717
983
|
|
|
718
|
-
|
|
719
|
-
|
|
984
|
+
\`\`\`bash
|
|
985
|
+
# 1. Identify last stable release
|
|
986
|
+
git log --oneline --tags --simplify-by-decoration | head -5
|
|
720
987
|
|
|
721
|
-
|
|
722
|
-
-
|
|
988
|
+
# 2. Deploy previous version
|
|
989
|
+
git checkout <previous-tag>
|
|
990
|
+
npm run build && npm run deploy
|
|
723
991
|
|
|
724
|
-
|
|
725
|
-
-
|
|
992
|
+
# 3. Verify rollback
|
|
993
|
+
curl -f https://your-app.com/health
|
|
994
|
+
\`\`\`
|
|
726
995
|
|
|
727
|
-
###
|
|
728
|
-
-
|
|
996
|
+
### Troubleshooting
|
|
729
997
|
|
|
730
|
-
|
|
998
|
+
#### High error rate
|
|
999
|
+
\`\`\`bash
|
|
1000
|
+
# Check recent application logs
|
|
1001
|
+
tail -f /var/log/app/error.log
|
|
731
1002
|
|
|
732
|
-
|
|
733
|
-
-
|
|
734
|
-
`},{id:"deployment",name:"DEPLOYMENT.md",description:"Deployment guide and procedures",defaultPath:"DEPLOYMENT.md",content:`# Deployment Guide — {{PROJECT_NAME}}
|
|
1003
|
+
# Check error counts by endpoint
|
|
1004
|
+
grep "ERROR" /var/log/app/app.log | awk '{print $5}' | sort | uniq -c | sort -rn | head -10
|
|
735
1005
|
|
|
736
|
-
|
|
1006
|
+
# Review recent deploys
|
|
1007
|
+
git log --oneline -10
|
|
1008
|
+
\`\`\`
|
|
737
1009
|
|
|
738
|
-
|
|
1010
|
+
1. Check application logs for exception traces
|
|
1011
|
+
2. Check downstream dependencies (database, cache, external APIs)
|
|
1012
|
+
3. Review recent deploys — consider rollback if deploy-correlated
|
|
739
1013
|
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
| Preview | | PRs | Yes |
|
|
1014
|
+
#### High latency
|
|
1015
|
+
\`\`\`bash
|
|
1016
|
+
# Check database slow query log
|
|
1017
|
+
psql $DATABASE_URL -c "SELECT query, calls, mean_exec_time FROM pg_stat_statements ORDER BY mean_exec_time DESC LIMIT 10;"
|
|
745
1018
|
|
|
746
|
-
|
|
1019
|
+
# Check cache hit rate
|
|
1020
|
+
redis-cli info stats | grep hit_rate
|
|
747
1021
|
|
|
748
|
-
|
|
749
|
-
-
|
|
750
|
-
|
|
1022
|
+
# Check CPU/memory
|
|
1023
|
+
top -b -n 1 | head -20
|
|
1024
|
+
\`\`\`
|
|
751
1025
|
|
|
752
|
-
|
|
1026
|
+
1. Check database query times (slow query log)
|
|
1027
|
+
2. Check cache hit rates
|
|
1028
|
+
3. Review resource utilization (CPU, memory, connections)
|
|
753
1029
|
|
|
1030
|
+
#### Service won't start
|
|
754
1031
|
\`\`\`bash
|
|
755
|
-
#
|
|
756
|
-
|
|
1032
|
+
# Check environment variables
|
|
1033
|
+
env | grep -E "DATABASE|REDIS|PORT"
|
|
757
1034
|
|
|
758
|
-
#
|
|
759
|
-
|
|
1035
|
+
# Test database connectivity
|
|
1036
|
+
psql $DATABASE_URL -c "SELECT 1"
|
|
760
1037
|
|
|
761
|
-
#
|
|
762
|
-
|
|
1038
|
+
# Check port availability
|
|
1039
|
+
lsof -i :3000
|
|
1040
|
+
\`\`\`
|
|
763
1041
|
|
|
764
|
-
|
|
765
|
-
|
|
1042
|
+
#### Database connection issues
|
|
1043
|
+
\`\`\`bash
|
|
1044
|
+
# Check connection pool status
|
|
1045
|
+
psql $DATABASE_URL -c "SELECT count(*), state FROM pg_stat_activity GROUP BY state;"
|
|
1046
|
+
|
|
1047
|
+
# Check max connections
|
|
1048
|
+
psql $DATABASE_URL -c "SHOW max_connections;"
|
|
766
1049
|
\`\`\`
|
|
767
1050
|
|
|
768
|
-
|
|
1051
|
+
#### Memory leak suspected
|
|
1052
|
+
\`\`\`bash
|
|
1053
|
+
# Monitor memory over time
|
|
1054
|
+
watch -n 5 'ps aux --sort=-%mem | head -5'
|
|
1055
|
+
|
|
1056
|
+
# Capture heap snapshot (Node.js)
|
|
1057
|
+
kill -USR2 <pid>
|
|
1058
|
+
\`\`\`
|
|
1059
|
+
`},{id:"adr",name:"Architecture Decision",description:"Architecture Decision Record",defaultPath:"docs/architecture/decisions/ADR-001.md",category:"technical",content:`# ADR-001: Title
|
|
1060
|
+
|
|
1061
|
+
**Status:** Proposed
|
|
1062
|
+
**Date:** {{DATE}}
|
|
1063
|
+
**Deciders:**
|
|
1064
|
+
|
|
1065
|
+
## Context
|
|
1066
|
+
What is the issue that we're seeing that is motivating this decision or change?
|
|
769
1067
|
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
| | Yes | |
|
|
1068
|
+
## Decision
|
|
1069
|
+
What is the change that we're proposing and/or doing?
|
|
773
1070
|
|
|
774
|
-
##
|
|
1071
|
+
## Rationale
|
|
1072
|
+
Why did we choose this option?
|
|
775
1073
|
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
4. Verify the rollback with smoke tests
|
|
1074
|
+
## Alternatives considered
|
|
1075
|
+
- **Option A:** Description — pros/cons
|
|
1076
|
+
- **Option B:** Description — pros/cons
|
|
780
1077
|
|
|
781
|
-
##
|
|
1078
|
+
## Consequences
|
|
782
1079
|
|
|
783
|
-
|
|
784
|
-
-
|
|
785
|
-
- [ ] Auth flow works
|
|
786
|
-
- [ ] Core features functional
|
|
787
|
-
- [ ] No error spikes in monitoring
|
|
1080
|
+
### Positive
|
|
1081
|
+
-
|
|
788
1082
|
|
|
789
|
-
|
|
1083
|
+
### Negative
|
|
1084
|
+
-
|
|
790
1085
|
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
| Release manager | |
|
|
795
|
-
`},{id:"testing",name:"TESTING.md",description:"Testing strategy and guide",defaultPath:"TESTING.md",content:`# Testing Guide — {{PROJECT_NAME}}
|
|
1086
|
+
### Neutral
|
|
1087
|
+
-
|
|
1088
|
+
`},{id:"onboarding",name:"Onboarding Guide",description:"Developer onboarding guide",defaultPath:"docs/onboarding.md",category:"technical",content:`# Developer Onboarding — {{PROJECT_NAME}}
|
|
796
1089
|
|
|
797
1090
|
**Last updated:** {{DATE}}
|
|
798
1091
|
|
|
799
|
-
##
|
|
1092
|
+
## Overview
|
|
1093
|
+
{{DESCRIPTION}}
|
|
800
1094
|
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
| E2E | User flows | Playwright | Key paths |
|
|
1095
|
+
## Prerequisites
|
|
1096
|
+
- [ ] Access to repository ({{REPO_URL}})
|
|
1097
|
+
- [ ] Access to staging environment
|
|
1098
|
+
- [ ] Accounts: (list required accounts/services)
|
|
806
1099
|
|
|
807
|
-
##
|
|
1100
|
+
## Day 1: Get running
|
|
1101
|
+
|
|
1102
|
+
- [ ] Clone the repository and set up local environment
|
|
1103
|
+
- [ ] Run the app locally and verify it works
|
|
1104
|
+
- [ ] Read the architecture overview (\`docs/architecture/overview.md\`)
|
|
1105
|
+
- [ ] Meet your team lead and get a tour of the codebase
|
|
808
1106
|
|
|
809
1107
|
\`\`\`bash
|
|
810
|
-
#
|
|
811
|
-
|
|
1108
|
+
# Clone
|
|
1109
|
+
git clone {{REPO_URL}}
|
|
1110
|
+
cd {{PROJECT_NAME}}
|
|
812
1111
|
|
|
813
|
-
#
|
|
814
|
-
npm
|
|
1112
|
+
# Install dependencies
|
|
1113
|
+
npm install
|
|
815
1114
|
|
|
816
|
-
#
|
|
817
|
-
|
|
1115
|
+
# Copy environment variables
|
|
1116
|
+
cp .env.example .env.local
|
|
1117
|
+
# Edit .env.local with real values (ask your team lead)
|
|
818
1118
|
|
|
819
|
-
#
|
|
820
|
-
npm run
|
|
1119
|
+
# Start development server
|
|
1120
|
+
npm run dev
|
|
821
1121
|
\`\`\`
|
|
822
1122
|
|
|
823
|
-
##
|
|
1123
|
+
## Week 1: Get productive
|
|
824
1124
|
|
|
825
|
-
|
|
1125
|
+
- [ ] Complete the environment setup checklist below
|
|
1126
|
+
- [ ] Read \`CONTRIBUTING.md\` and understand the PR process
|
|
1127
|
+
- [ ] Submit your first PR (even a small doc fix counts)
|
|
1128
|
+
- [ ] Attend team standup and sprint planning
|
|
1129
|
+
- [ ] Review 2–3 recent merged PRs to understand code patterns
|
|
1130
|
+
- [ ] Shadow a code review
|
|
826
1131
|
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
1132
|
+
## Month 1: Get comfortable
|
|
1133
|
+
|
|
1134
|
+
- [ ] Deliver your first feature end-to-end
|
|
1135
|
+
- [ ] Lead a code review
|
|
1136
|
+
- [ ] Identify one piece of tech debt and create a ticket
|
|
1137
|
+
- [ ] Update this onboarding doc with anything that was unclear
|
|
1138
|
+
|
|
1139
|
+
## Environment setup
|
|
1140
|
+
|
|
1141
|
+
\`\`\`bash
|
|
1142
|
+
# Install dependencies
|
|
1143
|
+
npm install
|
|
1144
|
+
|
|
1145
|
+
# Copy environment variables
|
|
1146
|
+
cp .env.example .env.local
|
|
1147
|
+
|
|
1148
|
+
# Start development server
|
|
1149
|
+
npm run dev
|
|
833
1150
|
\`\`\`
|
|
834
1151
|
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
- Reset state between tests
|
|
838
|
-
- Test happy path and error cases
|
|
1152
|
+
## Tech stack
|
|
1153
|
+
{{TECH_STACK}}
|
|
839
1154
|
|
|
840
|
-
|
|
841
|
-
-
|
|
842
|
-
-
|
|
843
|
-
-
|
|
1155
|
+
## IDE setup
|
|
1156
|
+
- Recommended: VS Code or Cursor
|
|
1157
|
+
- Install recommended extensions (see \`.vscode/extensions.json\`)
|
|
1158
|
+
- Enable format on save
|
|
844
1159
|
|
|
845
|
-
##
|
|
1160
|
+
## Project structure
|
|
846
1161
|
|
|
847
1162
|
\`\`\`
|
|
848
|
-
|
|
849
|
-
__tests__/ # Unit tests
|
|
850
|
-
__integration__/ # Integration tests
|
|
851
|
-
e2e/ # E2E tests
|
|
1163
|
+
(describe key directories here)
|
|
852
1164
|
\`\`\`
|
|
853
1165
|
|
|
854
|
-
##
|
|
855
|
-
|
|
856
|
-
Tests run automatically on every PR. PRs cannot merge with failing tests.
|
|
857
|
-
`},{id:"glossary",name:"Glossary",description:"Project terminology reference",defaultPath:"docs/glossary.md",content:`# Glossary — {{PROJECT_NAME}}
|
|
1166
|
+
## Key concepts
|
|
1167
|
+
-
|
|
858
1168
|
|
|
859
|
-
|
|
1169
|
+
## Common tasks
|
|
860
1170
|
|
|
861
|
-
|
|
1171
|
+
### Running tests
|
|
1172
|
+
\`\`\`bash
|
|
1173
|
+
npm test
|
|
1174
|
+
\`\`\`
|
|
862
1175
|
|
|
863
|
-
|
|
1176
|
+
### Building for production
|
|
1177
|
+
\`\`\`bash
|
|
1178
|
+
npm run build
|
|
1179
|
+
\`\`\`
|
|
864
1180
|
|
|
865
|
-
|
|
866
|
-
|------|------------|
|
|
867
|
-
| | |
|
|
1181
|
+
## Common pitfalls
|
|
868
1182
|
|
|
869
|
-
|
|
1183
|
+
1. **Forgetting to copy .env.local** — the app won't start without required env vars. Copy from \`.env.example\` and fill in real values.
|
|
1184
|
+
2. **Running \`npm install\` instead of the project's package manager** — check \`package.json\` for the \`packageManager\` field or look for a lock file (\`pnpm-lock.yaml\`, \`yarn.lock\`).
|
|
1185
|
+
3. **Committing to \`main\` directly** — always branch and open a PR. Direct pushes to \`main\` are blocked.
|
|
1186
|
+
4. **Skipping tests** — CI will catch you, but it's faster to run \`npm test\` locally before pushing.
|
|
1187
|
+
5. **Not reading existing patterns** — before adding a new abstraction, search the codebase for how similar problems are solved.
|
|
870
1188
|
|
|
871
|
-
|
|
872
|
-
|---------|-----------|---------|
|
|
873
|
-
| | | |
|
|
1189
|
+
## Your first PR
|
|
874
1190
|
|
|
875
|
-
|
|
1191
|
+
1. Pick a small, well-defined issue labelled \`good first issue\`
|
|
1192
|
+
2. Create a branch: \`git checkout -b feat/your-name-first-pr\`
|
|
1193
|
+
3. Make the change and add a test
|
|
1194
|
+
4. Open a PR with the PR template filled out
|
|
1195
|
+
5. Ask for a review in the team Slack channel
|
|
876
1196
|
|
|
877
|
-
|
|
1197
|
+
## Key contacts
|
|
878
1198
|
|
|
879
|
-
|
|
1199
|
+
| Role | Name | Contact |
|
|
1200
|
+
|------|------|---------|
|
|
1201
|
+
| | | |
|
|
880
1202
|
|
|
881
|
-
|
|
882
|
-
|
|
1203
|
+
## Resources
|
|
1204
|
+
- Architecture overview: \`docs/architecture/overview.md\`
|
|
1205
|
+
- API reference: \`docs/api-reference.md\`
|
|
1206
|
+
- Runbook: \`docs/runbook.md\`
|
|
1207
|
+
- Contributing guide: \`CONTRIBUTING.md\`
|
|
1208
|
+
`},{id:"database",name:"Database Docs",description:"Database schema and design reference",defaultPath:"docs/DATABASE.md",category:"technical",content:`# Database Documentation — {{PROJECT_NAME}}
|
|
883
1209
|
|
|
884
1210
|
**Last updated:** {{DATE}}
|
|
885
1211
|
|
|
@@ -941,7 +1267,7 @@ psql $DATABASE_URL < backup.sql
|
|
|
941
1267
|
## Performance notes
|
|
942
1268
|
|
|
943
1269
|
-
|
|
944
|
-
`},{id:"openapi",name:"OpenAPI Spec",description:"OpenAPI 3.0 API specification scaffold",defaultPath:"docs/api-spec.yaml",content:`openapi: 3.0.3
|
|
1270
|
+
`},{id:"openapi",name:"OpenAPI Spec",description:"OpenAPI 3.0 API specification scaffold",defaultPath:"docs/api-spec.yaml",category:"technical",content:`openapi: 3.0.3
|
|
945
1271
|
info:
|
|
946
1272
|
title: {{PROJECT_NAME}} API
|
|
947
1273
|
description: |
|
|
@@ -1047,4 +1373,735 @@ components:
|
|
|
1047
1373
|
application/json:
|
|
1048
1374
|
schema:
|
|
1049
1375
|
$ref: '#/components/schemas/Error'
|
|
1050
|
-
`}];function f({open:e,onOpenChange:t,rootParam:a,onDocCreated:m}){let[f,h]=(0,r.useState)(1),[b,g]=(0,r.useState)(null),[x,v]=(0,r.useState)(""),[y,N]=(0,r.useState)(""),[w,j]=(0,r.useState)(!1);async function k(){if(b&&x.trim()){N(""),j(!0);try{let e=await fetch(`/api/docs${a}`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({path:x.trim(),content:b.content})});if(409===e.status){N("File already exists"),j(!1);return}if(!e.ok){let t=await e.json();N(t.error||"Failed to create file"),j(!1);return}t(!1),m(x.trim())}catch{N("Network error"),j(!1)}}}return s.jsx(d.Vq,{open:e,onOpenChange:t,children:(0,s.jsxs)(d.cZ,{className:"max-w-2xl bg-surface border-border",children:[s.jsx(d.fK,{children:s.jsx(d.$N,{className:"text-txt text-sm font-semibold",children:1===f?"Choose a template":"Confirm file path"})}),1===f&&s.jsx(u.x,{className:"max-h-[420px]",children:s.jsx("div",{className:"grid grid-cols-3 gap-2 p-1",children:p.map(e=>(0,s.jsxs)("button",{onClick:()=>{g(e),v(e.defaultPath),N(""),h(2)},className:(0,o.cn)("flex flex-col items-start gap-1.5 p-3 rounded-lg border border-border text-left","bg-surface2 hover:bg-surface2/80 hover:border-accent/50 transition-colors"),children:[(0,s.jsxs)("div",{className:"flex items-center gap-2",children:[s.jsx(n.Z,{className:"h-3.5 w-3.5 text-accent shrink-0"}),s.jsx("span",{className:"text-xs font-medium text-txt",children:e.name})]}),s.jsx("p",{className:"text-[11px] text-muted leading-relaxed",children:e.description}),s.jsx("p",{className:"text-[10px] text-muted/60 font-mono truncate w-full",children:e.defaultPath})]},e.id))})}),2===f&&b&&(0,s.jsxs)("div",{className:"space-y-4",children:[(0,s.jsxs)("div",{className:"flex items-start gap-3 p-3 rounded-lg bg-surface2 border border-border",children:[s.jsx(n.Z,{className:"h-4 w-4 text-accent shrink-0 mt-0.5"}),(0,s.jsxs)("div",{children:[s.jsx("p",{className:"text-xs font-medium text-txt",children:b.name}),s.jsx("p",{className:"text-[11px] text-muted mt-0.5",children:b.description})]})]}),(0,s.jsxs)("div",{className:"space-y-1.5",children:[s.jsx("label",{className:"text-[11px] font-medium text-muted uppercase tracking-wider",children:"File path"}),s.jsx(c.I,{autoFocus:!0,value:x,onChange:e=>{v(e.target.value),N("")},onKeyDown:e=>{"Enter"===e.key&&k()},placeholder:"docs/my-document.md",className:"h-8 text-xs bg-surface2 border-border font-mono"}),y&&s.jsx("p",{className:"text-[11px] text-red-400",children:y})]}),(0,s.jsxs)("div",{className:"flex items-center justify-between pt-1",children:[(0,s.jsxs)(l.z,{variant:"ghost",size:"sm",onClick:()=>h(1),className:"h-7 text-xs text-muted hover:text-txt gap-1.5",children:[s.jsx(i.Z,{className:"h-3 w-3"}),"Back"]}),s.jsx(l.z,{size:"sm",onClick:k,disabled:w||!x.trim(),className:"h-7 text-xs bg-accent hover:bg-accent/90 text-white",children:w?"Creating…":"Create"})]})]})]})})}},5819:(e,t,a)=>{"use strict";a.d(t,{C:()=>o});var s=a(7486);a(618);var r=a(4039),n=a(5098);let i=(0,r.j)("inline-flex items-center rounded-full border border-slate-200 px-2.5 py-0.5 text-xs font-semibold transition-colors focus:outline-none focus:ring-2 focus:ring-slate-950 focus:ring-offset-2 dark:border-slate-800 dark:focus:ring-slate-300",{variants:{variant:{default:"border-transparent bg-slate-900 text-slate-50 hover:bg-slate-900/80 dark:bg-slate-50 dark:text-slate-900 dark:hover:bg-slate-50/80",secondary:"border-transparent bg-slate-100 text-slate-900 hover:bg-slate-100/80 dark:bg-slate-800 dark:text-slate-50 dark:hover:bg-slate-800/80",destructive:"border-transparent bg-red-500 text-slate-50 hover:bg-red-500/80 dark:bg-red-900 dark:text-slate-50 dark:hover:bg-red-900/80",outline:"text-slate-950 dark:text-slate-50"}},defaultVariants:{variant:"default"}});function o({className:e,variant:t,...a}){return s.jsx("div",{className:(0,n.cn)(i({variant:t}),e),...a})}},3068:(e,t,a)=>{"use strict";a.d(t,{z:()=>l});var s=a(7486),r=a(618),n=a(8942),i=a(4039),o=a(5098);let d=(0,i.j)("inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium ring-offset-white transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-slate-950 focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0 dark:ring-offset-slate-950 dark:focus-visible:ring-slate-300",{variants:{variant:{default:"bg-slate-900 text-slate-50 hover:bg-slate-900/90 dark:bg-slate-50 dark:text-slate-900 dark:hover:bg-slate-50/90",destructive:"bg-red-500 text-slate-50 hover:bg-red-500/90 dark:bg-red-900 dark:text-slate-50 dark:hover:bg-red-900/90",outline:"border border-slate-200 bg-white hover:bg-slate-100 hover:text-slate-900 dark:border-slate-800 dark:bg-slate-950 dark:hover:bg-slate-800 dark:hover:text-slate-50",secondary:"bg-slate-100 text-slate-900 hover:bg-slate-100/80 dark:bg-slate-800 dark:text-slate-50 dark:hover:bg-slate-800/80",ghost:"hover:bg-slate-100 hover:text-slate-900 dark:hover:bg-slate-800 dark:hover:text-slate-50",link:"text-slate-900 underline-offset-4 hover:underline dark:text-slate-50"},size:{default:"h-10 px-4 py-2",sm:"h-9 rounded-md px-3",lg:"h-11 rounded-md px-8",icon:"h-10 w-10"}},defaultVariants:{variant:"default",size:"default"}}),l=r.forwardRef(({className:e,variant:t,size:a,asChild:r=!1,...i},l)=>{let c=r?n.g7:"button";return s.jsx(c,{className:(0,o.cn)(d({variant:t,size:a,className:e})),ref:l,...i})});l.displayName="Button"},8650:(e,t,a)=>{"use strict";a.d(t,{$N:()=>p,Vq:()=>d,cZ:()=>u,fK:()=>m});var s=a(7486),r=a(618),n=a(2439),i=a(2153),o=a(5098);let d=n.fC;n.xz;let l=n.h_;n.x8;let c=r.forwardRef(({className:e,...t},a)=>s.jsx(n.aV,{ref:a,className:(0,o.cn)("fixed inset-0 z-50 bg-black/80 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0",e),...t}));c.displayName=n.aV.displayName;let u=r.forwardRef(({className:e,children:t,...a},r)=>(0,s.jsxs)(l,{children:[s.jsx(c,{}),(0,s.jsxs)(n.VY,{ref:r,className:(0,o.cn)("fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border border-slate-200 bg-white p-6 shadow-lg duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] sm:rounded-lg dark:border-slate-800 dark:bg-slate-950",e),...a,children:[t,(0,s.jsxs)(n.x8,{className:"absolute right-4 top-4 rounded-sm opacity-70 ring-offset-white transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-slate-950 focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-slate-100 data-[state=open]:text-slate-500 dark:ring-offset-slate-950 dark:focus:ring-slate-300 dark:data-[state=open]:bg-slate-800 dark:data-[state=open]:text-slate-400",children:[s.jsx(i.Z,{className:"h-4 w-4"}),s.jsx("span",{className:"sr-only",children:"Close"})]})]})]}));u.displayName=n.VY.displayName;let m=({className:e,...t})=>s.jsx("div",{className:(0,o.cn)("flex flex-col space-y-1.5 text-center sm:text-left",e),...t});m.displayName="DialogHeader";let p=r.forwardRef(({className:e,...t},a)=>s.jsx(n.Dx,{ref:a,className:(0,o.cn)("text-lg font-semibold leading-none tracking-tight",e),...t}));p.displayName=n.Dx.displayName,r.forwardRef(({className:e,...t},a)=>s.jsx(n.dk,{ref:a,className:(0,o.cn)("text-sm text-slate-500 dark:text-slate-400",e),...t})).displayName=n.dk.displayName},9228:(e,t,a)=>{"use strict";a.d(t,{$F:()=>u,AW:()=>m,Xi:()=>p,h_:()=>c});var s=a(7486),r=a(618),n=a(79),i=a(8953),o=a(9644),d=a(3399),l=a(5098);let c=n.fC,u=n.xz;n.ZA,n.Uv,n.Tr,n.Ee,r.forwardRef(({className:e,inset:t,children:a,...r},o)=>(0,s.jsxs)(n.fF,{ref:o,className:(0,l.cn)("flex cursor-default select-none items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-none focus:bg-slate-100 data-[state=open]:bg-slate-100 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0 dark:focus:bg-slate-800 dark:data-[state=open]:bg-slate-800",t&&"pl-8",e),...r,children:[a,s.jsx(i.Z,{className:"ml-auto"})]})).displayName=n.fF.displayName,r.forwardRef(({className:e,...t},a)=>s.jsx(n.tu,{ref:a,className:(0,l.cn)("z-50 min-w-[8rem] overflow-hidden rounded-md border border-slate-200 bg-white p-1 text-slate-950 shadow-lg data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 origin-[--radix-dropdown-menu-content-transform-origin] dark:border-slate-800 dark:bg-slate-950 dark:text-slate-50",e),...t})).displayName=n.tu.displayName;let m=r.forwardRef(({className:e,sideOffset:t=4,...a},r)=>s.jsx(n.Uv,{children:s.jsx(n.VY,{ref:r,sideOffset:t,className:(0,l.cn)("z-50 max-h-[var(--radix-dropdown-menu-content-available-height)] min-w-[8rem] overflow-y-auto overflow-x-hidden rounded-md border border-slate-200 bg-white p-1 text-slate-950 shadow-md data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 origin-[--radix-dropdown-menu-content-transform-origin] dark:border-slate-800 dark:bg-slate-950 dark:text-slate-50",e),...a})}));m.displayName=n.VY.displayName;let p=r.forwardRef(({className:e,inset:t,...a},r)=>s.jsx(n.ck,{ref:r,className:(0,l.cn)("relative flex cursor-default select-none items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-none transition-colors focus:bg-slate-100 focus:text-slate-900 data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0 dark:focus:bg-slate-800 dark:focus:text-slate-50",t&&"pl-8",e),...a}));p.displayName=n.ck.displayName,r.forwardRef(({className:e,children:t,checked:a,...r},i)=>(0,s.jsxs)(n.oC,{ref:i,className:(0,l.cn)("relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none transition-colors focus:bg-slate-100 focus:text-slate-900 data-[disabled]:pointer-events-none data-[disabled]:opacity-50 dark:focus:bg-slate-800 dark:focus:text-slate-50",e),checked:a,...r,children:[s.jsx("span",{className:"absolute left-2 flex h-3.5 w-3.5 items-center justify-center",children:s.jsx(n.wU,{children:s.jsx(o.Z,{className:"h-4 w-4"})})}),t]})).displayName=n.oC.displayName,r.forwardRef(({className:e,children:t,...a},r)=>(0,s.jsxs)(n.Rk,{ref:r,className:(0,l.cn)("relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none transition-colors focus:bg-slate-100 focus:text-slate-900 data-[disabled]:pointer-events-none data-[disabled]:opacity-50 dark:focus:bg-slate-800 dark:focus:text-slate-50",e),...a,children:[s.jsx("span",{className:"absolute left-2 flex h-3.5 w-3.5 items-center justify-center",children:s.jsx(n.wU,{children:s.jsx(d.Z,{className:"h-2 w-2 fill-current"})})}),t]})).displayName=n.Rk.displayName,r.forwardRef(({className:e,inset:t,...a},r)=>s.jsx(n.__,{ref:r,className:(0,l.cn)("px-2 py-1.5 text-sm font-semibold",t&&"pl-8",e),...a})).displayName=n.__.displayName,r.forwardRef(({className:e,...t},a)=>s.jsx(n.Z0,{ref:a,className:(0,l.cn)("-mx-1 my-1 h-px bg-slate-100 dark:bg-slate-800",e),...t})).displayName=n.Z0.displayName},2162:(e,t,a)=>{"use strict";a.d(t,{I:()=>i});var s=a(7486),r=a(618),n=a(5098);let i=r.forwardRef(({className:e,type:t,...a},r)=>s.jsx("input",{type:t,className:(0,n.cn)("flex h-10 w-full rounded-md border border-slate-200 bg-white px-3 py-2 text-base ring-offset-white file:border-0 file:bg-transparent file:text-sm file:font-medium file:text-slate-950 placeholder:text-slate-500 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-slate-950 focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 md:text-sm dark:border-slate-800 dark:bg-slate-950 dark:ring-offset-slate-950 dark:file:text-slate-50 dark:placeholder:text-slate-400 dark:focus-visible:ring-slate-300",e),ref:r,...a}));i.displayName="Input"},2119:(e,t,a)=>{"use strict";a.d(t,{x:()=>o});var s=a(7486),r=a(618),n=a(7051),i=a(5098);let o=r.forwardRef(({className:e,children:t,...a},r)=>(0,s.jsxs)(n.fC,{ref:r,className:(0,i.cn)("relative overflow-hidden",e),...a,children:[s.jsx(n.l_,{className:"h-full w-full rounded-[inherit]",children:t}),s.jsx(d,{}),s.jsx(n.Ns,{})]}));o.displayName=n.fC.displayName;let d=r.forwardRef(({className:e,orientation:t="vertical",...a},r)=>s.jsx(n.gb,{ref:r,orientation:t,className:(0,i.cn)("flex touch-none select-none transition-colors","vertical"===t&&"h-full w-2.5 border-l border-l-transparent p-[1px]","horizontal"===t&&"h-2.5 flex-col border-t border-t-transparent p-[1px]",e),...a,children:s.jsx(n.q4,{className:"relative flex-1 rounded-full bg-slate-200 dark:bg-slate-800"})}));d.displayName=n.gb.displayName},6637:(e,t,a)=>{"use strict";a.d(t,{Z:()=>o});var s=a(7486),r=a(618),n=a(7168),i=a(5098);let o=r.forwardRef(({className:e,orientation:t="horizontal",decorative:a=!0,...r},o)=>s.jsx(n.f,{ref:o,decorative:a,orientation:t,className:(0,i.cn)("shrink-0 bg-slate-200 dark:bg-slate-800","horizontal"===t?"h-[1px] w-full":"h-full w-[1px]",e),...r}));o.displayName=n.f.displayName},5875:(e,t,a)=>{"use strict";a.d(t,{_v:()=>c,aJ:()=>l,pn:()=>o,u:()=>d});var s=a(7486),r=a(618),n=a(6448),i=a(5098);let o=n.zt,d=n.fC,l=n.xz,c=r.forwardRef(({className:e,sideOffset:t=4,...a},r)=>s.jsx(n.VY,{ref:r,sideOffset:t,className:(0,i.cn)("z-50 overflow-hidden rounded-md border border-slate-200 bg-white px-3 py-1.5 text-sm text-slate-950 shadow-md animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 origin-[--radix-tooltip-content-transform-origin] dark:border-slate-800 dark:bg-slate-950 dark:text-slate-50",e),...a}));c.displayName=n.VY.displayName},6266:(e,t,a)=>{"use strict";a.d(t,{q:()=>o,w:()=>d});var s=a(7486),r=a(618),n=a(6811);let i=(0,r.createContext)(null);function o(){let e=(0,r.useContext)(i);if(!e)throw Error("useApp must be used inside AppProvider");return e}function d({children:e}){let t=(0,n.useRouter)(),[a,o]=(0,r.useState)([]),[d,l]=(0,r.useState)(""),[c,u]=(0,r.useState)(null),[m,p]=(0,r.useState)(null),[f,h]=(0,r.useState)([]),[b,g]=(0,r.useState)(!0),[x,v]=(0,r.useState)(!1),[y,N]=(0,r.useState)(null);(0,r.useRef)(null);let w=d?`?root=${encodeURIComponent(d)}`:"",j=(0,r.useCallback)(async e=>{let t=e||d;if(!t)return;let a=`?root=${encodeURIComponent(t)}`;try{let[e,t,s]=await Promise.all([fetch(`/api/summary${a}`).then(e=>e.json()),fetch(`/api/tasks${a}`).then(e=>e.json()),fetch(`/api/activity${a}&limit=30`).then(e=>e.json())]);u(e),p(t.board),h(Array.isArray(s)?s:[])}catch{}g(!1)},[d]),k=(0,r.useCallback)(async(e,t)=>{p(a=>{let s;if(!a)return a;let r=structuredClone(a);for(let a of Object.keys(r)){let n=r[a].findIndex(t=>t.id===e);-1!==n&&(s={...r[a][n],status:t},r[a]=r[a].filter(t=>t.id!==e))}return s&&r[t]&&(r[t]=[s,...r[t]]),r});try{await fetch(`/api/tasks${w}`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({taskId:e,status:t,actor:"human"})}),j()}catch{j()}},[w,j]),C=(0,r.useCallback)(async e=>{let a=await fetch(`/api/docs${w}&read=${encodeURIComponent(e)}`);N(await a.json()),t.push("/docs")},[w,t]);return s.jsx(i.Provider,{value:{projects:a,activeProject:d,summary:c,board:m,activity:f,liveIndicator:x,loading:b,selectedDoc:y,setSelectedDoc:N,rootParam:w,onProjectChange:function(e){l(e),j(e)},refresh:j,moveTask:k,openDoc:C},children:e})}},5098:(e,t,a)=>{"use strict";a.d(t,{cn:()=>n});var s=a(9360),r=a(2646);function n(...e){return(0,r.m6)((0,s.W)(e))}},2026:(e,t,a)=>{"use strict";a.r(t),a.d(t,{$$typeof:()=>i,__esModule:()=>n,default:()=>o});var s=a(2334);let r=(0,s.createProxy)(String.raw`/Users/hoangnguyen/Documents/nextjs/vibedoc/src/app/(app)/layout.tsx`),{__esModule:n,$$typeof:i}=r;r.default;let o=(0,s.createProxy)(String.raw`/Users/hoangnguyen/Documents/nextjs/vibedoc/src/app/(app)/layout.tsx#default`)},7831:(e,t,a)=>{"use strict";a.r(t),a.d(t,{default:()=>n,metadata:()=>r});var s=a(9703);a(5260);let r={title:"VibeDoc",description:"Project intelligence for AI-assisted development"};function n({children:e}){return s.jsx("html",{lang:"en",className:"dark",children:s.jsx("body",{className:"bg-bg text-txt min-h-screen",children:e})})}},5260:()=>{}};
|
|
1376
|
+
`},{id:"meeting-notes",name:"Meeting Notes",description:"Meeting notes template",defaultPath:`docs/meetings/${n}.md`,category:"technical",content:`# Meeting Notes — ${n}
|
|
1377
|
+
|
|
1378
|
+
**Attendees:**
|
|
1379
|
+
**Facilitator:**
|
|
1380
|
+
|
|
1381
|
+
## Agenda
|
|
1382
|
+
|
|
1383
|
+
1.
|
|
1384
|
+
2.
|
|
1385
|
+
|
|
1386
|
+
## Notes
|
|
1387
|
+
|
|
1388
|
+
## Decisions
|
|
1389
|
+
|
|
1390
|
+
## Action items
|
|
1391
|
+
|
|
1392
|
+
| Action | Owner | Due |
|
|
1393
|
+
|--------|-------|-----|
|
|
1394
|
+
| | | |
|
|
1395
|
+
|
|
1396
|
+
## Next meeting
|
|
1397
|
+
`},{id:"blank",name:"Blank Document",description:"Empty markdown file",defaultPath:"docs/untitled.md",category:"technical",content:"# Untitled\n\n"},{id:"dockerfile",name:"Dockerfile",description:"Multi-stage Docker build with health check",defaultPath:"Dockerfile",category:"infrastructure",content:`# Stage 1: Install dependencies
|
|
1398
|
+
FROM node:20-alpine AS deps
|
|
1399
|
+
RUN apk add --no-cache libc6-compat
|
|
1400
|
+
WORKDIR /app
|
|
1401
|
+
COPY package*.json ./
|
|
1402
|
+
RUN npm ci --only=production
|
|
1403
|
+
|
|
1404
|
+
# Stage 2: Build
|
|
1405
|
+
FROM node:20-alpine AS builder
|
|
1406
|
+
WORKDIR /app
|
|
1407
|
+
COPY --from=deps /app/node_modules ./node_modules
|
|
1408
|
+
COPY . .
|
|
1409
|
+
RUN npm run build
|
|
1410
|
+
|
|
1411
|
+
# Stage 3: Run
|
|
1412
|
+
FROM node:20-alpine AS runner
|
|
1413
|
+
WORKDIR /app
|
|
1414
|
+
ENV NODE_ENV=production
|
|
1415
|
+
RUN addgroup --system --gid 1001 nodejs
|
|
1416
|
+
RUN adduser --system --uid 1001 appuser
|
|
1417
|
+
COPY --from=builder /app/dist ./dist
|
|
1418
|
+
COPY --from=deps /app/node_modules ./node_modules
|
|
1419
|
+
COPY package*.json ./
|
|
1420
|
+
USER appuser
|
|
1421
|
+
EXPOSE 3000
|
|
1422
|
+
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \\
|
|
1423
|
+
CMD wget -qO- http://localhost:3000/health || exit 1
|
|
1424
|
+
CMD ["node", "dist/index.js"]
|
|
1425
|
+
`},{id:"docker-compose",name:"docker-compose.yml",description:"Docker Compose with app, Postgres, and Redis",defaultPath:"docker-compose.yml",category:"infrastructure",content:`# Docker Compose V2+ (no version key needed)
|
|
1426
|
+
services:
|
|
1427
|
+
app:
|
|
1428
|
+
build: .
|
|
1429
|
+
ports:
|
|
1430
|
+
- "3000:3000"
|
|
1431
|
+
environment:
|
|
1432
|
+
DATABASE_URL: postgresql://postgres:password@db:5432/{{PROJECT_NAME}}
|
|
1433
|
+
REDIS_URL: redis://redis:6379
|
|
1434
|
+
depends_on:
|
|
1435
|
+
db:
|
|
1436
|
+
condition: service_healthy
|
|
1437
|
+
redis:
|
|
1438
|
+
condition: service_healthy
|
|
1439
|
+
|
|
1440
|
+
db:
|
|
1441
|
+
image: postgres:16-alpine
|
|
1442
|
+
environment:
|
|
1443
|
+
POSTGRES_PASSWORD: password
|
|
1444
|
+
POSTGRES_DB: {{PROJECT_NAME}}
|
|
1445
|
+
healthcheck:
|
|
1446
|
+
test: ["CMD-SHELL", "pg_isready -U postgres"]
|
|
1447
|
+
interval: 10s
|
|
1448
|
+
timeout: 5s
|
|
1449
|
+
retries: 5
|
|
1450
|
+
volumes:
|
|
1451
|
+
- postgres_data:/var/lib/postgresql/data
|
|
1452
|
+
|
|
1453
|
+
redis:
|
|
1454
|
+
image: redis:7-alpine
|
|
1455
|
+
healthcheck:
|
|
1456
|
+
test: ["CMD", "redis-cli", "ping"]
|
|
1457
|
+
interval: 10s
|
|
1458
|
+
timeout: 5s
|
|
1459
|
+
retries: 5
|
|
1460
|
+
volumes:
|
|
1461
|
+
- redis_data:/data
|
|
1462
|
+
|
|
1463
|
+
volumes:
|
|
1464
|
+
postgres_data:
|
|
1465
|
+
redis_data:
|
|
1466
|
+
`},{id:"dockerignore",name:".dockerignore",description:"Docker build context exclusions",defaultPath:".dockerignore",category:"infrastructure",content:`node_modules
|
|
1467
|
+
npm-debug.log*
|
|
1468
|
+
.git
|
|
1469
|
+
.gitignore
|
|
1470
|
+
.env*
|
|
1471
|
+
!.env.example
|
|
1472
|
+
dist
|
|
1473
|
+
build
|
|
1474
|
+
coverage
|
|
1475
|
+
.nyc_output
|
|
1476
|
+
*.test.*
|
|
1477
|
+
*.spec.*
|
|
1478
|
+
__tests__
|
|
1479
|
+
e2e
|
|
1480
|
+
.github
|
|
1481
|
+
docs
|
|
1482
|
+
README.md
|
|
1483
|
+
CHANGELOG.md
|
|
1484
|
+
`},{id:"makefile",name:"Makefile",description:"Makefile with common dev/build/deploy targets",defaultPath:"Makefile",category:"infrastructure",content:`.PHONY: help dev build test lint docker-up docker-down migrate clean
|
|
1485
|
+
|
|
1486
|
+
help: ## Show this help
|
|
1487
|
+
@grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | awk 'BEGIN {FS = ":.*?## "}; {printf "\\033[36m%-20s\\033[0m %s\\n", $$1, $$2}'
|
|
1488
|
+
|
|
1489
|
+
dev: ## Start development server
|
|
1490
|
+
npm run dev
|
|
1491
|
+
|
|
1492
|
+
build: ## Build for production
|
|
1493
|
+
npm run build
|
|
1494
|
+
|
|
1495
|
+
test: ## Run all tests
|
|
1496
|
+
npm test
|
|
1497
|
+
|
|
1498
|
+
lint: ## Run linter
|
|
1499
|
+
npm run lint
|
|
1500
|
+
|
|
1501
|
+
docker-up: ## Start Docker services
|
|
1502
|
+
docker compose up -d
|
|
1503
|
+
|
|
1504
|
+
docker-down: ## Stop Docker services
|
|
1505
|
+
docker compose down
|
|
1506
|
+
|
|
1507
|
+
migrate: ## Run database migrations
|
|
1508
|
+
npm run db:migrate
|
|
1509
|
+
|
|
1510
|
+
clean: ## Remove build artifacts
|
|
1511
|
+
rm -rf dist build .next coverage node_modules/.cache
|
|
1512
|
+
`},{id:"env-example",name:".env.example",description:"Annotated environment variables template",defaultPath:".env.example",category:"infrastructure",content:`# App Config
|
|
1513
|
+
NODE_ENV=development
|
|
1514
|
+
PORT=3000
|
|
1515
|
+
APP_URL=http://localhost:3000
|
|
1516
|
+
LOG_LEVEL=info
|
|
1517
|
+
|
|
1518
|
+
# Database
|
|
1519
|
+
DATABASE_URL=postgresql://user:password@localhost:5432/{{PROJECT_NAME}}_dev
|
|
1520
|
+
|
|
1521
|
+
# Auth
|
|
1522
|
+
JWT_SECRET=your-super-secret-jwt-key-change-in-production
|
|
1523
|
+
JWT_EXPIRES_IN=7d
|
|
1524
|
+
SESSION_SECRET=your-session-secret-change-in-production
|
|
1525
|
+
|
|
1526
|
+
# External Services
|
|
1527
|
+
# STRIPE_SECRET_KEY=sk_test_...
|
|
1528
|
+
# SENDGRID_API_KEY=SG....
|
|
1529
|
+
# AWS_ACCESS_KEY_ID=
|
|
1530
|
+
# AWS_SECRET_ACCESS_KEY=
|
|
1531
|
+
# AWS_REGION=us-east-1
|
|
1532
|
+
# AWS_S3_BUCKET=
|
|
1533
|
+
|
|
1534
|
+
# Observability
|
|
1535
|
+
# SENTRY_DSN=https://...@sentry.io/...
|
|
1536
|
+
# DATADOG_API_KEY=
|
|
1537
|
+
# NEW_RELIC_LICENSE_KEY=
|
|
1538
|
+
`},{id:"nginx-conf",name:"nginx.conf",description:"Nginx reverse proxy with gzip, security headers, rate limiting",defaultPath:"nginx/nginx.conf",category:"infrastructure",content:`events {
|
|
1539
|
+
worker_connections 1024;
|
|
1540
|
+
}
|
|
1541
|
+
|
|
1542
|
+
http {
|
|
1543
|
+
gzip on;
|
|
1544
|
+
gzip_types text/plain text/css application/json application/javascript text/xml;
|
|
1545
|
+
gzip_min_length 1000;
|
|
1546
|
+
|
|
1547
|
+
# Rate limiting
|
|
1548
|
+
limit_req_zone $binary_remote_addr zone=api:10m rate=10r/s;
|
|
1549
|
+
|
|
1550
|
+
server {
|
|
1551
|
+
listen 80;
|
|
1552
|
+
server_name _;
|
|
1553
|
+
|
|
1554
|
+
# Security headers
|
|
1555
|
+
add_header X-Frame-Options "SAMEORIGIN" always;
|
|
1556
|
+
add_header X-Content-Type-Options "nosniff" always;
|
|
1557
|
+
add_header X-XSS-Protection "1; mode=block" always;
|
|
1558
|
+
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
|
|
1559
|
+
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
|
|
1560
|
+
|
|
1561
|
+
location /api/ {
|
|
1562
|
+
limit_req zone=api burst=20 nodelay;
|
|
1563
|
+
proxy_pass http://app:3000;
|
|
1564
|
+
proxy_http_version 1.1;
|
|
1565
|
+
proxy_set_header Upgrade $http_upgrade;
|
|
1566
|
+
proxy_set_header Connection 'upgrade';
|
|
1567
|
+
proxy_set_header Host $host;
|
|
1568
|
+
proxy_set_header X-Real-IP $remote_addr;
|
|
1569
|
+
proxy_cache_bypass $http_upgrade;
|
|
1570
|
+
}
|
|
1571
|
+
|
|
1572
|
+
location / {
|
|
1573
|
+
proxy_pass http://app:3000;
|
|
1574
|
+
proxy_http_version 1.1;
|
|
1575
|
+
proxy_set_header Host $host;
|
|
1576
|
+
proxy_set_header X-Real-IP $remote_addr;
|
|
1577
|
+
}
|
|
1578
|
+
}
|
|
1579
|
+
}
|
|
1580
|
+
`},{id:"ci-workflow",name:"CI Workflow",description:"GitHub Actions CI: lint, typecheck, test matrix, coverage",defaultPath:".github/workflows/ci.yml",category:"github-actions",content:`name: CI
|
|
1581
|
+
on:
|
|
1582
|
+
push:
|
|
1583
|
+
branches: [main, develop]
|
|
1584
|
+
pull_request:
|
|
1585
|
+
branches: [main, develop]
|
|
1586
|
+
|
|
1587
|
+
jobs:
|
|
1588
|
+
lint:
|
|
1589
|
+
runs-on: ubuntu-latest
|
|
1590
|
+
steps:
|
|
1591
|
+
- uses: actions/checkout@v4
|
|
1592
|
+
- uses: actions/setup-node@v4
|
|
1593
|
+
with: {node-version: '20', cache: 'npm'}
|
|
1594
|
+
- run: npm ci
|
|
1595
|
+
- run: npm run lint
|
|
1596
|
+
- run: npm run typecheck
|
|
1597
|
+
|
|
1598
|
+
test:
|
|
1599
|
+
runs-on: ubuntu-latest
|
|
1600
|
+
strategy:
|
|
1601
|
+
matrix:
|
|
1602
|
+
node-version: ['20', '22']
|
|
1603
|
+
steps:
|
|
1604
|
+
- uses: actions/checkout@v4
|
|
1605
|
+
- uses: actions/setup-node@v4
|
|
1606
|
+
with: {node-version: '\${{ matrix.node-version }}', cache: 'npm'}
|
|
1607
|
+
- run: npm ci
|
|
1608
|
+
- run: npm run test:coverage
|
|
1609
|
+
- uses: codecov/codecov-action@v4
|
|
1610
|
+
if: matrix.node-version == '20'
|
|
1611
|
+
|
|
1612
|
+
build:
|
|
1613
|
+
runs-on: ubuntu-latest
|
|
1614
|
+
needs: [lint, test]
|
|
1615
|
+
steps:
|
|
1616
|
+
- uses: actions/checkout@v4
|
|
1617
|
+
- uses: actions/setup-node@v4
|
|
1618
|
+
with: {node-version: '20', cache: 'npm'}
|
|
1619
|
+
- run: npm ci
|
|
1620
|
+
- run: npm run build
|
|
1621
|
+
`},{id:"cd-workflow",name:"CD Workflow",description:"GitHub Actions CD: deploy to production with health check",defaultPath:".github/workflows/cd.yml",category:"github-actions",content:`name: CD
|
|
1622
|
+
on:
|
|
1623
|
+
push:
|
|
1624
|
+
branches: [main]
|
|
1625
|
+
|
|
1626
|
+
jobs:
|
|
1627
|
+
deploy:
|
|
1628
|
+
runs-on: ubuntu-latest
|
|
1629
|
+
# needs: [ci] # Uncomment if using a reusable CI workflow
|
|
1630
|
+
environment: production
|
|
1631
|
+
steps:
|
|
1632
|
+
- uses: actions/checkout@v4
|
|
1633
|
+
- uses: actions/setup-node@v4
|
|
1634
|
+
with: {node-version: '20', cache: 'npm'}
|
|
1635
|
+
- run: npm ci
|
|
1636
|
+
- run: npm run build
|
|
1637
|
+
- name: Deploy
|
|
1638
|
+
env:
|
|
1639
|
+
DEPLOY_TOKEN: \${{ secrets.DEPLOY_TOKEN }}
|
|
1640
|
+
DEPLOY_URL: \${{ secrets.DEPLOY_URL }}
|
|
1641
|
+
run: |
|
|
1642
|
+
# Add your deployment command here
|
|
1643
|
+
# e.g.: npx railway deploy, vercel deploy --prod, etc.
|
|
1644
|
+
echo "Deploy to production"
|
|
1645
|
+
- name: Health check
|
|
1646
|
+
run: |
|
|
1647
|
+
sleep 30
|
|
1648
|
+
curl -f \${{ secrets.APP_URL }}/health || exit 1
|
|
1649
|
+
`},{id:"security-scan",name:"Security Scan",description:"GitHub Actions security: npm audit + CodeQL analysis",defaultPath:".github/workflows/security.yml",category:"github-actions",content:`name: Security
|
|
1650
|
+
on:
|
|
1651
|
+
push:
|
|
1652
|
+
branches: [main]
|
|
1653
|
+
schedule:
|
|
1654
|
+
- cron: '0 0 * * 1' # Weekly on Monday
|
|
1655
|
+
|
|
1656
|
+
jobs:
|
|
1657
|
+
audit:
|
|
1658
|
+
runs-on: ubuntu-latest
|
|
1659
|
+
steps:
|
|
1660
|
+
- uses: actions/checkout@v4
|
|
1661
|
+
- uses: actions/setup-node@v4
|
|
1662
|
+
with: {node-version: '20', cache: 'npm'}
|
|
1663
|
+
- run: npm ci
|
|
1664
|
+
- run: npm audit --audit-level=high
|
|
1665
|
+
|
|
1666
|
+
codeql:
|
|
1667
|
+
runs-on: ubuntu-latest
|
|
1668
|
+
permissions:
|
|
1669
|
+
actions: read
|
|
1670
|
+
contents: read
|
|
1671
|
+
security-events: write
|
|
1672
|
+
steps:
|
|
1673
|
+
- uses: actions/checkout@v4
|
|
1674
|
+
- uses: github/codeql-action/init@v3
|
|
1675
|
+
with: {languages: javascript}
|
|
1676
|
+
- uses: github/codeql-action/autobuild@v3
|
|
1677
|
+
- uses: github/codeql-action/analyze@v3
|
|
1678
|
+
`},{id:"dependabot-config",name:"Dependabot Config",description:"Dependabot config: npm + GitHub Actions weekly updates",defaultPath:".github/dependabot.yml",category:"github-actions",content:`version: 2
|
|
1679
|
+
updates:
|
|
1680
|
+
- package-ecosystem: npm
|
|
1681
|
+
directory: "/"
|
|
1682
|
+
schedule:
|
|
1683
|
+
interval: weekly
|
|
1684
|
+
day: monday
|
|
1685
|
+
groups:
|
|
1686
|
+
minor-and-patch:
|
|
1687
|
+
update-types: ["minor", "patch"]
|
|
1688
|
+
ignore:
|
|
1689
|
+
- dependency-name: "*"
|
|
1690
|
+
update-types: ["version-update:semver-major"]
|
|
1691
|
+
|
|
1692
|
+
- package-ecosystem: github-actions
|
|
1693
|
+
directory: "/"
|
|
1694
|
+
schedule:
|
|
1695
|
+
interval: weekly
|
|
1696
|
+
day: monday
|
|
1697
|
+
`},{id:"release-workflow",name:"Release Workflow",description:"GitHub Actions release: GitHub Release + Docker image to GHCR",defaultPath:".github/workflows/release.yml",category:"github-actions",content:`name: Release
|
|
1698
|
+
on:
|
|
1699
|
+
push:
|
|
1700
|
+
tags: ['v*']
|
|
1701
|
+
|
|
1702
|
+
jobs:
|
|
1703
|
+
release:
|
|
1704
|
+
runs-on: ubuntu-latest
|
|
1705
|
+
permissions:
|
|
1706
|
+
contents: write
|
|
1707
|
+
packages: write
|
|
1708
|
+
steps:
|
|
1709
|
+
- uses: actions/checkout@v4
|
|
1710
|
+
- name: Create GitHub Release
|
|
1711
|
+
uses: softprops/action-gh-release@v2
|
|
1712
|
+
with:
|
|
1713
|
+
generate_release_notes: true
|
|
1714
|
+
- name: Log in to GHCR
|
|
1715
|
+
uses: docker/login-action@v3
|
|
1716
|
+
with:
|
|
1717
|
+
registry: ghcr.io
|
|
1718
|
+
username: \${{ github.actor }}
|
|
1719
|
+
password: \${{ secrets.GITHUB_TOKEN }}
|
|
1720
|
+
- name: Build and push Docker image
|
|
1721
|
+
uses: docker/build-push-action@v5
|
|
1722
|
+
with:
|
|
1723
|
+
context: .
|
|
1724
|
+
push: true
|
|
1725
|
+
tags: |
|
|
1726
|
+
ghcr.io/\${{ github.repository }}:\${{ github.ref_name }}
|
|
1727
|
+
ghcr.io/\${{ github.repository }}:latest
|
|
1728
|
+
`},{id:"codeowners",name:"CODEOWNERS",description:"GitHub CODEOWNERS file for review assignments",defaultPath:".github/CODEOWNERS",category:"github",content:`# IMPORTANT: Replace {{PROJECT_NAME}} below with your GitHub organization name
|
|
1729
|
+
# (org name and project name are often different)
|
|
1730
|
+
# Format: @org-name/team-slug
|
|
1731
|
+
|
|
1732
|
+
# Global owners - review all changes
|
|
1733
|
+
* @{{PROJECT_NAME}}/maintainers
|
|
1734
|
+
|
|
1735
|
+
# Documentation
|
|
1736
|
+
docs/ @{{PROJECT_NAME}}/docs
|
|
1737
|
+
*.md @{{PROJECT_NAME}}/docs
|
|
1738
|
+
|
|
1739
|
+
# CI/CD config
|
|
1740
|
+
.github/ @{{PROJECT_NAME}}/devops
|
|
1741
|
+
Dockerfile @{{PROJECT_NAME}}/devops
|
|
1742
|
+
docker-compose*.yml @{{PROJECT_NAME}}/devops
|
|
1743
|
+
|
|
1744
|
+
# Security-sensitive files
|
|
1745
|
+
**/auth/ @{{PROJECT_NAME}}/security
|
|
1746
|
+
**/security/ @{{PROJECT_NAME}}/security
|
|
1747
|
+
SECURITY.md @{{PROJECT_NAME}}/security
|
|
1748
|
+
`},{id:"eslintrc",name:"ESLint Config",description:"ESLint config with TypeScript strict rules",defaultPath:".eslintrc.json",category:"code-quality",content:`{
|
|
1749
|
+
"extends": [
|
|
1750
|
+
"eslint:recommended",
|
|
1751
|
+
"plugin:@typescript-eslint/recommended",
|
|
1752
|
+
"plugin:@typescript-eslint/recommended-requiring-type-checking"
|
|
1753
|
+
],
|
|
1754
|
+
"parser": "@typescript-eslint/parser",
|
|
1755
|
+
"parserOptions": {
|
|
1756
|
+
"project": true,
|
|
1757
|
+
"tsconfigRootDir": "."
|
|
1758
|
+
},
|
|
1759
|
+
"plugins": ["@typescript-eslint"],
|
|
1760
|
+
"rules": {
|
|
1761
|
+
"no-console": "warn",
|
|
1762
|
+
"no-unused-vars": "off",
|
|
1763
|
+
"@typescript-eslint/no-unused-vars": ["error", { "argsIgnorePattern": "^_" }],
|
|
1764
|
+
"@typescript-eslint/no-explicit-any": "warn",
|
|
1765
|
+
"@typescript-eslint/consistent-type-imports": "error",
|
|
1766
|
+
"@typescript-eslint/no-floating-promises": "error"
|
|
1767
|
+
},
|
|
1768
|
+
"ignorePatterns": ["dist/", "build/", "node_modules/", "*.config.js"]
|
|
1769
|
+
}
|
|
1770
|
+
`},{id:"prettierrc",name:"Prettier Config",description:"Prettier formatting config",defaultPath:".prettierrc",category:"code-quality",content:`{
|
|
1771
|
+
"semi": false,
|
|
1772
|
+
"singleQuote": true,
|
|
1773
|
+
"trailingComma": "es5",
|
|
1774
|
+
"printWidth": 100,
|
|
1775
|
+
"tabWidth": 2,
|
|
1776
|
+
"useTabs": false,
|
|
1777
|
+
"bracketSpacing": true,
|
|
1778
|
+
"arrowParens": "avoid"
|
|
1779
|
+
}
|
|
1780
|
+
`},{id:"tsconfig-strict",name:"tsconfig (strict)",description:"TypeScript config with strict settings for Node/ESM",defaultPath:"tsconfig.json",category:"code-quality",content:`{
|
|
1781
|
+
"compilerOptions": {
|
|
1782
|
+
"target": "ES2022",
|
|
1783
|
+
"lib": ["ES2022"],
|
|
1784
|
+
"module": "NodeNext",
|
|
1785
|
+
"moduleResolution": "NodeNext",
|
|
1786
|
+
"outDir": "dist",
|
|
1787
|
+
"rootDir": "src",
|
|
1788
|
+
"strict": true,
|
|
1789
|
+
"noUncheckedIndexedAccess": true,
|
|
1790
|
+
"exactOptionalPropertyTypes": true,
|
|
1791
|
+
"noImplicitReturns": true,
|
|
1792
|
+
"noFallthroughCasesInSwitch": true,
|
|
1793
|
+
"noImplicitOverride": true,
|
|
1794
|
+
"esModuleInterop": true,
|
|
1795
|
+
"skipLibCheck": true,
|
|
1796
|
+
"forceConsistentCasingInFileNames": true,
|
|
1797
|
+
"paths": {
|
|
1798
|
+
"@/*": ["./src/*"]
|
|
1799
|
+
}
|
|
1800
|
+
},
|
|
1801
|
+
"include": ["src/**/*"],
|
|
1802
|
+
"exclude": ["node_modules", "dist"]
|
|
1803
|
+
}
|
|
1804
|
+
`},{id:"editorconfig",name:".editorconfig",description:"EditorConfig for consistent editor settings",defaultPath:".editorconfig",category:"code-quality",content:`root = true
|
|
1805
|
+
|
|
1806
|
+
[*]
|
|
1807
|
+
indent_style = space
|
|
1808
|
+
indent_size = 2
|
|
1809
|
+
end_of_line = lf
|
|
1810
|
+
charset = utf-8
|
|
1811
|
+
trim_trailing_whitespace = true
|
|
1812
|
+
insert_final_newline = true
|
|
1813
|
+
|
|
1814
|
+
[*.md]
|
|
1815
|
+
trim_trailing_whitespace = false
|
|
1816
|
+
|
|
1817
|
+
[Makefile]
|
|
1818
|
+
indent_style = tab
|
|
1819
|
+
|
|
1820
|
+
[*.{yml,yaml}]
|
|
1821
|
+
indent_size = 2
|
|
1822
|
+
`},{id:"lint-staged",name:"lint-staged Config",description:"lint-staged config for pre-commit formatting and linting",defaultPath:".lintstagedrc.json",category:"code-quality",content:`{
|
|
1823
|
+
"*.{ts,tsx}": ["eslint --fix", "prettier --write"],
|
|
1824
|
+
"*.{js,jsx}": ["eslint --fix", "prettier --write"],
|
|
1825
|
+
"*.{json,md,yml,yaml}": ["prettier --write"],
|
|
1826
|
+
"*.{css,scss}": ["prettier --write"]
|
|
1827
|
+
}
|
|
1828
|
+
`},{id:"commitlint",name:"commitlint Config",description:"commitlint config enforcing Conventional Commits",defaultPath:"commitlint.config.js",category:"code-quality",content:`module.exports = {
|
|
1829
|
+
extends: ['@commitlint/config-conventional'],
|
|
1830
|
+
rules: {
|
|
1831
|
+
'type-enum': [2, 'always', [
|
|
1832
|
+
'feat', 'fix', 'docs', 'style', 'refactor',
|
|
1833
|
+
'perf', 'test', 'chore', 'revert', 'ci', 'build'
|
|
1834
|
+
]],
|
|
1835
|
+
'scope-case': [2, 'always', 'lower-case'],
|
|
1836
|
+
'subject-case': [2, 'always', 'lower-case'],
|
|
1837
|
+
'subject-max-length': [2, 'always', 100],
|
|
1838
|
+
'body-max-line-length': [2, 'always', 200],
|
|
1839
|
+
},
|
|
1840
|
+
}
|
|
1841
|
+
`},{id:"husky-setup",name:"Husky Setup Doc",description:"Documentation for Husky git hooks setup",defaultPath:".husky/README.md",category:"code-quality",content:`# Husky Git Hooks
|
|
1842
|
+
|
|
1843
|
+
This project uses [Husky](https://typicode.github.io/husky/) to enforce code quality at commit time.
|
|
1844
|
+
|
|
1845
|
+
## Setup
|
|
1846
|
+
|
|
1847
|
+
After cloning and running \`npm install\`, Husky hooks are auto-installed via the \`prepare\` script.
|
|
1848
|
+
|
|
1849
|
+
If hooks aren't running, install manually:
|
|
1850
|
+
|
|
1851
|
+
\`\`\`
|
|
1852
|
+
npx husky install
|
|
1853
|
+
\`\`\`
|
|
1854
|
+
|
|
1855
|
+
## Hooks
|
|
1856
|
+
|
|
1857
|
+
| Hook | Command | Purpose |
|
|
1858
|
+
|------|---------|---------|
|
|
1859
|
+
| pre-commit | \`lint-staged\` | Lint and format staged files |
|
|
1860
|
+
| commit-msg | \`commitlint\` | Validate commit message format |
|
|
1861
|
+
| pre-push | \`npm test\` | Run tests before pushing |
|
|
1862
|
+
|
|
1863
|
+
## Skip hooks (emergencies only)
|
|
1864
|
+
|
|
1865
|
+
\`\`\`
|
|
1866
|
+
git commit --no-verify -m "emergency fix"
|
|
1867
|
+
\`\`\`
|
|
1868
|
+
|
|
1869
|
+
Use sparingly. CI will still catch failures.
|
|
1870
|
+
`},{id:"vscode-settings",name:"VS Code Settings",description:"VS Code workspace settings for the project",defaultPath:".vscode/settings.json",category:"code-quality",content:`{
|
|
1871
|
+
"editor.formatOnSave": true,
|
|
1872
|
+
"editor.defaultFormatter": "esbenp.prettier-vscode",
|
|
1873
|
+
"editor.codeActionsOnSave": {
|
|
1874
|
+
"source.fixAll.eslint": "explicit",
|
|
1875
|
+
"source.organizeImports": "explicit"
|
|
1876
|
+
},
|
|
1877
|
+
"typescript.preferences.importModuleSpecifier": "non-relative",
|
|
1878
|
+
"typescript.tsdk": "node_modules/typescript/lib",
|
|
1879
|
+
"files.eol": "\\n",
|
|
1880
|
+
"files.trimTrailingWhitespace": true,
|
|
1881
|
+
"files.insertFinalNewline": true,
|
|
1882
|
+
"[markdown]": {
|
|
1883
|
+
"editor.formatOnSave": false
|
|
1884
|
+
}
|
|
1885
|
+
}
|
|
1886
|
+
`},{id:"vscode-extensions",name:"VS Code Extensions",description:"Recommended VS Code extensions for the project",defaultPath:".vscode/extensions.json",category:"code-quality",content:`{
|
|
1887
|
+
"recommendations": [
|
|
1888
|
+
"esbenp.prettier-vscode",
|
|
1889
|
+
"dbaeumer.vscode-eslint",
|
|
1890
|
+
"ms-vscode.vscode-typescript-next",
|
|
1891
|
+
"bradlc.vscode-tailwindcss",
|
|
1892
|
+
"eamodio.gitlens",
|
|
1893
|
+
"usernamehw.errorlens",
|
|
1894
|
+
"streetsidesoftware.code-spell-checker",
|
|
1895
|
+
"github.copilot",
|
|
1896
|
+
"christian-kohler.path-intellisense"
|
|
1897
|
+
]
|
|
1898
|
+
}
|
|
1899
|
+
`},{id:"health-check-doc",name:"Health Check Guide",description:"Health check endpoint documentation with Kubernetes config",defaultPath:"docs/health-checks.md",category:"monitoring",content:`# Health Checks — {{PROJECT_NAME}}
|
|
1900
|
+
|
|
1901
|
+
**Last updated:** {{DATE}}
|
|
1902
|
+
|
|
1903
|
+
## Overview
|
|
1904
|
+
|
|
1905
|
+
Health check endpoints allow load balancers and orchestrators to verify service status.
|
|
1906
|
+
|
|
1907
|
+
## Endpoints
|
|
1908
|
+
|
|
1909
|
+
| Endpoint | Purpose | Auth required |
|
|
1910
|
+
|----------|---------|---------------|
|
|
1911
|
+
| \`GET /health\` | Liveness probe — is the process running? | No |
|
|
1912
|
+
| \`GET /health/ready\` | Readiness probe — can the service handle traffic? | No |
|
|
1913
|
+
| \`GET /health/detailed\` | Full dependency status | Yes (internal) |
|
|
1914
|
+
|
|
1915
|
+
## Liveness Check (\`GET /health\`)
|
|
1916
|
+
|
|
1917
|
+
Returns 200 if the process is alive, regardless of dependency status.
|
|
1918
|
+
|
|
1919
|
+
\`\`\`json
|
|
1920
|
+
{"status": "ok", "uptime": 1234}
|
|
1921
|
+
\`\`\`
|
|
1922
|
+
|
|
1923
|
+
## Readiness Check (\`GET /health/ready\`)
|
|
1924
|
+
|
|
1925
|
+
Returns 200 only if all critical dependencies are healthy.
|
|
1926
|
+
|
|
1927
|
+
\`\`\`json
|
|
1928
|
+
{
|
|
1929
|
+
"status": "ready",
|
|
1930
|
+
"dependencies": {
|
|
1931
|
+
"database": "ok",
|
|
1932
|
+
"redis": "ok",
|
|
1933
|
+
"external_api": "degraded"
|
|
1934
|
+
}
|
|
1935
|
+
}
|
|
1936
|
+
\`\`\`
|
|
1937
|
+
|
|
1938
|
+
Returns 503 if any critical dependency is unhealthy.
|
|
1939
|
+
|
|
1940
|
+
## Kubernetes Configuration
|
|
1941
|
+
|
|
1942
|
+
\`\`\`yaml
|
|
1943
|
+
livenessProbe:
|
|
1944
|
+
httpGet:
|
|
1945
|
+
path: /health
|
|
1946
|
+
port: 3000
|
|
1947
|
+
initialDelaySeconds: 30
|
|
1948
|
+
periodSeconds: 10
|
|
1949
|
+
readinessProbe:
|
|
1950
|
+
httpGet:
|
|
1951
|
+
path: /health/ready
|
|
1952
|
+
port: 3000
|
|
1953
|
+
initialDelaySeconds: 5
|
|
1954
|
+
periodSeconds: 5
|
|
1955
|
+
\`\`\`
|
|
1956
|
+
`},{id:"slo-doc",name:"SLO/SLA Document",description:"Service Level Objectives with error budget and burn rate alerts",defaultPath:"docs/slo.md",category:"monitoring",content:`# Service Level Objectives — {{PROJECT_NAME}}
|
|
1957
|
+
|
|
1958
|
+
**Last updated:** {{DATE}}
|
|
1959
|
+
**Owner:** Platform Team
|
|
1960
|
+
|
|
1961
|
+
## Availability SLO
|
|
1962
|
+
|
|
1963
|
+
| Metric | Target | Error Budget (30 days) |
|
|
1964
|
+
|--------|--------|----------------------|
|
|
1965
|
+
| Availability | 99.9% | 43.8 minutes |
|
|
1966
|
+
| Success rate | 99.5% | — |
|
|
1967
|
+
|
|
1968
|
+
## Latency SLO
|
|
1969
|
+
|
|
1970
|
+
| Percentile | Target |
|
|
1971
|
+
|------------|--------|
|
|
1972
|
+
| p50 | < 100ms |
|
|
1973
|
+
| p95 | < 500ms |
|
|
1974
|
+
| p99 | < 1000ms |
|
|
1975
|
+
|
|
1976
|
+
## Error Budget Policy
|
|
1977
|
+
|
|
1978
|
+
| Burn Rate | Alert Window | Severity | Action |
|
|
1979
|
+
|-----------|-------------|----------|--------|
|
|
1980
|
+
| > 14.4x | 1 hour | Critical | Page on-call immediately |
|
|
1981
|
+
| > 6x | 6 hours | High | Page on-call |
|
|
1982
|
+
| > 3x | 24 hours | Medium | Ticket + monitor |
|
|
1983
|
+
| > 1x | 72 hours | Low | Review in standup |
|
|
1984
|
+
|
|
1985
|
+
## Consequences of Exhausting Error Budget
|
|
1986
|
+
|
|
1987
|
+
- Feature freeze until budget replenishes
|
|
1988
|
+
- Reliability sprint prioritized over new features
|
|
1989
|
+
- Post-mortem required for any budget burn > 50%
|
|
1990
|
+
|
|
1991
|
+
## Measurement
|
|
1992
|
+
|
|
1993
|
+
- Uptime tracked via synthetic monitoring (Pingdom / UptimeRobot)
|
|
1994
|
+
- Latency tracked via APM (Datadog / New Relic)
|
|
1995
|
+
- Error rate from application logs + Sentry
|
|
1996
|
+
`},{id:"incident-runbook",name:"Incident Runbook",description:"Incident response runbook with severity levels and escalation",defaultPath:"docs/incident-runbook.md",category:"monitoring",content:`# Incident Runbook — {{PROJECT_NAME}}
|
|
1997
|
+
|
|
1998
|
+
**Last updated:** {{DATE}}
|
|
1999
|
+
|
|
2000
|
+
## Severity Levels
|
|
2001
|
+
|
|
2002
|
+
| Severity | Definition | Response Time | Example |
|
|
2003
|
+
|----------|-----------|---------------|---------|
|
|
2004
|
+
| P0 | Complete outage, all users affected | 15 minutes | Site down |
|
|
2005
|
+
| P1 | Major feature broken, >50% users affected | 30 minutes | Login broken |
|
|
2006
|
+
| P2 | Significant degradation, subset of users | 2 hours | Slow API |
|
|
2007
|
+
| P3 | Minor issue, workaround available | Next business day | Cosmetic bug |
|
|
2008
|
+
|
|
2009
|
+
## Roles
|
|
2010
|
+
|
|
2011
|
+
| Role | Responsibility |
|
|
2012
|
+
|------|---------------|
|
|
2013
|
+
| Incident Commander (IC) | Owns resolution, coordinates team, communicates status |
|
|
2014
|
+
| Tech Lead | Diagnoses root cause, coordinates fixes |
|
|
2015
|
+
| Comms Lead | Updates status page, notifies stakeholders |
|
|
2016
|
+
|
|
2017
|
+
## Response Process
|
|
2018
|
+
|
|
2019
|
+
### 0–15 minutes (Detect & Triage)
|
|
2020
|
+
1. Confirm the incident (not a false alarm)
|
|
2021
|
+
2. Assign Incident Commander
|
|
2022
|
+
3. Create incident Slack channel: \`#incident-YYYYMMDD-description\`
|
|
2023
|
+
4. Set severity level
|
|
2024
|
+
5. Start incident timeline document
|
|
2025
|
+
|
|
2026
|
+
### 15–60 minutes (Investigate)
|
|
2027
|
+
1. Identify scope: what's broken, who's affected
|
|
2028
|
+
2. Check recent deployments (\`git log\`, deployment history)
|
|
2029
|
+
3. Review error rates and logs
|
|
2030
|
+
4. Consider rollback if recent deploy is suspected
|
|
2031
|
+
|
|
2032
|
+
### Mitigation
|
|
2033
|
+
1. Apply fix or rollback
|
|
2034
|
+
2. Monitor for improvement
|
|
2035
|
+
3. Update status page
|
|
2036
|
+
4. Notify stakeholders
|
|
2037
|
+
|
|
2038
|
+
## Post-Incident Checklist
|
|
2039
|
+
|
|
2040
|
+
- [ ] Incident resolved and verified
|
|
2041
|
+
- [ ] Status page updated to "resolved"
|
|
2042
|
+
- [ ] Stakeholders notified
|
|
2043
|
+
- [ ] Timeline documented
|
|
2044
|
+
- [ ] Post-mortem scheduled (P0/P1) or ticket created (P2)
|
|
2045
|
+
- [ ] Action items created in project tracker
|
|
2046
|
+
`},{id:"postmortem",name:"Postmortem Template",description:"Blameless postmortem template with five-whys and action items",defaultPath:"docs/postmortem-template.md",category:"monitoring",content:`# Postmortem: [Title]
|
|
2047
|
+
|
|
2048
|
+
**Date:** {{DATE}}
|
|
2049
|
+
**Severity:** P[0-3]
|
|
2050
|
+
**Duration:**
|
|
2051
|
+
**Author:**
|
|
2052
|
+
**Reviewers:**
|
|
2053
|
+
|
|
2054
|
+
> This postmortem follows a blameless culture. We focus on systems and processes, not individuals.
|
|
2055
|
+
|
|
2056
|
+
## Summary
|
|
2057
|
+
|
|
2058
|
+
<!-- 2-3 sentence summary: what happened, why it matters, what we're doing about it -->
|
|
2059
|
+
|
|
2060
|
+
## Impact
|
|
2061
|
+
|
|
2062
|
+
- **Users affected:**
|
|
2063
|
+
- **Duration:**
|
|
2064
|
+
- **Revenue impact:**
|
|
2065
|
+
- **Data loss:**
|
|
2066
|
+
|
|
2067
|
+
## Timeline
|
|
2068
|
+
|
|
2069
|
+
| Time (UTC) | Event |
|
|
2070
|
+
|------------|-------|
|
|
2071
|
+
| 00:00 | Monitoring alert fired |
|
|
2072
|
+
| 00:05 | On-call engineer paged |
|
|
2073
|
+
| 00:15 | Incident confirmed, IC assigned |
|
|
2074
|
+
| 00:30 | Root cause identified |
|
|
2075
|
+
| 01:00 | Fix deployed |
|
|
2076
|
+
| 01:15 | Incident resolved |
|
|
2077
|
+
|
|
2078
|
+
## Root Cause Analysis (Five Whys)
|
|
2079
|
+
|
|
2080
|
+
**Problem:** [Describe the issue]
|
|
2081
|
+
|
|
2082
|
+
1. **Why?** [First cause]
|
|
2083
|
+
2. **Why?** [Second cause]
|
|
2084
|
+
3. **Why?** [Third cause]
|
|
2085
|
+
4. **Why?** [Fourth cause]
|
|
2086
|
+
5. **Why?** [Root cause]
|
|
2087
|
+
|
|
2088
|
+
## What Went Well
|
|
2089
|
+
|
|
2090
|
+
-
|
|
2091
|
+
-
|
|
2092
|
+
|
|
2093
|
+
## What Could Have Gone Better
|
|
2094
|
+
|
|
2095
|
+
-
|
|
2096
|
+
-
|
|
2097
|
+
|
|
2098
|
+
## Action Items
|
|
2099
|
+
|
|
2100
|
+
| Action | Owner | Due Date | Priority |
|
|
2101
|
+
|--------|-------|----------|----------|
|
|
2102
|
+
| | | | P[0-3] |
|
|
2103
|
+
|
|
2104
|
+
## Lessons Learned
|
|
2105
|
+
|
|
2106
|
+
<!-- Key takeaways to share with the wider team -->
|
|
2107
|
+
`}]},5098:(e,t,a)=>{"use strict";a.d(t,{cn:()=>i});var s=a(9360),r=a(2646);function i(...e){return(0,r.m6)((0,s.W)(e))}},2026:(e,t,a)=>{"use strict";a.r(t),a.d(t,{$$typeof:()=>n,__esModule:()=>i,default:()=>o});var s=a(2334);let r=(0,s.createProxy)(String.raw`/Users/hoangnguyen/Documents/nextjs/vibedoc/src/app/(app)/layout.tsx`),{__esModule:i,$$typeof:n}=r;r.default;let o=(0,s.createProxy)(String.raw`/Users/hoangnguyen/Documents/nextjs/vibedoc/src/app/(app)/layout.tsx#default`)},7831:(e,t,a)=>{"use strict";a.r(t),a.d(t,{default:()=>i,metadata:()=>r});var s=a(9703);a(5260);let r={title:"VibeDoc",description:"Project intelligence for AI-assisted development"};function i({children:e}){return s.jsx("html",{lang:"en",className:"dark",children:s.jsx("body",{className:"bg-bg text-txt min-h-screen",children:e})})}},5260:()=>{}};
|