new-term-radar
신규 AI 용어를 매일 추적, X·Hugging Face·GitHub 등에서 모델·제품·레포 이름을 빠르게 수집
브랜드를 탑재하면 전체 마케팅 운영체계가 브랜드 형태로 작동합니다 분석·코호트·캠페인 캘린더·메일·광고·랜딩페이지 제공
A lifecycle-marketing operating system. Onboard a brand and the whole suite runs as that brand: analytics, cohorts, a rolling campaign calendar, and generated mailers, ads and landing pages.
마케팅JavaScript · HTMLGitHub @Anchit-AI-Hustle온라인운영자 미확인
써 보셨어요? 한 번만 눌러 주세요. 로그인은 필요 없어요.
개인 계정의 공개 저장소 소유자는 GitHub로 로그인해 운영자를 확인하고 소개를 직접 관리할 수 있습니다. 관리자 승인은 필요하지 않습니다.
로그인한 뒤 확인 파일을 만들어 이 저장소의 기본 브랜치에 30분 안에 커밋해 주세요. 다른 브랜치나 포크의 파일은 인정하지 않습니다. 파일을 올린 뒤 아래에서 확인하면 관리자 승인 없이 관리할 수 있습니다. 자격을 유지하려면 파일을 남겨 두세요.
로그인이 필요하면 로그인 화면으로 이동합니다. 로그인 후 이곳으로 돌아와 원하는 확인 버튼을 다시 눌러 주세요.
프로젝트 폴더에서 /nomorevibe verify를 실행하면 소유권을 확인하고 소개를 직접 관리할 수 있습니다.
1분 만에 확인하기Lifecycle OS — retention/lifecycle-marketing platform for any brand
저장소 README에서 가져옴
README 전체를 불러오는 중입니다. 아래는 저장된 발췌입니다.
A universal brand platform for lifecycle and growth marketing. Any signed-in
operator onboards their own brand, and the whole application re-skins and
re-scopes to it: its palette, its typography, its voice, its catalogue, its
competitors, its connected platforms and its data.
Deployed as a single Vercel project (no framework, outputDirectory: ".").
KNICKGASM is tenant zero — the brand the repo ships with, and one tenant among
many, not a hardcoded owner.README 전문 보기 ↗A universal brand platform for lifecycle and growth marketing. Any signed-in operator onboards their own brand, and the whole application re-skins and re-scopes to it: its palette, its typography, its voice, its catalogue, its competitors, its connected platforms and its data.
Deployed as a single Vercel project (no framework, outputDirectory: ".").
KNICKGASM is tenant zero — the brand the repo ships with, and one tenant among
many, not a hardcoded owner.
This README was rewritten on 2026-08-19. The previous one still described a three-stage single-brand tool ("Data Analysis → Calendar → Mailer Studio"), said automatic sending was not included, and named the palette by hues it does not contain. All three had stopped being true. If something here looks stale,
CLAUDE.mdis the living project memory and wins.
Lifecycle marketing needs a constant stream of assets — mailers, ads and landing pages, one per cohort per market per week — and every one has to be on-brand and factually correct.
Generative tools make the first half fast and the second half dangerous. Asked for a mailer, they return a convincing one containing a price nobody set, a rating nobody earned, a review nobody wrote and a claim nobody approved. It reads perfectly, which is exactly why it ships. Run more than one brand and the same fluency quietly puts one brand's products, colours and copy inside another brand's campaign.
These are not typos. An invented rating is an advertising-standards exposure. Another company's product claim under your name is worse. Both are discovered after the send, by someone else.
So the platform is built the other way round: a fact it does not have stays missing and says so, and one brand's data cannot reach another brand's workspace — not as a policy someone has to follow, but because the code path does not exist. Every such claim is held by a test or a gate:
| Claim | Enforced by |
|---|---|
| No fact is invented to fill a gap | [DATA REQUIRED BEFORE LAUNCH: …] markers; gateProof() strips unsourced proof |
| One brand's assets never appear under another | npm run test:isolation, tests/brand-catalog-scope.spec.js |
| No foreign brand name or figure in the tree | npm run check:foreign:ci |
| Every asset is built to its own medium's rules | api/_shared/asset-contracts.js, tests/generation-quality.spec.js |
| A copyable prompt says what it returns | tests/asset-vs-element-prompts.spec.js |
| The right campaign reaches the right cohort | tests/brain-cohort-planning.spec.js |
| Generation cites real results, or states it has none | tests/creative-evidence.spec.js |
┌──────────────────────────────────────────────────────────────┐
│ /onboarding — the first screen. A brand, or a starter one. │
└──────────────────────────────┬───────────────────────────────┘
│ brand_workspaces + RLS
┌───────────────────────────────────┼───────────────────────────────────┐
│ │ │
▼ ▼ ▼
UNDERSTAND CREATE SEND
analytics, cohorts, calendar, mailers, ads, preflight → dispatch
competitors, journey landing pages, social, → adapters → webhooks
attribution, ad findings video, logo briefs deliverability, warmup
Everything is scoped to the active brand. A workspace with nothing connected gets honest empty states and demo examples from invented brands, never another tenant's data.
| Document | What it covers |
|---|---|
CLAUDE.md | The living project memory. Architecture decisions, standing rules, and why each exists. Read this first. |
DEVELOPMENT.md | How it is built: the 12-function cap, the mailer pipeline, the provider cascade, the data layer. |
docs/universal-brand-platform.md | The multi-tenant brand layer end to end. |
docs/publishing-and-deliverability.md | The send pipeline and the gate in front of it. |
docs/campaign-orchestration-master-spec.md | The standing operating contract for all campaign and creative generation. |
docs/asset-contracts.md | How each asset type is built to its own medium's rules, and checked. |
docs/asset-and-element-prompts.md | Why a prompt that returns a photograph is not the prompt that returns the mailer. |
docs/creative-evidence.md | How generation is grounded in what actually worked, without inventing a result. |
These are not aspirations. Each is enforced somewhere, and the enforcement is named so you can check it.
Zero fabrication. No product fact, price, URL, image, rating, review, claim,
segment size or performance figure is ever invented. A missing value is written
as [DATA REQUIRED BEFORE LAUNCH: field, product, region] and rendered as that
marker, because a gap that silently vanishes reads as a design choice.
One brand's assets come from that brand. brand-catalog-server.js is the
only place the server decides whose products these are, and the answer is the
workspace's own catalogue or no asset at all. There is no third option where
another brand's photo renders under a caveat. Gate: npm run test:isolation.
A check that could not run is never a pass. The deliverability preflight
returns warn, never pass, for anything it could not inspect. A refused
blocklist query is not "clean"; a DNS lookup that timed out is excluded from the
denominator rather than scored zero.
Nothing leaves without three switches. LIVE_CONNECTORS=on repo-wide, plus
per-workspace publishing, plus a per-platform write flag for the guarded ones.
Miss one and the job builds the exact request and stops, showing it.
Every feature costs credits, and a missing price throws. credit-catalog.js
is the single source; a feature key absent from it raises rather than running
free.
Twelve serverless functions, permanently. Vercel Hobby caps them there.
Logic lives in api/_shared/ (excluded from the count) and is mounted on
existing routers by ?action= / ?op=. A CI step fails the build if the count
moves.
api/ 12 serverless functions, and no more
_shared/ all real logic (not counted against the cap)
adapters/ Meta, Google Ads, Klaviyo, WebEngage, CRM hooks
data/brands/ tenant zero + the starter preset library
scripts/ build tools, generators, guards
tests/ ~750 Playwright tests
docs/ architecture, specs, runbooks
*.html self-contained pages sharing auth.js + brand-context.js
npm run build # build the product catalogue (runs at deploy)
npm test # the Playwright suite
npm run verify # every CI gate, in one command — run before pushing
npm run brand:sync # propagate tenant zero into theme.css / CLAUDE.md / seed
npm run brand:check # fail on brand drift
npm run brand:presets # regenerate the starter brand library
npm run test:isolation # no cross-brand content in generated assets
npm run attribution # order attribution from the store's own records
npm run verify exists because several gates ship in two forms: check:foreign
reports and always exits 0, while check:foreign:ci passes --fail. Reading
the exit code of the reporting variant is how a real finding once reached main.
Set in Vercel, never in the repo. Full list in .env.example.
| Group | Variables |
|---|---|
| Text models | OPENAI_API_KEY (+_2/_3), ANTHROPIC_API_KEY, GEMINI_API_KEY, XAI_API_KEY, GROQ_API_KEY, CEREBRAS_API_KEY |
| Storage | SUPABASE_URL, SUPABASE_ANON_KEY, SUPABASE_SERVICE_ROLE_KEY |
| Per-workspace secrets | CONNECTION_SECRET_KEY (32 hex bytes). Without it a key save is refused, not stored in the clear. |
| Sending | LIVE_CONNECTORS, <PLATFORM>_ALLOW_WRITES |
| Cron | CRON_SECRET |
| Buying credits (India) | RAZORPAY_KEY_ID, RAZORPAY_KEY_SECRET, RAZORPAY_WEBHOOK_SECRET, plus an INR price per pack in credit_pack_prices or CREDIT_PACK_PRICES |
A workspace brings its own platform credentials and its own model keys, which
reach llm.js through an AsyncLocalStorage request scope — a module-level
variable would leak keys across concurrent requests.
A pack priced in rupees is paid through Razorpay Standard Checkout as a one-time
order (api/_shared/razorpay-credits.js, on
/api/public-config?action=credits). The flow:
op=rzp-order (signed in). The server reads the pack's price from the
price list, never from the request; it must be INR and at least ₹1. It
records a pending row in credit_orders (provider = 'razorpay'), creates
the Razorpay order (POST /v1/orders, receipt ≤ 40 chars, notes
{wallet, pack, credits}) and stores its id in provider_ref. It answers
{keyId, orderId, amount, currency, pack}.credits.js Credits.buy) loads
checkout.razorpay.com/v1/checkout.js on tap and opens it with that order,
redirect: true and a callback_url, because phones and in-app browsers
block the bank's popup. Closing it or a declined card says nothing was
charged.op=rzp-verify (the checkout handler, signed in), op=rzp-callback (the
redirect's form POST, answered 303 /credits#paid or #unpaid) or
op=rzp-webhook (order.paid / payment.captured, signed with
RAZORPAY_WEBHOOK_SECRET over the raw body). Verify and callback check
HMAC-SHA256(order_id|payment_id, RAZORPAY_KEY_SECRET) in constant time,
then GET /v1/payments/{id} for the same order, the same amount in INR and
captured (an authorized payment is captured). The credits move once:
credit_fulfil_order() is a compare-and-set on pending, the payment id
replaces the order id in provider_ref, and a unique index
(20261024200000_razorpay_payment_once.sql) means one payment id can mark
one order paid, ever. The balance updates through Supabase Realtime.The webhook is created once per deployment in the Razorpay dashboard or with
POST /v1/webhooks (url, secret, active: true, events order.paid and
payment.captured). Test with card 4100 2800 0000 1007, any future expiry, CVV
123, contact 9000090000, then Success on the demo bank page. Gated by
tests/razorpay-credits-executed.spec.js and tests/razorpay-credits-page.spec.js.
Source of truth is data/brands/_default.json. Run
npm run brand:sync after editing it; npm run brand:check fails the build on
drift.
Colours are named by role, not by hue, because the active brand supplies its own palette and any hue word is wrong for almost every tenant:
| Role | Value |
|---|---|
| primary | #D0473E |
| accent | #6A33D8 |
| ink | #111111 |
| surface | #FFFFFF |
Headings Montserrat, body Instrument Sans. No em or en dashes in output copy
(scrubDashes() enforces it). Banned phrases and the six verifiable claims live
in the brand record and are enforced, not suggested.
main deploys to production automatically. To deploy by hand:
npm run verify && npm run build && vercel --prod
The OS ships as one installable PWA plus Android/iOS Capacitor shells
(android/, ios/, mobile/). The shells render the live deployment, so every
web deploy is also a mobile release. Builds are published by the Mobile
Builds workflow to the mobile-latest release tag.
Run locally, not on Vercel:
ingest/ — Matrixify / Shopify Analytics / Klaviyo / WebEngage into DuckDB,
then sync_to_supabase.py.mailer_system/ — Python campaign trigger engine (thresholds in
targets.json).marketing_automation/ — React + Vite + Express campaign compiler.snowflake-streamlit-app is a permanently separate distribution — the
Streamlit-in-Snowflake build, which reads warehouse tables directly with no
Vercel and no Supabase. It must never be merged into main, and a required
check (.github/workflows/protect-main-from-sis.yml) fails any PR that tries.
docs/PRD.md| Product requirements and history. |