Nicholai b20db98051
Some checks failed
CI / build-and-test (pull_request) Failing after 1m19s
feat(ci,flags,ops): ship end-to-end CI, feature-flag framework, gated surfaces, and ops docs
CI (.gitea/workflows/ci.yaml): lint → typecheck → vitest w/ coverage → OpenNext build → preview smoke → bundle-size budgets; Node 20; npm ci; artifacts; safe env; D1 dry-run scaffold.

Budgets: add scripts/budgets.mjs; TOTAL_STATIC_MAX_BYTES and MAX_ASSET_BYTES thresholds; report top offenders; fail on breach; README CI section.

Flags: add lib/flags.ts with typed booleans and safe defaults (ADMIN_ENABLED, ARTISTS_MODULE_ENABLED, UPLOADS_ADMIN_ENABLED, BOOKING_ENABLED, PUBLIC_APPOINTMENT_REQUESTS_ENABLED, REFERENCE_UPLOADS_PUBLIC_ENABLED, DEPOSITS_ENABLED, PUBLIC_DB_ARTISTS_ENABLED, ADVANCED_NAV_SCROLL_ANIMATIONS_ENABLED, STRICT_CI_GATES_ENABLED, ISR_CACHE_R2_ENABLED); robust parsing; client provider; unit tests.

Wiring: gate Admin shell and admin write APIs (503 JSON on uploads and artists writes); disable booking submit and short-circuit booking mutations when off; render static Hero/Artists when advanced animations off; tests for UI and API guards.

Ops: expand docs/prd/rollback-strategy.md with “Feature Flags Operations,” Cloudflare Dashboard and wrangler.toml steps, preview simulation, incident playbook, and post-toggle smoke checklist.

Release: add docs/releases/2025-09-19-feature-flags-rollout.md with last-good commit, preview/production flag matrices, rollback notes, and smoke results; link from rollback doc.

Chore: fix TS issues (gift-cards boolean handling, Lenis options, tailwind darkMode), remove next-on-pages peer conflict, update package.json scripts, configure Gitea act_runner label, open draft PR to trigger CI.

Refs: CI-1, FF-1, FF-2, FF-3, OPS-1
Impact: defaults preserve current behavior; no runtime changes unless flags flipped
2025-09-19 21:33:09 -06:00

1 line
8.2 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

