iArt.ai
AI 모션 그래픽 소프트웨어, 누구나 사용할 수 있는 After Effects 대안, 텍스트 프롬프트로 몇 분 안에 애니메이션·설명 영상 제작
Rockland 카운티에서 비즈니스·링크드인·팀·배우 헤드샷을 스튜디오 혹은 사무실에서 촬영합니다
Professional headshot photographer in Rockland County, NY. Business, LinkedIn, team and actor headshots in the studio or at your office in Spring Valley, Monsey, Nanuet, New City, Suffern and nearby.
미디어TypeScript · LuaGitHub @meilechb온라인운영자 미확인
써 보셨어요? 한 번만 눌러 주세요. 로그인은 필요 없어요.
아직 감지된 업데이트가 없습니다. GitHub 릴리스가 나오면 여기에 보입니다.
개인 계정의 공개 저장소 소유자는 GitHub로 로그인해 운영자를 확인하고 소개를 직접 관리할 수 있습니다. 관리자 승인은 필요하지 않습니다.
로그인한 뒤 확인 파일을 만들어 이 저장소의 기본 브랜치에 30분 안에 커밋해 주세요. 다른 브랜치나 포크의 파일은 인정하지 않습니다. 파일을 올린 뒤 아래에서 확인하면 관리자 승인 없이 관리할 수 있습니다. 자격을 유지하려면 파일을 남겨 두세요.
로그인이 필요하면 로그인 화면으로 이동합니다. 로그인 후 이곳으로 돌아와 원하는 확인 버튼을 다시 눌러 주세요.
프로젝트 폴더에서 /nomorevibe verify를 실행하면 소유권을 확인하고 소개를 직접 관리할 수 있습니다.
1분 만에 확인하기README 전체를 불러오는 중입니다. 아래는 저장된 발췌입니다.
Portfolio site plus a small studio back office: client proofing galleries with
access codes and per-photo notes, final delivery with downloads, order tracking,
and Stripe payments. Runs entirely on free tiers.README 전문 보기 ↗Portfolio site plus a small studio back office: client proofing galleries with access codes and per-photo notes, final delivery with downloads, order tracking, and Stripe payments. Runs entirely on free tiers.
| Area | Route | Notes |
|---|---|---|
| Public site | /, /portfolio, /pricing, /about, /contact | Portfolio grid with lightbox and category filter, packages from the database, contact form → inquiries |
| Client gallery | /g/[slug] | Access-code gate (30-day signed cookie). Proof galleries: favorites + notes per photo. Final galleries: per-photo and zip-all downloads. Photos stream through /api/photo/[id] after an access check |
| Payments | /pay/[orderId] | Client signs the agreement, pays the deposit (or in full), later the balance. Card form is embedded (Stripe Elements). Amounts always come from the database; /api/stripe/webhook and /pay/success both record payments (idempotent). Final galleries unlock downloads once the balance is paid. |
| Studio (admin) | /admin | Dashboard, inquiries → clients, orders with payment links, galleries (upload, reorder, codes, publish, reply to notes), portfolio manager, packages, Lightroom tokens |
| Lightroom API | /api/lr/* | Bearer-token API used by the Lightroom Classic publish plugin in lightroom/ |
| Auth | /login, /auth/signout | Single admin from ADMIN_EMAIL / ADMIN_PASSWORD_HASH |
Schema: db/schema.sql. Starter packages: db/seed.sql.
npm install
cp .env.example .env.local
DATABASE_URL in .env.local.npm run db:seed # runs db/schema.sql then db/seed.sql
(Or paste both files into Neon’s SQL Editor.)galleries, access Private → it adds BLOB_READ_WRITE_TOKEN to the projectportfolio, access Public → in Advanced Options set the env var prefix to PORTFOLIO so it adds PORTFOLIO_READ_WRITE_TOKEN (the code also accepts PORTFOLIO_BLOB_READ_WRITE_TOKEN)DATABASE_URL, NEXT_PUBLIC_SITE_URL, the admin and session values from step 3, and the Stripe keys from step 4.meilechbiller.com and www.meilechbiller.com and create the DNS records Vercel shows you.To run locally with the same stores: vercel env pull writes the tokens into .env.local.
npm run hash-password -- "a long strong password" # prints ADMIN_PASSWORD_HASH=...
openssl rand -base64 32 # SESSION_SECRET
Set ADMIN_EMAIL, ADMIN_PASSWORD_HASH and SESSION_SECRET locally and in Vercel. Sign in at /login.
STRIPE_SECRET_KEY and NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY (test keys until launch).https://meilechbiller.com/api/stripe/webhook with events
checkout.session.completed, checkout.session.async_payment_succeeded, checkout.session.async_payment_failed.
Copy the signing secret to STRIPE_WEBHOOK_SECRET.stripe listen --forward-to localhost:3000/api/stripe/webhook, test card 4242 4242 4242 4242.NEXT_PUBLIC_GA_MEASUREMENT_ID. The tag loads on the public site and client galleries only, never on /admin or /login.GA_API_SECRET. The server sends the conversion events with it: generate_lead when a contact inquiry is saved, purchase when a Stripe payment is recorded (transaction id = Checkout Session id), gallery_unlock when a client opens a gallery. The pricing page also sends book_cta_click from the browser.generate_lead and purchase as key events (Admin → Events).lightroom/meilechbiller.lrplugin is a Lightroom Classic publish service. One published collection = one client gallery.
/admin/integrations), create an API token, and download the plugin zip (or use the folder in this repo).meilechbiller.lrplugin.What happens: the plugin asks the site for a presigned upload URL per photo, PUTs the full-size JPEG straight to the private Blob store, then the site builds the 1600px preview and records the photo (/api/lr/*, bearer-token auth, hashes only in api_tokens). Re-publishing an edited photo replaces the files and keeps client notes. Client notes and favorites appear in Lightroom's Comments panel; favorites are tagged with the keyword “Client Favorite”. Removing a photo from the collection deletes it; deleting the collection archives the gallery.
After editing plugin files run node scripts/plugin-zip.mjs to refresh public/downloads/meilechbiller-lightroom.zip.
Everything about a person lives on their page under /admin/clients. Stages (New lead → Awaiting payment → Booked → Proofs out → Delivered) are worked out from the data; nothing is set by hand except Archive.
Portfolio images for the public site are managed at /admin/portfolio (featured images feed the home page hero and “Recent sessions”).
/api/photo/[id], which checks the gallery cookie (or the admin session) right before streaming the blob, and lets the browser cache with ETag revalidation.next/image handles thumbnails.mailto: links. Every attempt is listed in Admin → Emails. Resend or Postmark would automate “your proofs are ready” emails.src/lib/types.ts are hand-written to match db/schema.sql.$VAR inside .env* files, so secrets containing $ must be escaped as \$ locally. The generated password hash uses : separators to avoid this.npm run dev # start locally
npm run lint # eslint
npm run typecheck # tsc --noEmit
npm run build # production build
npm run db:migrate # apply db/schema.sql to DATABASE_URL (also runs automatically at the start of `npm run build`, so every Vercel deploy keeps the database schema current)
npm run db:seed # schema + starter packages
npm run hash-password -- "password"
Emails are optional. Without them the site still saves inquiries and shows mailto links in the admin.
RESEND_API_KEY in Vercel.EMAIL_FROM to an address on the verified domain, for example Meilech Biller <[email protected]>.INQUIRY_NOTIFY_EMAIL if new-inquiry alerts should go somewhere other than ADMIN_EMAIL.What gets sent: a notification to you and an automatic confirmation to the sender for every inquiry, the gallery link and access code when you press the button on a gallery, and a receipt when a client pays.
Service-area pages live at /headshots/<town> and are generated from src/lib/areas.ts. Business details for structured data (address, phone, social profiles) come from src/lib/site.ts; fill in the street address and phone when they are final. After the real domain is live: verify the site in Google Search Console and Bing Webmaster Tools, submit /sitemap.xml, and create a Google Business Profile with the same name, address and phone.