본문으로 건너뛰기
cccskills
무료GitHub에 공개

feature-schema

Use when a new feature needs a table, column or capability — evolving the schema so the new thing joins the permission, audit and RLS contract instead of sitting outside it. Covers the DDL/DML split, the resource/capability wiring, and the self-verifying migration.

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

연동 도구SupabasePostgreSQL
설치 방법 보기

포함된 파일(1)

  • SKILL.md5.6 KB

SKILL.md(원문)

설치하기 전에 에이전트에게 전달되는 지시 내용을 확인할 수 있습니다.

Adding a feature to the schema

The schema here is not a set of tables. It is a contract: every resource has a key, every key has capabilities, every write is authorized and audited in the same atomic step, and every table is reachable only through a policy. A new table that does not join that contract is not "a table without permissions yet" — it is a hole, and it will be found by someone who is not you.

This skill exists because joining the contract is mechanical, easy to half-do, and invisible when you get it wrong. A table with RLS enabled and no policy silently returns zero rows. A table with a policy and no resource_key cannot be granted to anyone. Both look fine until they do not.

Before writing anything

node scripts/sql-classify.mjs        # what tier does each migration sit in
ls supabase/migrations | tail -3     # the next number is the last + 1

Migrations are append-only and applied by hand, in order. Never edit an applied one — it already ran, so editing it changes nothing on any existing database and diverges you from every deployment that has it. If something is wrong, the fix is the next number.

The seven things a new table owes

Work through these in order. Each one is a question with a wrong answer that compiles.

1. Does it need to be a table at all? A setting is app_config. A secret is app_secrets (encrypted). A flag is feature_flags. Reach for a new table when you have rows that belong to someone and change over time.

2. What is its resource key? One short noun — blog, crm, payments. Add it to RESOURCE_KEYS in src/types/schema.ts in the same change, or the admin capability grid has a resource nobody can grant.

3. Which capabilities apply? view / create / edit / delete, plus publish when there is a published state. view is a floor — migration 075 made an acting capability require the view it depends on, so granting create without view now grants nothing. Seed grants for every existing role, including the ones that should get nothing: an absent row and an explicit allowed=false read differently to an operator looking at the grid.

4. RLS: enable it AND write policies. Enabling without a policy denies everything; Postgres will not warn you. Write USING for reads and WITH CHECK for writes — a USING-only policy lets a caller write a row they then cannot see.

5. Route writes through perform_action(). It authorizes and audits atomically, so no write path can produce a permission decision without also producing an audit row. A direct INSERT from application code bypasses both.

6. Split DDL from DML. The migration carries schema and any idempotent backfill it needs. Rows that make the system work go to seed/01_required.sql; starting values an admin will edit go to seed/02_defaults.sql. Company, product or content data goes in neither — it comes from the admin UI or the site-bootstrap skill. Run node scripts/sql-classify.mjs afterwards and confirm your migration lands in the tier you intended.

7. Verify inside the migration. End with a DO $verify$ block that asserts the thing you just claimed, and RAISE EXCEPTION if it is not true. Migration 075 checks that its own disclosure fix holds and that the private lookup is not reachable by authenticated. A migration that cannot fail at apply time is a migration you will trust for the wrong reasons.

The header is the deliverable

Every migration here opens by explaining the finding it closes, not what it does — the SQL already says what it does. Read 007_publish_capability_enforcement.sql for the shape. If you cannot articulate what was wrong before, the migration is not ready; you are guessing at a design rather than closing a gap.

Include what you checked and chose not to change. 075 records that every seeded role holding crm:create also holds crm:view, which is the fact that made a breaking change safe. Without it the next person has to rediscover it before they dare touch the policy.

Apply and prove

# never against production first
createdb scratch_test
for f in supabase/migrations/*.sql; do psql -v ON_ERROR_STOP=1 -d scratch_test -f "$f"; done
pnpm test:db          # permissions, RLS, PII
pnpm gen:e2e          # the permission-matrix invariants regenerate from the DB

pnpm test:db is not optional after a schema change. It is the only thing standing between a policy typo and a table that quietly returns everything to everyone.

Then hand off

A schema change is not finished when it applies. It is finished when:

  • pnpm test:db is green and you added a case that fails without your change
  • the feature has a screen, or the migration is queued in public_template_sync as ship-when-UI-exists
  • docs/PUBLIC_TEMPLATE.md says whether this crosses to the public template
  • work-units/session-state.json records it

Then use feature-testing to cover the surface you built on top.

Do not

  • Edit an applied migration.
  • Enable RLS without writing a policy in the same migration.
  • Grant an acting capability without view.
  • Seed company, product or content rows into a migration.
  • Write to a table from application code without going through perform_action().
  • Assume a policy works because the happy path works — the interesting case is the role that should be refused.

리뷰

아직 리뷰가 없습니다. 사용해 본 소감을 남겨 주세요.

댓글

로그인 없이 쓸 수 있습니다. 사용 후기, 질문, 작동하지 않은 환경 등을 편하게 남겨 주세요.

아직 댓글이 없습니다. 첫 댓글을 남겨 보세요.

보내면 바로 공개됩니다. 이메일 주소나 전화번호 같은 개인 정보는 쓰지 마세요. URL은 2개까지입니다.

0 / 1,000자

이 양식은 reCAPTCHA로 보호되며 Google 개인정보처리방침 및 서비스 약관이 적용됩니다.

같은 저장소의 스킬

brand

무료

Apply this site's visual identity — colours, type, logo files and fixed brand strings. Use for any page, component, social asset or document that should look like the site.

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

aryannema/vigyan-site-os22026년 10월 2일 업데이트

Use FIRST when someone asks for a new feature or a change to an existing one — before any schema, code or test. Works out what is actually being asked for, whether to build it or integrate a third party (Trustpilot, Stripe, Calendly and the like), where the data lives, who may do what, and what happens when the vendor is down. Produces a decision, then hands to feature-schema.

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

aryannema/vigyan-site-os22026년 10월 2일 업데이트

Use after building a feature — explore it in a real browser to find what nobody predicted, then turn each finding into a deterministic test that guards it forever. Covers the agentic pass, what to generate vs hand-write, and how to skip honestly when a capability is missing.

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

aryannema/vigyan-site-os22026년 10월 2일 업데이트

Publishing content or deploying site-os — what caches exist, what refreshes them, and how to prove a change is actually live. Use when publishing a post or product, launching a page, deploying, or when someone says a change "isn't showing".

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

aryannema/vigyan-site-os22026년 10월 2일 업데이트

Handling secrets, keys and credentials for site-os — reading vigyan-secrets.md safely, moving keys into app_secrets, rotating, and responding to an exposure. Use whenever a task touches a key, token, password, .env file, app_secrets, encryption, or the secrets document.

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

aryannema/vigyan-site-os22026년 10월 2일 업데이트

Audit a page or the whole yoursite site (or a new site) for indexing readiness — cache headers, sitemap, robots, canonical, JSON-LD, internal links — and check the publish pipeline (Cloudflare purge/warm, IndexNow, GSC, Bing). Use before/after publishing content or launching a site.

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

aryannema/vigyan-site-os22026년 10월 2일 업데이트

aryannema의 스킬 모두 보기

이 스킬의 문제 신고