exports.id=5593,exports.ids=[5593],exports.modules={61816:(e,s,r)=>{Promise.resolve().then(r.bind(r,29343))},29343:(e,s,r)=>{"use strict";r.d(s,{AdminSidebar:()=>_});var n,i,a=r(97247),t=r(79906),l=r(34178),o=r(19898),c=r(56460),d=r(57989),m=r(72465),N=r(50820),E=r(35216),u=r(69964),x=r(17316),h=r(19400),I=r(58053),g=r(25008);(function(e){e.SUPER_ADMIN="SUPER_ADMIN",e.SHOP_ADMIN="SHOP_ADMIN",e.ARTIST="ARTIST",e.CLIENT="CLIENT"})(n||(n={})),function(e){e.PENDING="PENDING",e.CONFIRMED="CONFIRMED",e.IN_PROGRESS="IN_PROGRESS",e.COMPLETED="COMPLETED",e.CANCELLED="CANCELLED"}(i||(i={}));let f=[{name:"Dashboard",href:"/admin",icon:c.Z,roles:[n.SHOP_ADMIN,n.SUPER_ADMIN]},{name:"Artists",href:"/admin/artists",icon:d.Z,roles:[n.SHOP_ADMIN,n.SUPER_ADMIN]},{name:"Portfolio",href:"/admin/portfolio",icon:m.Z,roles:[n.SHOP_ADMIN,n.SUPER_ADMIN]},{name:"Calendar",href:"/admin/calendar",icon:N.Z,roles:[n.SHOP_ADMIN,n.SUPER_ADMIN]},{name:"Analytics",href:"/admin/analytics",icon:E.Z,roles:[n.SHOP_ADMIN,n.SUPER_ADMIN]},{name:"File Manager",href:"/admin/uploads",icon:u.Z,roles:[n.SHOP_ADMIN,n.SUPER_ADMIN]},{name:"Settings",href:"/admin/settings",icon:x.Z,roles:[n.SHOP_ADMIN,n.SUPER_ADMIN]}];function _({user:e}){let s=(0,l.usePathname)(),r=f.filter(s=>s.roles.includes(e.role)),n=async()=>{await (0,o.signOut)({callbackUrl:"/"})};return(0,a.jsxs)("div",{className:"flex flex-col w-64 bg-white shadow-lg",children:[a.jsx("div",{className:"flex items-center justify-center h-16 px-4 border-b border-gray-200",children:(0,a.jsxs)(t.default,{href:"/",className:"flex items-center space-x-2",children:[a.jsx("div",{className:"w-8 h-8 bg-black rounded-md flex items-center justify-center",children:a.jsx("span",{className:"text-white font-bold text-sm",children:"U"})}),a.jsx("span",{className:"text-xl font-bold text-gray-900",children:"United Admin"})]})}),a.jsx("nav",{className:"flex-1 px-4 py-6 space-y-2",children:r.map(e=>{let r=s===e.href,n=e.icon;return(0,a.jsxs)(t.default,{href:e.href,className:(0,g.cn)("flex items-center px-3 py-2 text-sm font-medium rounded-md transition-colors",r?"bg-gray-100 text-gray-900":"text-gray-600 hover:bg-gray-50 hover:text-gray-900"),children:[a.jsx(n,{className:"w-5 h-5 mr-3"}),e.name]},e.name)})}),(0,a.jsxs)("div",{className:"border-t border-gray-200 p-4",children:[(0,a.jsxs)("div",{className:"flex items-center space-x-3 mb-4",children:[a.jsx("div",{className:"w-10 h-10 bg-gray-300 rounded-full flex items-center justify-center",children:e.image?a.jsx("img",{src:e.image,alt:e.name,className:"w-10 h-10 rounded-full"}):a.jsx("span",{className:"text-sm font-medium text-gray-600",children:e.name.charAt(0).toUpperCase()})}),(0,a.jsxs)("div",{className:"flex-1 min-w-0",children:[a.jsx("p",{className:"text-sm font-medium text-gray-900 truncate",children:e.name}),a.jsx("p",{className:"text-xs text-gray-500 truncate",children:e.role.replace("_"," ").toLowerCase()})]})]}),(0,a.jsxs)(I.z,{variant:"outline",size:"sm",onClick:n,className:"w-full justify-start",children:[a.jsx(h.Z,{className:"w-4 h-4 mr-2"}),"Sign Out"]})]})]})}},49446:(e,s,r)=>{"use strict";r.r(s),r.d(s,{default:()=>d});var n=r(72051),i=r(41288),a=r(4128),t=r(33897),l=r(74725);let o=(0,r(45347).createProxy)(String.raw`/home/Nicholai/Documents/Dev/united_v03/united-tattoo/united-tattoo/components/admin/sidebar.tsx#AdminSidebar`);var c=r(93470);async function d({children:e}){if(!c.vU.ADMIN_ENABLED)return n.jsx("div",{className:"min-h-screen flex items-center justify-center p-8",children:(0,n.jsxs)("div",{className:"max-w-md text-center space-y-4",children:[n.jsx("h1",{className:"text-2xl font-semibold",children:"Admin temporarily unavailable"}),n.jsx("p",{className:"text-muted-foreground",children:"Were performing maintenance or addressing an incident. Please try again later."})]})});let s=await (0,a.getServerSession)(t.Lz);return s||(0,i.redirect)("/auth/signin"),s.user.role!==l.i.SHOP_ADMIN&&s.user.role!==l.i.SUPER_ADMIN&&(0,i.redirect)("/unauthorized"),(0,n.jsxs)("div",{className:"flex h-screen bg-gray-100",children:[n.jsx(o,{user:s.user}),(0,n.jsxs)("div",{className:"flex-1 flex flex-col overflow-hidden",children:[n.jsx("header",{className:"bg-white shadow-sm border-b border-gray-200",children:(0,n.jsxs)("div",{className:"flex items-center justify-between px-6 py-4",children:[n.jsx("h1",{className:"text-2xl font-semibold text-gray-900",children:"Admin Dashboard"}),(0,n.jsxs)("div",{className:"flex items-center space-x-4",children:[(0,n.jsxs)("span",{className:"text-sm text-gray-600",children:["Welcome, ",s.user.name]}),n.jsx("div",{className:"w-8 h-8 bg-gray-300 rounded-full flex items-center justify-center",children:s.user.image?n.jsx("img",{src:s.user.image,alt:s.user.name,className:"w-8 h-8 rounded-full"}):n.jsx("span",{className:"text-sm font-medium text-gray-600",children:s.user.name.charAt(0).toUpperCase()})})]})]})}),n.jsx("main",{className:"flex-1 overflow-y-auto p-6",children:e})]})]})}},33897:(e,s,r)=>{"use strict";r.d(s,{Lz:()=>d,mk:()=>N});var n=r(22571),i=r(43016),a=r(76214),t=r(29628);let l=t.z.object({DATABASE_URL:t.z.string().url(),DIRECT_URL:t.z.string().url().optional(),NEXTAUTH_URL:t.z.string().url(),NEXTAUTH_SECRET:t.z.string().min(1),GOOGLE_CLIENT_ID:t.z.string().optional(),GOOGLE_CLIENT_SECRET:t.z.string().optional(),GITHUB_CLIENT_ID:t.z.string().optional(),GITHUB_CLIENT_SECRET:t.z.string().optional(),AWS_ACCESS_KEY_ID:t.z.string().min(1),AWS_SECRET_ACCESS_KEY:t.z.string().min(1),AWS_REGION:t.z.string().min(1),AWS_BUCKET_NAME:t.z.string().min(1),AWS_ENDPOINT_URL:t.z.string().url().optional(),NODE_ENV:t.z.enum(["development","production","test"]).default("development"),SMTP_HOST:t.z.string().optional(),SMTP_PORT:t.z.string().optional(),SMTP_USER:t.z.string().optional(),SMTP_PASSWORD:t.z.string().optional(),VERCEL_ANALYTICS_ID:t.z.string().optional()}),o=function(){try{return l.parse(process.env)}catch(e){if(e instanceof t.z.ZodError){let s=e.errors.map(e=>e.path.join(".")).join(", ");throw Error(`Missing or invalid environment variables: ${s}`)}throw e}}();var c=r(74725);let d={providers:[(0,a.Z)({name:"credentials",credentials:{email:{label:"Email",type:"email"},password:{label:"Password",type:"password"}},async authorize(e){if(console.log("Authorize called with:",e),!e?.email||!e?.password)return console.log("Missing email or password"),null;if(console.log("Email received:",e.email),console.log("Password received:",e.password?"***":"empty"),"nicholai@biohazardvfx.com"===e.email)return console.log("Admin user recognized!"),{id:"admin-nicholai",email:"nicholai@biohazardvfx.com",name:"Nicholai",role:c.i.SUPER_ADMIN};console.log("Using fallback user creation");let s={id:"dev-user-"+Date.now(),email:e.email,name:e.email.split("@")[0],role:c.i.SUPER_ADMIN};return console.log("Created user:",s),s}}),...o.GOOGLE_CLIENT_ID&&o.GOOGLE_CLIENT_SECRET?[(0,n.Z)({clientId:o.GOOGLE_CLIENT_ID,clientSecret:o.GOOGLE_CLIENT_SECRET})]:[],...o.GITHUB_CLIENT_ID&&o.GITHUB_CLIENT_SECRET?[(0,i.Z)({clientId:o.GITHUB_CLIENT_ID,clientSecret:o.GITHUB_CLIENT_SECRET})]:[]],session:{strategy:"jwt",maxAge:2592e3},callbacks:{jwt:async({token:e,user:s,account:r})=>(s&&(e.role=s.role||c.i.CLIENT,e.userId=s.id),e),session:async({session:e,token:s})=>(s&&(e.user.id=s.userId,e.user.role=s.role),e),signIn:async({user:e,account:s,profile:r})=>!0,redirect:async({url:e,baseUrl:s})=>e.startsWith("/")?`${s}${e}`:new URL(e).origin===s?e:`${s}/admin`},pages:{signIn:"/auth/signin",error:"/auth/error"},events:{async signIn({user:e,account:s,profile:r,isNewUser:n}){console.log(`User ${e.email} signed in`)},async signOut({session:e,token:s}){console.log("User signed out")}},debug:"development"===o.NODE_ENV};async function m(){let{getServerSession:e}=await r.e(4128).then(r.bind(r,4128));return e(d)}async function N(e){let s=await m();if(!s)throw Error("Authentication required");if(e&&!function(e,s){let r={[c.i.CLIENT]:0,[c.i.ARTIST]:1,[c.i.SHOP_ADMIN]:2,[c.i.SUPER_ADMIN]:3};return r[e]>=r[s]}(s.user.role,e))throw Error("Insufficient permissions");return s}},74725:(e,s,r)=>{"use strict";var n,i;r.d(s,{Z:()=>i,i:()=>n}),function(e){e.SUPER_ADMIN="SUPER_ADMIN",e.SHOP_ADMIN="SHOP_ADMIN",e.ARTIST="ARTIST",e.CLIENT="CLIENT"}(n||(n={})),function(e){e.PENDING="PENDING",e.CONFIRMED="CONFIRMED",e.IN_PROGRESS="IN_PROGRESS",e.COMPLETED="COMPLETED",e.CANCELLED="CANCELLED"}(i||(i={}))}};