getaura 0.0.0-stage → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (63) hide show
  1. package/README.md +25 -2
  2. package/dist/index.js +24230 -0
  3. package/dist/index.js.map +1 -0
  4. package/package.json +50 -4
  5. package/templates/README.md +94 -0
  6. package/templates/configs/env-example-header.txt +6 -0
  7. package/templates/configs/eslint.config.mjs +12 -0
  8. package/templates/configs/example.test.ts +21 -0
  9. package/templates/configs/husky-pre-commit +16 -0
  10. package/templates/configs/prettierignore +18 -0
  11. package/templates/configs/prettierrc.json +3 -0
  12. package/templates/configs/security-headers.md +41 -0
  13. package/templates/configs/vitest.config.ts +19 -0
  14. package/templates/docs/index.md +55 -0
  15. package/templates/github/dependabot.yml +25 -0
  16. package/templates/github/workflows/aura-weekly.yml +55 -0
  17. package/templates/github/workflows/aura.yml +90 -0
  18. package/templates/github/workflows/ci.yml +86 -0
  19. package/templates/guides/add-aura-key-to-github.md +34 -0
  20. package/templates/guides/github-security.md +63 -0
  21. package/templates/guides/install-github-cli.md +50 -0
  22. package/templates/guides/rotate-anthropic-key.md +33 -0
  23. package/templates/guides/rotate-aws-key.md +39 -0
  24. package/templates/guides/rotate-database-key.md +39 -0
  25. package/templates/guides/rotate-generic-key.md +37 -0
  26. package/templates/guides/rotate-github-token.md +36 -0
  27. package/templates/guides/rotate-google-key.md +45 -0
  28. package/templates/guides/rotate-openai-key.md +33 -0
  29. package/templates/guides/rotate-resend-key.md +32 -0
  30. package/templates/guides/rotate-sendgrid-key.md +32 -0
  31. package/templates/guides/rotate-slack-key.md +48 -0
  32. package/templates/guides/rotate-stripe-key.md +41 -0
  33. package/templates/guides/rotate-supabase-key.md +46 -0
  34. package/templates/guides/rotate-vercel-key.md +44 -0
  35. package/templates/guides/transfer-ownership.md +55 -0
  36. package/templates/pr/add-agent-rules.md +16 -0
  37. package/templates/pr/add-aura-workflow.md +18 -0
  38. package/templates/pr/add-brief.md +17 -0
  39. package/templates/pr/add-ci.md +16 -0
  40. package/templates/pr/add-env-example.md +18 -0
  41. package/templates/pr/add-linting.md +16 -0
  42. package/templates/pr/add-pre-commit.md +16 -0
  43. package/templates/pr/add-readme.md +16 -0
  44. package/templates/pr/add-security-headers.md +16 -0
  45. package/templates/pr/enable-dependency-updates.md +16 -0
  46. package/templates/pr/fix-vulnerable-deps.md +19 -0
  47. package/templates/pr/foundation.md +19 -0
  48. package/templates/pr/install-skills.md +18 -0
  49. package/templates/pr/move-misplaced-files.md +18 -0
  50. package/templates/pr/remove-dead-files.md +18 -0
  51. package/templates/pr/setup-testing.md +19 -0
  52. package/templates/pr/token-efficiency.md +18 -0
  53. package/templates/readme/README.md +73 -0
  54. package/templates/rules/agent-rules.md +43 -0
  55. package/templates/skills/aura/SKILL.md +76 -0
  56. package/templates/skills/database-migrations/SKILL.md +92 -0
  57. package/templates/skills/docs-and-readme/SKILL.md +40 -0
  58. package/templates/skills/error-handling/SKILL.md +79 -0
  59. package/templates/skills/folder-structure/SKILL.md +51 -0
  60. package/templates/skills/pre-launch-checklist/SKILL.md +60 -0
  61. package/templates/skills/secrets-and-env/SKILL.md +52 -0
  62. package/templates/skills/secure-api-routes/SKILL.md +92 -0
  63. package/templates/skills/writing-tests/SKILL.md +77 -0
