new-term-radar
신규 AI 용어를 매일 추적, X·Hugging Face·GitHub 등에서 모델·제품·레포 이름을 빠르게 수집
아직 감지된 업데이트가 없습니다. GitHub 릴리스가 나오면 여기에 보입니다.
개인 계정의 공개 저장소 소유자는 GitHub로 로그인해 운영자를 확인하고 소개를 직접 관리할 수 있습니다. 관리자 승인은 필요하지 않습니다.
로그인한 뒤 확인 파일을 만들어 이 저장소의 기본 브랜치에 30분 안에 커밋해 주세요. 다른 브랜치나 포크의 파일은 인정하지 않습니다. 파일을 올린 뒤 아래에서 확인하면 관리자 승인 없이 관리할 수 있습니다. 자격을 유지하려면 파일을 남겨 두세요.
로그인이 필요하면 로그인 화면으로 이동합니다. 로그인 후 이곳으로 돌아와 원하는 확인 버튼을 다시 눌러 주세요.
프로젝트 폴더에서 /nomorevibe verify를 실행하면 소유권을 확인하고 소개를 직접 관리할 수 있습니다.
1분 만에 확인하기Minimal multi-tenant cold-email campaign manager
저장소 README에서 가져옴
README 전체를 불러오는 중입니다. 아래는 저장된 발췌입니다.
A minimal, multi-tenant cold-email outreach tool. Each user connects their
own Gmail account, manages their own contacts, and sends their own
campaigns — fully isolated from every other user, enforced at the database
level, not just in application code.
Cold outreach tools either cost more than a small team can justify, or they
route your email through a shared sending service that tanks deliverability
the moment one tenant misbehaves. Coldloop takes a narrower, cheaper path:README 전문 보기 ↗A minimal, multi-tenant cold-email outreach tool. Each user connects their own Gmail account, manages their own contacts, and sends their own campaigns — fully isolated from every other user, enforced at the database level, not just in application code.
Cold outreach tools either cost more than a small team can justify, or they route your email through a shared sending service that tanks deliverability the moment one tenant misbehaves. Coldloop takes a narrower, cheaper path:
It was built for a small number of people (think: a handful of founders or a small sales team, not thousands of tenants) who want control over their own sending without building outreach infrastructure from scratch.
No automated scheduler (sending is always a manual click), no spam-folder tracking (Gmail's API doesn't expose that to senders — this repo doesn't pretend otherwise), no shared/team workspaces (every account is a fully separate tenant, even for people at the same company), no billing.
| Layer | Choice |
|---|---|
| Framework | Next.js 16 (App Router, Server Actions) |
| Database, Auth, Storage | Supabase (Postgres + Row Level Security) |
| Email sending & reply checking | Gmail API, per-user OAuth2 |
| AI email generation | Anthropic API (claude-opus-5) |
| Hosting | Vercel |
Nothing here is interchangeable casually — Row Level Security is what makes multi-tenancy safe, and the Gmail OAuth flow is what keeps sending per-user instead of shared.
Browser
│
▼
Next.js (Vercel)
│ │ │
▼ ▼ ▼
Supabase Gmail API Anthropic API
(auth, DB, (OAuth2 per user, (claude-opus-5,
storage, send + search no tools attached —
RLS) for replies) text-only, can't
produce images)
Every table in Postgres carries a user_id and a Row Level Security policy
that restricts it to auth.uid() = user_id — isolation is enforced by the
database itself, not by application-layer filtering, so a bug in a route
handler can't leak one user's data to another.
All tables live in the public schema. Five migrations, applied in order,
build this incrementally (supabase/migrations/0001–0004).
auth.users (Supabase-managed)
│
├──1:1── sender_profiles (onboarding info, one per user)
├──1:1── gmail_connections (one connected Gmail account per user)
├──1:N── contacts (a user's contact list)
├──1:N── campaigns (a user's named sending plans)
└──1:N── emails (every send attempt, draft or sent)
│ │
│ └──N:1── contacts (who it's to)
└───────────N:1── campaigns (which plan produced it, if any)
allowed_senders — global gate list, not user-owned (see below)
sender_profilesOne row per user — the identity and voice used to personalize every generated email.
| Column | Type | Notes |
|---|---|---|
user_id | uuid (PK) | References auth.users, cascades on delete |
company, sender_name | text | Required |
sender_title, product_description, target_segments, tone | text | Optional |
default_attachment_path, default_attachment_filename | text | Fallback attachment for every send unless overridden |
created_at, updated_at | timestamptz | updated_at auto-maintained by trigger |
contactsA user's contact list. One table, no per-campaign copies — the same contact can be targeted by multiple campaigns over time.
| Column | Type | Notes |
|---|---|---|
id | uuid (PK) | |
user_id | uuid | FK to auth.users |
name, email | text | Required |
company, personalization_notes | text | Optional, fed into templates/AI prompts |
status | enum | not_sent / sent / replied / bounced |
attachment_path, attachment_filename | text | Overrides the profile's default attachment |
status is what the automatic follow-up cadence reads: a contact with
sent status becomes eligible for the next sequence step 3 days after
their last email, unless replied (reply detection sets this and cancels
pending follow-ups) or bounced.
campaignsA named, reusable sending plan.
| Column | Type | Notes |
|---|---|---|
id | uuid (PK) | |
user_id | uuid | FK to auth.users |
name | text | |
objective | enum | initial / followup1 / followup2 — which template/stage this campaign targets |
generation_mode | text | template (free, deterministic) or ai (Claude-generated) |
ai_prompt | text | The instructions Claude writes from, when generation_mode = 'ai' |
attachment_path, attachment_filename | text | Campaign-level attachment |
max_send_count | integer | Cumulative cap across the campaign's whole lifetime, even if prepared/sent more than once |
emailsEvery send attempt — draft, sent, failed, or canceled. This is the audit log and the queue at the same time.
| Column | Type | Notes |
|---|---|---|
id | uuid (PK) | |
user_id | uuid | FK to auth.users |
contact_id | uuid | FK to contacts, cascades on delete |
campaign_id | uuid | FK to campaigns, nullable, on delete set null |
sequence_step | enum | initial / followup1 / followup2 |
subject, body | text | The actual generated content |
status | enum | draft / sent / failed / canceled |
sent_at | timestamptz | Null until actually sent |
attachment_filename | text | What was attached at send time (recorded independently of the source attachment, for history) |
A row is created as draft when a campaign batch is prepared, edited
in place on the Review page, and only becomes sent (or failed) when
the user clicks "Confirm and send." canceled is set automatically if the
contact replies while a draft is still pending.
gmail_connectionsOne connected Gmail account per user.
| Column | Type | Notes |
|---|---|---|
user_id | uuid (PK) | FK to auth.users |
gmail_address | text | The connected account's address |
encrypted_access_token, encrypted_refresh_token | text | AES-256-GCM encrypted at the application layer before storage — never stored in plaintext |
token_expires_at | timestamptz |
allowed_sendersA global gate list — not user-owned data, no user_id column. Until
Google's OAuth verification is complete for this app, only pre-approved
Google test users can actually authorize Gmail sending; this table mirrors
that list so the app can gate the "Connect Gmail" button without a second
Google API round-trip. A user may only query whether their own email is
on the list; only the service role can write to it.
A private Supabase Storage bucket, attachments, with one folder per
user ({user_id}/profile/, {user_id}/contacts/, {user_id}/campaigns/).
Row Level Security on storage.objects restricts each user to their own
folder.
src/
app/
(app)/ # everything behind the sidebar shell (auth required)
layout.tsx # shared shell: sidebar + top bar, one auth check
dashboard/ # onboarding checklist, Gmail connect, reply check
onboarding/ # sender profile form
contacts/ # add contact (form or CSV), contacts table
campaigns/ # list, create, and per-campaign detail/prepare
review/ # edit/discard/regenerate drafts, confirm & send
api/gmail/ # OAuth connect + callback route handlers
auth/callback/ # Supabase Auth magic-link/OAuth callback
login/ # Supabase Auth UI (outside the shell)
components/
app-shell/ # sidebar, top bar, user menu
status-badge.tsx # colored pills for contact/campaign status
file-input-button.tsx
lib/
ai/ # Claude email generation
emails/ # template rendering + follow-up eligibility logic
gmail/ # OAuth client, token encryption, send, reply search
storage/ # attachment upload/download
supabase/ # server/browser clients, generated DB types
ui/ # shared button style constants
supabase/
migrations/ # schema, in order — see Database schema above
supabase login
supabase link --project-ref <your-project-ref>
supabase db push
This applies all four migrations in order, including the Storage bucket
and its RLS policies.gmail.send, gmail.readonly, userinfo.email under Data Access, and
add your own email (and anyone else testing) as a test user under
Audience — this app requests sensitive scopes that need Google
verification for public use, so it stays in Testing mode until that's
submitted separately.localhost during development:
https://<your-domain>/api/gmail/callback and
http://localhost:3001/api/gmail/callback.NEXT_PUBLIC_SUPABASE_URL=
NEXT_PUBLIC_SUPABASE_ANON_KEY=
GOOGLE_CLIENT_ID=
GOOGLE_CLIENT_SECRET=
GMAIL_TOKEN_ENCRYPTION_KEY= # openssl rand -base64 32
ANTHROPIC_API_KEY= # optional
npm install
npm run dev
Connect the repo to Vercel and set the same environment variables there
(Production, Preview, and Development). Update the Google OAuth redirect
URI and Supabase's Auth → URL Configuration → Site URL to match your
production domain before inviting real users — both default to
localhost and will silently misroute confirmation emails and OAuth
callbacks otherwise.
Until Google verification is complete, add yourself (and anyone else testing) to both the Google Cloud test users list above and the database gate:
insert into allowed_senders (email) values ('[email protected]');