@@ -0,0 +1,92 @@
1
+ ---
2
+ name: database-migrations
3
+ description: Use when creating or changing database tables, columns, views, functions or row level security policies in Supabase. Covers migration files, row level security, indexes and testing policies.
4
+ ---
5
+
6
+ # Database migrations
7
+
8
+ All database changes go through migration files in `supabase/migrations/`, committed to git. Never change the production schema by hand in the Supabase dashboard; the next deploy or a new environment won't have it.
9
+
10
+ ## Creating a migration
11
+
12
+ 1. Run `npx supabase migration new <short_name>` (for example `add_projects_table`). It creates `supabase/migrations/<timestamp>_<short_name>.sql`.
13
+ 2. Write the SQL in that file.
14
+ 3. Apply it locally with `npx supabase db reset` (rebuilds the local database from all migrations) or `npx supabase migration up`.
15
+ 4. Production gets it through `npx supabase db push` or the team's deploy pipeline. Ask the user before pushing to production.
16
+
17
+ Never edit a migration that has already been applied anywhere else. Write a new migration that makes the change.
18
+
19
+ ## Every table gets row level security
20
+
21
+ Supabase exposes tables in the `public` schema through its API. Without row level security (RLS), anyone with the public key can read and change every row.
22
+
23
+ ```sql
24
+ create table public.projects (
25
+ id uuid primary key default gen_random_uuid(),
26
+ owner_id uuid not null references auth.users (id) on delete cascade,
27
+ name text not null,
28
+ created_at timestamptz not null default now()
29
+ );
30
+
31
+ alter table public.projects enable row level security;
32
+
33
+ create policy "Owners can read their projects"
34
+ on public.projects for select to authenticated
35
+ using ((select auth.uid()) = owner_id);
36
+
37
+ create policy "Owners can create projects"
38
+ on public.projects for insert to authenticated
39
+ with check ((select auth.uid()) = owner_id);
40
+
41
+ create policy "Owners can update their projects"
42
+ on public.projects for update to authenticated
43
+ using ((select auth.uid()) = owner_id)
44
+ with check ((select auth.uid()) = owner_id);
45
+
46
+ create policy "Owners can delete their projects"
47
+ on public.projects for delete to authenticated
48
+ using ((select auth.uid()) = owner_id);
49
+
50
+ create index projects_owner_id_idx on public.projects (owner_id);
51
+ ```
52
+
53
+ Rules:
54
+ - `enable row level security` on every new table, in the same migration that creates it.
55
+ - Write explicit policies for each operation you allow. No policy means no access, which is the safe default.
56
+ - Wrap `auth.uid()` as `(select auth.uid())` so Postgres evaluates it once per query, not once per row.
57
+ - Add `to authenticated` (or `to anon` when truly public) so policies don't run for roles they don't apply to.
58
+ - Never use `using (true)` for writes. Use it for reads only when the data is meant to be public, and say so in a comment.
59
+ - Don't base policies on `user_metadata` in the JWT; users can change it.
60
+
61
+ ## Indexes
62
+
63
+ Add an index on every foreign key column and every column used in a policy (`owner_id`, `team_id`, `user_id`). Missing indexes make RLS slow as data grows.
64
+
65
+ ## Views and functions
66
+
67
+ - Create views with `with (security_invoker = true)` so they respect RLS.
68
+ - `security definer` functions bypass RLS. Avoid them unless needed; if you use one, set `set search_path = ''`, use fully qualified names, and keep it out of the exposed `public` schema when possible.
69
+
70
+ ## Keys
71
+
72
+ The service role key (`service_role` JWT or `sb_secret_...`) bypasses RLS. Use it only in server code, never in client components or `NEXT_PUBLIC_` variables. The browser uses the publishable or anon key, and RLS protects the data.
73
+
74
+ ## Storage
75
+
76
+ Storage buckets need policies too, on `storage.objects`. Scope them by bucket and by the owner's folder, for example `(storage.foldername(name))[1] = (select auth.uid())::text`.
77
+
78
+ ## Testing policies
79
+
80
+ After changing policies, check them:
81
+ - With pgTAP tests in `supabase/tests/` run by `npx supabase test db`, or
82
+ - In the local SQL editor, impersonating a user:
83
+
84
+ ```sql
85
+ begin;
86
+ set local role authenticated;
87
+ set local request.jwt.claims = '{"sub": "<some user uuid>"}';
88
+ select * from public.projects; -- should only return that user's rows
89
+ rollback;
90
+ ```
91
+
92
+ Test that a user can't read or change another user's rows, and that signed-out users get nothing.
@@ -0,0 +1,40 @@
1
+ ---
2
+ name: docs-and-readme
3
+ description: Use when a change affects how the app behaves, is set up, configured or deployed (new feature, new env var, new integration, new command), or when the work seems to contradict the product brief. Keeps README.md, docs/ and .aura/brief.md accurate.
4
+ ---
5
+
6
+ # Docs and README
7
+
8
+ Docs are how the user, future teammates and future coding agent sessions understand the project without reading all the code. Out-of-date docs are worse than none.
9
+
10
+ ## What to update
11
+
12
+ | You changed… | Update |
13
+ | --- | --- |
14
+ | Setup steps, scripts or prerequisites | `README.md` → Getting started and Commands |
15
+ | Added or renamed an environment variable | `.env.example` and `README.md` → Environment variables |
16
+ | Added a service or integration (Stripe, email, AI) | `docs/index.md` → Integrations, plus a short note in `docs/` if setup is involved |
17
+ | Data model or how parts fit together | `docs/index.md` → Architecture notes |
18
+ | Where code lives | `docs/index.md` → Where things live |
19
+ | Deployment or migrations process | `README.md` → Deployment |
20
+ | User-visible behaviour | `README.md` → What it does, if the summary changed |
21
+
22
+ Update docs in the same change as the code, not in a follow-up.
23
+
24
+ ## docs/index.md
25
+
26
+ This is the first file a coding agent reads. Keep it short: links and one-line facts, not essays. When you learn something about the codebase that would have saved you time (a non-obvious convention, where a key piece of logic lives, a gotcha), add one line to it.
27
+
28
+ ## The product brief
29
+
30
+ `.aura/brief.md` is the source of truth for what the product is, who it's for and what it does. Read it before planning a feature.
31
+
32
+ If the work you're asked to do contradicts the brief (a new audience, a different pricing model, a feature the brief rules out), stop and ask the user before continuing. If they confirm, update the brief in the same change. Never update the brief silently.
33
+
34
+ ## Writing style
35
+
36
+ - Plain language. The reader may be non-technical.
37
+ - Short sentences, active voice, sentence case headings.
38
+ - Exact commands in code blocks, using the project's package manager.
39
+ - Never include real secrets, keys, passwords or personal data, even as examples. Use placeholders like `sk_test_...`.
40
+ - Delete docs that no longer apply rather than leaving them stale.
@@ -0,0 +1,79 @@
1
+ ---
2
+ name: error-handling
3
+ description: Use when building pages, forms, data fetching, route handlers or server actions, or when something can fail (network, database, payments, AI calls). Covers user-facing error, loading and empty states and safe server-side logging.
4
+ ---
5
+
6
+ # Error handling
7
+
8
+ Things fail: networks drop, APIs time out, users submit bad data. The app should tell the user what happened in plain words, let them recover, and keep the details in the server logs.
9
+
10
+ ## Every screen has four states
11
+
12
+ For every page or component that loads data, handle:
13
+ 1. **Loading**: a skeleton or spinner.
14
+ 2. **Empty**: a helpful message and the next action ("No projects yet. Create your first one.").
15
+ 3. **Error**: a plain message and a way to retry.
16
+ 4. **Success**: the data.
17
+
18
+ ## Next.js special files
19
+
20
+ Add these per route segment where it makes sense, at least at the app root:
21
+
22
+ - `app/loading.tsx`: shown while the segment loads.
23
+ - `app/error.tsx`: catches errors in the segment. Must be a client component.
24
+ - `app/not-found.tsx`: shown when `notFound()` is called or no route matches.
25
+ - `app/global-error.tsx`: catches errors in the root layout. Must render its own `<html>` and `<body>`.
26
+
27
+ ```tsx
28
+ "use client";
29
+
30
+ export default function Error({ error, reset }: { error: Error & { digest?: string }; reset: () => void }) {
31
+ return (
32
+ <div role="alert">
33
+ <h2>Something went wrong</h2>
34
+ <p>Please try again. If it keeps happening, contact support.</p>
35
+ <button onClick={() => reset()}>Try again</button>
36
+ </div>
37
+ );
38
+ }
39
+ ```
40
+
41
+ Call `notFound()` from `next/navigation` when a record doesn't exist or the user can't see it.
42
+
43
+ ## Never leak internals
44
+
45
+ - Don't show stack traces, SQL errors, raw API error messages, file paths or IDs of other users to the user.
46
+ - Route handlers return a generic message and the right status code: 400 invalid input, 401 not signed in, 403 not allowed, 404 not found, 429 rate limited, 500 anything else.
47
+ - Never return `error.message` from a database or third-party call to the client.
48
+
49
+ ## Server actions and forms
50
+
51
+ Return expected errors as values instead of throwing, so the form can show them:
52
+
53
+ ```ts
54
+ "use server";
55
+
56
+ export async function createProject(_prev: unknown, formData: FormData) {
57
+ // check the user and validate input first (see the secure-api-routes skill)
58
+ const { error } = await saveProject(formData);
59
+ if (error) {
60
+ console.error("createProject failed", error);
61
+ return { ok: false, message: "Could not save the project. Please try again." };
62
+ }
63
+ return { ok: true, message: "Project created." };
64
+ }
65
+ ```
66
+
67
+ Show `message` with `useActionState`. Show field-level validation messages next to the fields. Disable the submit button while pending.
68
+
69
+ ## Logging
70
+
71
+ - Log unexpected errors on the server with `console.error("what failed", error)`. On Vercel they appear in the project's Logs.
72
+ - Include context (which action, which record id), never secrets, passwords, tokens or full card or personal data.
73
+ - If the project uses an error tracker such as Sentry, use it instead of only `console.error`.
74
+
75
+ ## External calls
76
+
77
+ - Wrap calls to Stripe, AI APIs, email providers and other services in `try`/`catch`.
78
+ - Set a timeout on slow calls (`AbortSignal.timeout(10_000)` with `fetch`).
79
+ - For payments and emails, make retries safe (Stripe idempotency keys, check before sending twice).
@@ -0,0 +1,51 @@
1
+ ---
2
+ name: folder-structure
3
+ description: Use when creating a new file or folder, deciding where code belongs, or when the user asks to tidy or reorganize the project. Describes the target layout for a Next.js App Router and Supabase project.
4
+ ---
5
+
6
+ # Folder structure
7
+
8
+ A predictable layout means the user and every agent session can find things without searching the whole repo.
9
+
10
+ ## Target layout
11
+
12
+ Projects use either the root layout or the `src/` layout. Check which one exists and stay with it. In the `src/` layout, everything below except `supabase/`, `e2e/`, `docs/` and `public/` lives inside `src/`.
13
+
14
+ ```
15
+ app/ Routes only: page.tsx, layout.tsx, route.ts, loading.tsx, error.tsx
16
+ (marketing)/ Route groups to organize routes without changing URLs
17
+ api/ Route handlers
18
+ components/
19
+ ui/ Generic building blocks (button, input, dialog)
20
+ <feature>/ Components for one feature (billing/, projects/)
21
+ lib/
22
+ supabase/ Supabase clients: client.ts (browser), server.ts (server), admin.ts (secret key, server only)
23
+ <feature>.ts Business logic, data access, integrations (stripe.ts, email.ts)
24
+ hooks/ React hooks (use-*.ts)
25
+ types/ Shared TypeScript types
26
+ supabase/
27
+ migrations/ Database migrations
28
+ tests/ Database policy tests
29
+ e2e/ Playwright end-to-end tests
30
+ docs/ Project docs, starting with docs/index.md
31
+ public/ Static files served as-is
32
+ ```
33
+
34
+ Unit tests sit next to the file they test (`lib/pricing.test.ts`) or in `tests/`. Follow whichever the repo already uses.
35
+
36
+ ## Rules for new code
37
+
38
+ - `app/` holds routes. Keep page files thin: fetch data and render components. Put logic in `lib/` and UI in `components/`.
39
+ - Code that uses secrets or the Supabase admin client lives in `lib/` and starts with `import "server-only";`.
40
+ - Client components (`"use client"`) go in `components/`, not `lib/`.
41
+ - One component per file. Name files in kebab-case (`project-card.tsx`) unless the repo already uses another convention.
42
+ - Use the `@/` import alias instead of long relative paths (`../../../`).
43
+ - If a file grows past about 300 lines, split it by responsibility.
44
+ - Before creating a helper, search for an existing one. Don't create a second `utils` that does the same thing.
45
+
46
+ ## Moving existing files
47
+
48
+ - Don't reorganize many files at once. Move a few related files per change, update imports, and run typecheck, lint and tests.
49
+ - Never move files in `app/` without checking the URL won't change. Moving a page folder changes its URL.
50
+ - Don't move or rename migrations in `supabase/migrations/`.
51
+ - If the user asks for a big reorganization, propose a plan in small steps first.
@@ -0,0 +1,60 @@
1
+ ---
2
+ name: pre-launch-checklist
3
+ description: Use when the user is about to launch, go live, accept real payments, invite real users or share the app publicly. Walks through security, data, configuration and ownership checks before launch.
4
+ ---
5
+
6
+ # Pre-launch checklist
7
+
8
+ Work through this list with the user. Run what you can yourself, and ask the user to confirm the dashboard items. Report the result as a short list: done, needs action, not applicable.
9
+
10
+ ## 1. Aura scan
11
+
12
+ - Run `aura scan --json`. Resolve every critical and high finding before launch (`aura next --json` shows how).
13
+ - Explain any medium findings the user decides to leave, so it's a conscious choice.
14
+
15
+ ## 2. Tests and build
16
+
17
+ - The test suite, lint, typecheck and production build all pass locally and in CI.
18
+ - The core flows (sign up, sign in, the main action, payment) have tests or have been checked by hand on a preview deployment.
19
+
20
+ ## 3. Data security
21
+
22
+ - Row level security is enabled on every table in the `public` schema, with explicit policies. In Supabase: Database → Tables shows an "RLS disabled" warning on any table without it. Supabase's Security Advisor (Advisors → Security Advisor) lists issues too.
23
+ - Every route handler and server action checks the user (see the secure-api-routes skill).
24
+ - Storage buckets have policies, and only intentionally public buckets are public.
25
+
26
+ ## 4. Secrets and environment
27
+
28
+ - No secrets in the repo (the Aura scan checks this). Any secret that was ever committed has been rotated.
29
+ - Every variable in `.env.example` is set in Vercel for Production: Project → Settings → Environment Variables.
30
+ - Production uses live keys where needed (Stripe `sk_live_` and a live webhook endpoint pointing at the production domain), and nothing secret is in a `NEXT_PUBLIC_` variable.
31
+
32
+ ## 5. Auth and email settings
33
+
34
+ - Supabase: Authentication → URL Configuration has the production Site URL and redirect URLs.
35
+ - Supabase's built-in email sender has low limits and is meant for testing. Set up custom SMTP (Authentication → Emails → SMTP Settings) with a provider such as Resend before real users sign up.
36
+
37
+ ## 6. User experience
38
+
39
+ - Every page has loading, empty and error states, and there is a custom 404 page (see the error-handling skill).
40
+ - No stack traces or raw error messages are shown to users.
41
+
42
+ ## 7. Legal pages
43
+
44
+ Check that a privacy policy and terms of service page exist and are linked in the footer. If the app uses non-essential cookies or serves the EU or UK, check for a cookie notice. Flag what's missing; don't write legal text or give legal advice. Suggest the user gets proper legal input.
45
+
46
+ ## 8. Backups
47
+
48
+ - Supabase daily backups are included on paid plans (Database → Backups). Free projects have no downloadable backups and pause after a week of inactivity. If the app holds real user data, recommend a paid plan, and point-in-time recovery for important data.
49
+ - Confirm the user knows how to restore.
50
+
51
+ ## 9. Ownership
52
+
53
+ - Run `aura inventory` with the user so every service, domain and account has a recorded owner.
54
+ - Accounts (GitHub, Vercel, Supabase, Stripe, domain registrar) should be owned by a company account or organization with two-factor authentication, not one person's personal login. `aura guide transfer-ownership` explains how.
55
+ - Run `aura guide github-security` if branch protection and secret scanning aren't on yet.
56
+
57
+ ## 10. After launch
58
+
59
+ - Watch Vercel logs and error tracking for the first days.
60
+ - Run `aura scan` after each significant change.
@@ -0,0 +1,52 @@
1
+ ---
2
+ name: secrets-and-env
3
+ description: Use when adding an API key, password, token or any configuration value, adding a new integration, or when a secret may have been exposed. Covers environment variables, NEXT_PUBLIC_ rules, .env.example and what to do after a leak.
4
+ ---
5
+
6
+ # Secrets and environment variables
7
+
8
+ ## Never hardcode secrets
9
+
10
+ API keys, passwords, tokens, webhook secrets and connection strings never go in source code, tests, docs, comments or commit messages. Read them from `process.env`:
11
+
12
+ ```ts
13
+ const apiKey = process.env.OPENAI_API_KEY;
14
+ if (!apiKey) throw new Error("OPENAI_API_KEY is not set");
15
+ ```
16
+
17
+ Read secrets only in server code (route handlers, server actions, server components, `lib/` server modules). Add `import "server-only";` at the top of modules that read secrets so they can never be bundled into the browser.
18
+
19
+ ## NEXT_PUBLIC_ variables
20
+
21
+ Next.js copies every variable that starts with `NEXT_PUBLIC_` into the JavaScript sent to browsers. Anyone can read them.
22
+
23
+ - Only values that are safe to publish go in `NEXT_PUBLIC_`: the Supabase URL, the Supabase publishable or anon key, the Stripe publishable key (`pk_...`), analytics IDs.
24
+ - Never put a secret in a `NEXT_PUBLIC_` variable: no `sk_`, `sb_secret_`, `service_role`, `whsec_`, AI provider keys or database URLs.
25
+ - Never rename a secret to add `NEXT_PUBLIC_` to make an error go away. Move the code that needs it to the server instead.
26
+
27
+ ## When you add a variable
28
+
29
+ 1. Use it through `process.env.NAME` in server code.
30
+ 2. Add it to `.env.example` with a comment and no value:
31
+ ```bash
32
+ # Resend API key for transactional email. Server only. https://resend.com/api-keys
33
+ RESEND_API_KEY=
34
+ ```
35
+ 3. Tell the user to add the real value to their local `.env.local`.
36
+ 4. Tell the user to add it in Vercel: Project → Settings → Environment Variables, for Production and Preview (mark secrets as Sensitive), then redeploy. `vercel env pull .env.local` copies them back to local.
37
+ 5. If CI needs it, add it as a GitHub Actions secret.
38
+
39
+ ## Files
40
+
41
+ - `.env.local` holds real values and is never committed. Check `.gitignore` covers `.env*` and allows `.env.example` (`!.env.example`).
42
+ - `.env.example` is committed and lists every variable the app needs, with no real values.
43
+
44
+ ## If a secret leaks
45
+
46
+ A secret has leaked if it was committed to git (even if later deleted), pasted in a chat, issue or log, or sent to the browser.
47
+
48
+ 1. Tell the user immediately and plainly which secret and where. Never print the value.
49
+ 2. Run `aura guide rotate-<service>-key` (for example `rotate-stripe-key`, `rotate-supabase-key`; `rotate-generic-key` for others) and walk the user through it. Rotating means creating a new key and deleting the old one in the service's dashboard. Only the user can do this.
50
+ 3. Remove the secret from the code and read it from `process.env` instead.
51
+ 4. Once rotated, the old key is useless, so rewriting git history is optional. Don't rewrite history or force-push without the user's agreement.
52
+ 5. Run `aura scan` to confirm.
@@ -0,0 +1,92 @@
1
+ ---
2
+ name: secure-api-routes
3
+ description: Use when creating or changing a route handler (app/**/route.ts), a server action ("use server"), proxy.ts or middleware.ts, or a webhook endpoint. Covers authentication, permissions, input validation, webhook signatures and rate limiting.
4
+ ---
5
+
6
+ # Secure API routes
7
+
8
+ Every route handler and server action is a public URL that anyone on the internet can call directly, with any input. Assume they will.
9
+
10
+ ## Checklist for every route handler and server action
11
+
12
+ 1. **Who is calling?** Check the user on the server, inside the handler or action.
13
+ 2. **Are they allowed?** Check they own or have access to the specific record.
14
+ 3. **Is the input valid?** Validate with zod before using it.
15
+ 4. **What do you return?** Only the fields the caller needs. Generic error messages.
16
+
17
+ ## Authentication with Supabase
18
+
19
+ Use the server client from `lib/supabase/server` and check the user with `getUser()` (or `getClaims()`, which verifies the token's signature). Never use `getSession()` for auth decisions on the server: it reads the cookie without verifying it.
20
+
21
+ ```ts
22
+ import { z } from "zod";
23
+ import { createClient } from "@/lib/supabase/server";
24
+
25
+ const Body = z.object({ name: z.string().min(1).max(100) });
26
+
27
+ export async function POST(request: Request) {
28
+ const supabase = await createClient();
29
+ const { data: { user } } = await supabase.auth.getUser();
30
+ if (!user) return Response.json({ error: "Not signed in" }, { status: 401 });
31
+
32
+ const parsed = Body.safeParse(await request.json().catch(() => null));
33
+ if (!parsed.success) return Response.json({ error: "Invalid input" }, { status: 400 });
34
+
35
+ const { data, error } = await supabase
36
+ .from("projects")
37
+ .insert({ name: parsed.data.name, owner_id: user.id })
38
+ .select("id, name")
39
+ .single();
40
+ if (error) {
41
+ console.error("Create project failed", error);
42
+ return Response.json({ error: "Could not create project" }, { status: 500 });
43
+ }
44
+ return Response.json(data, { status: 201 });
45
+ }
46
+ ```
47
+
48
+ Server actions follow the same pattern: get the user first, validate the arguments, then act.
49
+
50
+ ## Authorization by ownership
51
+
52
+ - Never trust an `id` or `userId` sent by the client to decide who someone is. Use `user.id` from the server.
53
+ - When reading or changing a record, filter by owner (`.eq("owner_id", user.id)`) and rely on row level security as a second layer. If no row matches, return 404.
54
+ - Admin-only actions check a role stored on the server (a table or `app_metadata`), never a value from the request. Never use `user_metadata` for roles: users can edit it.
55
+ - Use the service role or secret key only in server code, only when RLS can't express the rule, and do the permission check yourself first.
56
+
57
+ ## proxy.ts and middleware.ts
58
+
59
+ Next.js 16 renamed `middleware.ts` to `proxy.ts`. Use it to refresh the Supabase session and redirect signed-out users, but don't rely on it as the only check. Always check auth again in the route handler, server action or data access function.
60
+
61
+ ## Webhooks
62
+
63
+ Verify the signature before doing anything. For Stripe, read the raw body:
64
+
65
+ ```ts
66
+ const body = await request.text();
67
+ const signature = request.headers.get("stripe-signature");
68
+ if (!signature) return new Response("Missing signature", { status: 400 });
69
+ let event;
70
+ try {
71
+ event = stripe.webhooks.constructEvent(body, signature, process.env.STRIPE_WEBHOOK_SECRET!);
72
+ } catch {
73
+ return new Response("Invalid signature", { status: 400 });
74
+ }
75
+ ```
76
+
77
+ Handle each event idempotently (store `event.id` and skip duplicates); providers retry.
78
+
79
+ ## Rate limiting
80
+
81
+ Rate-limit routes that send email or SMS, check passwords or codes, call paid AI APIs, or create accounts. Use a Vercel Firewall rate limit rule or a library such as `@upstash/ratelimit`. Key the limit on user id when signed in, IP otherwise.
82
+
83
+ ## Intentionally public routes
84
+
85
+ Some routes are meant to be public (health checks, public pages' data, webhooks that verify a signature). Mark them on the line above the handler so Aura knows it's deliberate:
86
+
87
+ ```ts
88
+ // aura-ignore: public — health check used by uptime monitoring, returns no data
89
+ export async function GET() { ... }
90
+ ```
91
+
92
+ Only add this when the route is truly public and returns nothing private. If unsure, ask the user.
@@ -0,0 +1,77 @@
1
+ ---
2
+ name: writing-tests
3
+ description: Use when adding or changing a feature, fixing a bug, or before saying a task is done. Covers writing Vitest unit tests, testing Next.js route handlers and server actions, and when to use Playwright.
4
+ ---
5
+
6
+ # Writing tests
7
+
8
+ Every new feature and every bug fix gets a test. Tests are how the user knows their app still works after the next change.
9
+
10
+ ## Rules
11
+
12
+ - Add tests in the same change as the feature, not later.
13
+ - For a bug fix, first write a test that fails because of the bug, then fix it.
14
+ - Run the full test suite before saying you're done. If tests fail, fix them. Never delete or skip a failing test to make the suite pass unless the user agrees.
15
+ - Test behaviour (inputs and outputs), not implementation details.
16
+ - No real network calls, real payments or production databases in unit tests. Mock them.
17
+
18
+ ## Where tests go
19
+
20
+ Follow the existing pattern in the repo. If there is none, put the test next to the file it tests: `lib/pricing.ts` → `lib/pricing.test.ts`. End-to-end tests go in `e2e/`.
21
+
22
+ ## Unit tests with Vitest
23
+
24
+ ```ts
25
+ import { describe, expect, it } from "vitest";
26
+ import { calculateTotal } from "@/lib/pricing";
27
+
28
+ describe("calculateTotal", () => {
29
+ it("applies the discount", () => {
30
+ expect(calculateTotal(1000, { percentOff: 10 })).toBe(900);
31
+ });
32
+
33
+ it("never goes below zero", () => {
34
+ expect(calculateTotal(500, { amountOff: 800 })).toBe(0);
35
+ });
36
+ });
37
+ ```
38
+
39
+ Cover the normal case, edge cases (empty, zero, very large) and the failure case.
40
+
41
+ Files that import `server-only` throw in tests. Add `vi.mock("server-only", () => ({}));` at the top of the test file.
42
+
43
+ ## Route handlers
44
+
45
+ Import the handler and call it with a real `Request`:
46
+
47
+ ```ts
48
+ import { POST } from "@/app/api/projects/route";
49
+
50
+ it("rejects requests without a signed-in user", async () => {
51
+ const res = await POST(new Request("http://localhost/api/projects", {
52
+ method: "POST",
53
+ body: JSON.stringify({ name: "Test" }),
54
+ }));
55
+ expect(res.status).toBe(401);
56
+ });
57
+ ```
58
+
59
+ Mock the Supabase client module (`vi.mock("@/lib/supabase/server", ...)`) to control who is signed in. Always test the unauthenticated case, the wrong-user case and invalid input.
60
+
61
+ ## Server actions
62
+
63
+ Keep the logic in a plain function in `lib/` and have the action call it. Test the plain function directly. Test the action itself for auth and validation the same way as a route handler.
64
+
65
+ ## Components
66
+
67
+ Vitest can test client components with React Testing Library. Add `// @vitest-environment jsdom` at the top of the file (needs `jsdom`, `@testing-library/react` and `@vitejs/plugin-react` installed). Async server components can't be unit tested; cover them with an end-to-end test.
68
+
69
+ ## End-to-end with Playwright
70
+
71
+ Use Playwright for the few flows that must never break: sign up, sign in, the core action, checkout. Keep them few and stable. Put them in `e2e/` so Vitest doesn't pick them up.
72
+
73
+ ## Before you finish
74
+
75
+ 1. Run the test script (see the commands in the project rules file).
76
+ 2. Run lint and typecheck.
77
+ 3. Tell the user which tests you added and that they pass.