@oaklandzoo/ostup 0.3.0 → 0.4.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.
- package/README.md +23 -0
- package/bin/cli.mjs +27 -1
- package/package.json +1 -1
- package/src/brief/classify.mjs +218 -0
- package/src/brief/index.mjs +126 -0
- package/src/brief/profile-router.mjs +89 -0
- package/src/brief/questions.mjs +333 -0
- package/src/brief/render-brief.mjs +232 -0
- package/src/brief/sample-briefs.mjs +304 -0
- package/src/brief/schema.mjs +176 -0
- package/src/mvp-flow.mjs +43 -1
- package/templates/AGENTS.md +10 -0
- package/templates/CLAUDE.md +3 -0
- package/templates/START_HERE.md +8 -4
- package/templates/profiles/blog/.env.example.additions +7 -0
- package/templates/profiles/blog/README.md +70 -0
- package/templates/profiles/blog/section-prompts.md +63 -0
- package/templates/profiles/booking/.env.example.additions +16 -0
- package/templates/profiles/booking/README.md +61 -0
- package/templates/profiles/booking/section-prompts.md +47 -0
- package/templates/profiles/lead-gen/.env.example.additions +8 -0
- package/templates/profiles/lead-gen/README.md +58 -0
- package/templates/profiles/lead-gen/section-prompts.md +47 -0
- package/templates/profiles/marketing/README.md +39 -0
- package/templates/profiles/marketing/section-prompts.md +36 -0
- package/templates/profiles/saas-dashboard/.env.example.additions +21 -0
- package/templates/profiles/saas-dashboard/README.md +60 -0
- package/templates/profiles/saas-dashboard/section-prompts.md +52 -0
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
# Profile: blog
|
|
2
|
+
|
|
3
|
+
> Content engine. MDX posts, RSS, sitemap, tag/author pages. SEO-first. No CMS v1.
|
|
4
|
+
|
|
5
|
+
## Day-one scope
|
|
6
|
+
|
|
7
|
+
| Section | Purpose | Required |
|
|
8
|
+
|---|---|---|
|
|
9
|
+
| Homepage | Latest 6-10 posts, intro paragraph | yes |
|
|
10
|
+
| Post page | Single post by slug, MDX-rendered | yes |
|
|
11
|
+
| Tag index | List of all tags with post counts | yes |
|
|
12
|
+
| Tag page | All posts under a tag | yes |
|
|
13
|
+
| Author page (if multi-author) | Author bio + their posts | conditional |
|
|
14
|
+
| RSS feed | `/rss.xml` valid RSS 2.0 | yes |
|
|
15
|
+
| Sitemap | `/sitemap.xml` valid sitemap | yes |
|
|
16
|
+
| About | Static about page | yes |
|
|
17
|
+
| Footer | Links, RSS, year | yes |
|
|
18
|
+
|
|
19
|
+
## Wired infrastructure
|
|
20
|
+
|
|
21
|
+
- **MDX** for post bodies. Posts live as `.mdx` files in `content/posts/`.
|
|
22
|
+
- Frontmatter schema: `title`, `slug`, `date`, `tags[]`, `author?`, `description?`, `draft?`.
|
|
23
|
+
- `next-mdx-remote` or `@next/mdx` (agent picks; both work).
|
|
24
|
+
- Open Graph + Twitter card metadata per post.
|
|
25
|
+
- Article + Organization JSON-LD schema.
|
|
26
|
+
|
|
27
|
+
## Env additions
|
|
28
|
+
|
|
29
|
+
See `.env.example.additions` (mostly empty for blog v1).
|
|
30
|
+
|
|
31
|
+
## File contracts
|
|
32
|
+
|
|
33
|
+
```
|
|
34
|
+
content/posts/<slug>.mdx
|
|
35
|
+
---
|
|
36
|
+
title: "Post title"
|
|
37
|
+
slug: "post-slug"
|
|
38
|
+
date: "2026-05-21"
|
|
39
|
+
tags: ["agents", "tooling"]
|
|
40
|
+
author: "GG"
|
|
41
|
+
description: "One-sentence summary for SEO."
|
|
42
|
+
---
|
|
43
|
+
|
|
44
|
+
Body in MDX.
|
|
45
|
+
|
|
46
|
+
content/authors/<author>.mdx (optional)
|
|
47
|
+
---
|
|
48
|
+
name: "GG"
|
|
49
|
+
bio: "One-paragraph bio."
|
|
50
|
+
social: { x: "@goodshin", github: "DubsFan" }
|
|
51
|
+
---
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
## Hard rules
|
|
55
|
+
|
|
56
|
+
- Posts ship as committed MDX files. No DB v1.
|
|
57
|
+
- `draft: true` excludes from production builds AND from RSS/sitemap.
|
|
58
|
+
- RSS / sitemap regenerate on build.
|
|
59
|
+
- Code blocks use one syntax highlighter (Shiki recommended). Pick at build time, not client-side.
|
|
60
|
+
- Reading width capped at 720px or so for body comfort.
|
|
61
|
+
- Light + dark mode via `prefers-color-scheme`.
|
|
62
|
+
|
|
63
|
+
## Acceptance
|
|
64
|
+
|
|
65
|
+
- Homepage shows latest 6 posts sorted by date desc.
|
|
66
|
+
- Individual post page renders MDX with syntax-highlighted code.
|
|
67
|
+
- RSS feed validates at https://validator.w3.org/feed/.
|
|
68
|
+
- Sitemap includes every published post (no drafts).
|
|
69
|
+
- Tag pages reachable from each post's tag list.
|
|
70
|
+
- Lighthouse Performance >= 95 (static content, should be fast).
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
# Blog profile section prompts
|
|
2
|
+
|
|
3
|
+
Agent: build each section using the brief. Default MDX library: `next-mdx-remote`. Use `gray-matter` for frontmatter parsing.
|
|
4
|
+
|
|
5
|
+
## Homepage
|
|
6
|
+
|
|
7
|
+
- Title + tagline from the brief.
|
|
8
|
+
- Latest 6 posts: title (clickable), date, 1-2-sentence excerpt from `description` or first 160 chars of body.
|
|
9
|
+
- "All posts" link to a chronological archive (optional v1).
|
|
10
|
+
- Tag cloud or top 5 tags if there are 3+ tagged posts.
|
|
11
|
+
|
|
12
|
+
## Post page (`/posts/[slug]`)
|
|
13
|
+
|
|
14
|
+
- Title (h1), date, tags (clickable to tag pages), author (if multi-author).
|
|
15
|
+
- MDX-rendered body.
|
|
16
|
+
- Code blocks: syntax-highlighted with Shiki. Light + dark theme.
|
|
17
|
+
- Body width capped (~65ch).
|
|
18
|
+
- Reading time estimate (optional).
|
|
19
|
+
- Open Graph: title, description, type=article, published_time, author.
|
|
20
|
+
|
|
21
|
+
## Tag index (`/tags`)
|
|
22
|
+
|
|
23
|
+
- All tags from all published posts, sorted by post count desc.
|
|
24
|
+
- Each tag: name + post count + link.
|
|
25
|
+
|
|
26
|
+
## Tag page (`/tags/[tag]`)
|
|
27
|
+
|
|
28
|
+
- All posts under that tag, chronological desc.
|
|
29
|
+
- Same card format as homepage list.
|
|
30
|
+
|
|
31
|
+
## Author page (`/authors/[author]`) — only if multi-author
|
|
32
|
+
|
|
33
|
+
- Author bio from `content/authors/<author>.mdx`.
|
|
34
|
+
- All posts by that author.
|
|
35
|
+
|
|
36
|
+
## RSS feed (`/rss.xml`)
|
|
37
|
+
|
|
38
|
+
- RSS 2.0.
|
|
39
|
+
- Include title, link, description, pubDate, category for each post.
|
|
40
|
+
- Published posts only (`draft: false`).
|
|
41
|
+
- Validate the output structure manually before claiming done.
|
|
42
|
+
|
|
43
|
+
## Sitemap (`/sitemap.xml`)
|
|
44
|
+
|
|
45
|
+
- All published posts + tag pages + author pages + homepage + about.
|
|
46
|
+
- `<lastmod>` on each entry.
|
|
47
|
+
- No drafts.
|
|
48
|
+
|
|
49
|
+
## About
|
|
50
|
+
|
|
51
|
+
- Pulled from the brief: who runs the site, what it covers, contact.
|
|
52
|
+
- Single page. Plain text + maybe a portrait from `inputs/images/`.
|
|
53
|
+
|
|
54
|
+
## Footer
|
|
55
|
+
|
|
56
|
+
- RSS link with feed icon.
|
|
57
|
+
- GitHub link (if applicable).
|
|
58
|
+
- Year + copyright.
|
|
59
|
+
|
|
60
|
+
## First post
|
|
61
|
+
|
|
62
|
+
- If the brief mentions a launch announcement, write `content/posts/hello-world.mdx` as a placeholder with the project summary.
|
|
63
|
+
- Otherwise leave `content/posts/` with a `.gitkeep` only and let the operator write the first post.
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# --- booking profile additions ---
|
|
2
|
+
# Database for Booking entity (Neon recommended; any Postgres works)
|
|
3
|
+
DATABASE_URL=
|
|
4
|
+
|
|
5
|
+
# Email confirmation
|
|
6
|
+
RESEND_API_KEY=
|
|
7
|
+
BOOKING_TO_EMAIL=
|
|
8
|
+
BOOKING_FROM_EMAIL=noreply@example.com
|
|
9
|
+
|
|
10
|
+
# Optional: Stripe deposit checkout (enable only if `payments` addon is on)
|
|
11
|
+
STRIPE_SECRET_KEY=
|
|
12
|
+
STRIPE_PUBLISHABLE_KEY=
|
|
13
|
+
STRIPE_WEBHOOK_SECRET=
|
|
14
|
+
|
|
15
|
+
# Public app URL (Vercel sets this for production)
|
|
16
|
+
NEXT_PUBLIC_APP_URL=http://localhost:3000
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
# Profile: booking
|
|
2
|
+
|
|
3
|
+
> Appointment / reservation site. Availability request, booking form, optional Stripe deposit, email confirmations.
|
|
4
|
+
|
|
5
|
+
## Day-one scope
|
|
6
|
+
|
|
7
|
+
| Section | Purpose | Required |
|
|
8
|
+
|---|---|---|
|
|
9
|
+
| Hero | Single value statement + "Check availability" or "Book now" CTA | yes |
|
|
10
|
+
| Availability / Booking form | Date range or appointment slot picker + guest info | yes |
|
|
11
|
+
| Rooms / Services | List of bookable units with descriptions and rates | yes |
|
|
12
|
+
| Deposit checkout | Stripe Checkout for the deposit if `payments` addon is on | conditional |
|
|
13
|
+
| Confirmation email | Auto-send on submission to both guest and admin | yes |
|
|
14
|
+
| About / Amenities | Trust-building content from the brief | yes |
|
|
15
|
+
| Footer | Contact, cancellation policy summary | yes |
|
|
16
|
+
|
|
17
|
+
## Wired infrastructure
|
|
18
|
+
|
|
19
|
+
- **Postgres** for the `Booking` entity (date_start, date_end, guest info, status, deposit_status).
|
|
20
|
+
- **Resend** for guest + admin confirmation emails.
|
|
21
|
+
- **Stripe Checkout** for deposit (only if `payments` addon is on per the brief).
|
|
22
|
+
- Mobile-first calendar / date picker.
|
|
23
|
+
|
|
24
|
+
## Env additions
|
|
25
|
+
|
|
26
|
+
See `.env.example.additions`.
|
|
27
|
+
|
|
28
|
+
## API contracts
|
|
29
|
+
|
|
30
|
+
```
|
|
31
|
+
POST /api/booking/request
|
|
32
|
+
Body: { name, email, phone?, date_start, date_end, room_or_service?, notes? }
|
|
33
|
+
Response: { ok, booking_id }
|
|
34
|
+
Behavior: insert Booking with status='pending', email both parties.
|
|
35
|
+
|
|
36
|
+
POST /api/booking/deposit
|
|
37
|
+
Body: { booking_id }
|
|
38
|
+
Response: { ok, checkout_url }
|
|
39
|
+
Behavior: create Stripe Checkout session, return URL.
|
|
40
|
+
|
|
41
|
+
POST /api/webhooks/stripe
|
|
42
|
+
Behavior: on payment_intent.succeeded, mark booking deposit_status='paid'.
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
## Hard rules
|
|
46
|
+
|
|
47
|
+
- Date pickers MUST be mobile-friendly (no tiny native date inputs without testing).
|
|
48
|
+
- Server-side validate the date range (no past dates, no end-before-start).
|
|
49
|
+
- Confirmation emails go out immediately on form submit, even before deposit.
|
|
50
|
+
- Deposit is OPTIONAL: if `payments` addon is off, skip Stripe entirely. Booking still goes through.
|
|
51
|
+
- Calendar availability check should be server-side; do not trust client.
|
|
52
|
+
- If `Booking.status` is 'pending' for >48h with no deposit, mark as 'expired'.
|
|
53
|
+
|
|
54
|
+
## Acceptance
|
|
55
|
+
|
|
56
|
+
- Visitor can request dates and submit.
|
|
57
|
+
- Both visitor and admin receive emails within 30 seconds.
|
|
58
|
+
- Deposit Checkout opens if enabled, completes round-trip to the booking record.
|
|
59
|
+
- Past dates rejected with clear error.
|
|
60
|
+
- Hero CTA above the fold at 420x900.
|
|
61
|
+
- Lighthouse mobile Performance >= 85 (acceptable lower than marketing because of date picker JS).
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
# Booking profile section prompts
|
|
2
|
+
|
|
3
|
+
Agent: build each section using the brief in `docs/brief.md`. Honor `must_avoid` strictly.
|
|
4
|
+
|
|
5
|
+
## Hero
|
|
6
|
+
|
|
7
|
+
- Headline (5-9 words) about the experience being booked.
|
|
8
|
+
- Subhead: one sentence on what the visitor gets when they book.
|
|
9
|
+
- Primary CTA: "Check availability" or "Book now" — opens the booking form modal or scrolls to it.
|
|
10
|
+
|
|
11
|
+
## Availability / Booking form
|
|
12
|
+
|
|
13
|
+
- Date range picker (or single-date for appointments). Mobile-friendly is mandatory.
|
|
14
|
+
- Guest info: name, email, phone, party size (if relevant), notes.
|
|
15
|
+
- Validate server-side: no past dates, end after start, party size within room limits.
|
|
16
|
+
- Loading state on submit. Success state with booking ID. Error state with clear message.
|
|
17
|
+
|
|
18
|
+
## Rooms / Services
|
|
19
|
+
|
|
20
|
+
- Pull entity list from the brief's `data_model.entities`. If a Room entity exists, list its fields visually.
|
|
21
|
+
- Each unit: name, description (short), rate per night/hour, photo placeholder if `inputs/images/` has anything matching.
|
|
22
|
+
- "Book this" CTA scrolls back to the booking form with the room pre-selected.
|
|
23
|
+
|
|
24
|
+
## Deposit checkout (conditional)
|
|
25
|
+
|
|
26
|
+
- Only render if `payments` addon is in the brief.
|
|
27
|
+
- After successful booking submission, present a "Pay deposit to confirm" CTA.
|
|
28
|
+
- Clicking opens Stripe Checkout via `/api/booking/deposit`.
|
|
29
|
+
- On Checkout success, return to a `/booking/[id]/confirmed` page.
|
|
30
|
+
- Webhook `/api/webhooks/stripe` updates `deposit_status='paid'`.
|
|
31
|
+
|
|
32
|
+
## Confirmation emails
|
|
33
|
+
|
|
34
|
+
- Guest receives: "Your booking request is in. We'll confirm within X hours. Booking ID: ABC123."
|
|
35
|
+
- Admin receives: full booking details + a link to the admin route (TBD v2).
|
|
36
|
+
- Use Resend. Plain text + HTML versions.
|
|
37
|
+
|
|
38
|
+
## About / Amenities
|
|
39
|
+
|
|
40
|
+
- Pull from the brief's `must_have_sections`. Echo the brief's vibe.
|
|
41
|
+
- Photos from `inputs/images/` if any. Otherwise text-only placeholders.
|
|
42
|
+
|
|
43
|
+
## Footer
|
|
44
|
+
|
|
45
|
+
- Cancellation policy summary (1-2 sentences from the brief or a placeholder asking the operator).
|
|
46
|
+
- Contact email + phone.
|
|
47
|
+
- Year + copyright.
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
# Profile: lead-gen
|
|
2
|
+
|
|
3
|
+
> Service-company site that captures contact requests. Resend for email, optional CRM webhook, local SEO basics.
|
|
4
|
+
|
|
5
|
+
## Day-one scope
|
|
6
|
+
|
|
7
|
+
| Section | Purpose | Required |
|
|
8
|
+
|---|---|---|
|
|
9
|
+
| Hero | Single value statement + primary CTA "Request a quote" or "Contact us" | yes |
|
|
10
|
+
| Services | 3-8 service cards or list. Tap-to-call on mobile. | yes |
|
|
11
|
+
| Service area | Map placeholder OR text list of cities / zip codes covered | yes |
|
|
12
|
+
| Testimonials | 2-4 quotes (placeholders OK if brief has none) | yes |
|
|
13
|
+
| FAQ | 4-8 questions, accordion or stacked | yes |
|
|
14
|
+
| Contact form | Name, phone, email, message. Posts to /api/contact. | yes |
|
|
15
|
+
| Footer | Phone, email, license number if applicable, year | yes |
|
|
16
|
+
|
|
17
|
+
## Wired infrastructure
|
|
18
|
+
|
|
19
|
+
- **Resend** for email notifications when a lead submits the form.
|
|
20
|
+
- Optional **CRM webhook** (env: `CRM_WEBHOOK_URL`). If set, also POST the lead payload as JSON.
|
|
21
|
+
- **JSON-LD LocalBusiness schema** in the head of every page.
|
|
22
|
+
- Open Graph + Twitter metadata using `{{DISPLAY_NAME}}` and the brand summary.
|
|
23
|
+
|
|
24
|
+
## Env additions
|
|
25
|
+
|
|
26
|
+
See `.env.example.additions` for the variables this profile expects.
|
|
27
|
+
|
|
28
|
+
## API contract for /api/contact
|
|
29
|
+
|
|
30
|
+
```
|
|
31
|
+
POST /api/contact
|
|
32
|
+
Content-Type: application/json
|
|
33
|
+
Body: { name: string, email: string, phone?: string, message: string }
|
|
34
|
+
Response: { ok: boolean, id?: string }
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
The route:
|
|
38
|
+
1. Validates required fields (name, email, message).
|
|
39
|
+
2. Sends an email via Resend to `CONTACT_TO_EMAIL` from `CONTACT_FROM_EMAIL`.
|
|
40
|
+
3. If `CRM_WEBHOOK_URL` is set, POSTs the lead payload there.
|
|
41
|
+
4. Returns 200 with `{ ok: true }` on success; 400 on validation; 500 on send failure.
|
|
42
|
+
|
|
43
|
+
No persistent storage v1. Leads live in the operator's email inbox.
|
|
44
|
+
|
|
45
|
+
## Hard rules
|
|
46
|
+
|
|
47
|
+
- Phone number on every page (mobile sticky CTA acceptable).
|
|
48
|
+
- Service area is explicit. Do not claim to cover areas the brief does not mention.
|
|
49
|
+
- No JS-heavy carousels. Stacked content reads better on phones.
|
|
50
|
+
- Honor `constraints.must_avoid` strictly.
|
|
51
|
+
|
|
52
|
+
## Acceptance
|
|
53
|
+
|
|
54
|
+
- Visitor can submit the contact form, sees an inline success state.
|
|
55
|
+
- Owner receives the lead by email at the address in `CONTACT_TO_EMAIL`.
|
|
56
|
+
- JSON-LD LocalBusiness schema validates at https://search.google.com/test/rich-results.
|
|
57
|
+
- Hero CTA above the fold at 420x900.
|
|
58
|
+
- Lighthouse mobile Performance >= 90, Accessibility >= 95.
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
# Lead-gen profile section prompts
|
|
2
|
+
|
|
3
|
+
Agent: build each section using the brief in `docs/brief.md`. Do not invent service offerings, prices, or testimonials.
|
|
4
|
+
|
|
5
|
+
## Hero
|
|
6
|
+
|
|
7
|
+
- Headline: 5-9 words. Echo the project summary in the operator's voice.
|
|
8
|
+
- Subhead: one sentence on who it serves and what they get.
|
|
9
|
+
- Primary CTA: "Request a quote" or "Contact us today" (use the brief's wording if it specifies).
|
|
10
|
+
- Secondary trust signal: years in business, license number, or service area at a glance (only if in brief).
|
|
11
|
+
|
|
12
|
+
## Services
|
|
13
|
+
|
|
14
|
+
- List 3-8 services from the brief's `scope.must_have_sections` (filter out non-service sections like hero/footer/contact).
|
|
15
|
+
- Each service card: short title + one or two sentences + (if available from brief) a starting-price hint.
|
|
16
|
+
- Tap-to-call phone link visible on mobile.
|
|
17
|
+
|
|
18
|
+
## Service area
|
|
19
|
+
|
|
20
|
+
- If the brief mentions specific cities, towns, or zip codes, list them.
|
|
21
|
+
- If only a general area, use that phrasing exactly.
|
|
22
|
+
- If no specific area info: ask the operator to fill in `docs/brief.md` before building this section. Do NOT default to "nationwide."
|
|
23
|
+
|
|
24
|
+
## Testimonials
|
|
25
|
+
|
|
26
|
+
- 2-4 short quotes. If the brief has actual quotes, use them.
|
|
27
|
+
- If none: use clear placeholders like `[Testimonial pending — operator to add]` and DO NOT fabricate.
|
|
28
|
+
|
|
29
|
+
## FAQ
|
|
30
|
+
|
|
31
|
+
- 4-8 questions tied to the services from the brief.
|
|
32
|
+
- Suggested defaults: "How fast can you get here?", "Do you provide free estimates?", "Are you licensed and insured?", "Do you offer financing?". Match to the brief's business model.
|
|
33
|
+
- Use an accordion or stacked Q/A. No JS framework needed.
|
|
34
|
+
|
|
35
|
+
## Contact form
|
|
36
|
+
|
|
37
|
+
- Fields: name (required), email (required), phone (optional), message (required).
|
|
38
|
+
- POSTs to `/api/contact`.
|
|
39
|
+
- Inline success message on submit: "Got it. We will be in touch within one business day."
|
|
40
|
+
- On error: inline message with retry, never alert dialogs.
|
|
41
|
+
- Form labels visible, not just placeholders (accessibility).
|
|
42
|
+
|
|
43
|
+
## Footer
|
|
44
|
+
|
|
45
|
+
- Phone, email, address (if relevant), license number (if relevant).
|
|
46
|
+
- Current year, copyright.
|
|
47
|
+
- Privacy / Terms links if the operator has them (otherwise omit; do not invent legalese).
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# Profile: marketing
|
|
2
|
+
|
|
3
|
+
> Single-page or short marketing site. Default for projects with weak signals.
|
|
4
|
+
|
|
5
|
+
## Day-one scope
|
|
6
|
+
|
|
7
|
+
| Section | Purpose | Required |
|
|
8
|
+
|---|---|---|
|
|
9
|
+
| Hero | Single primary value statement + one CTA (email or "Get started") | yes |
|
|
10
|
+
| Features | 3-6 short benefit cards | yes |
|
|
11
|
+
| Social proof / Testimonials | Quote, logo strip, or "in use at" line | optional |
|
|
12
|
+
| Pricing | One or two tiers, simple | optional |
|
|
13
|
+
| Email signup | Inline form posting to /api/subscribe (no DB; logs or forwards) | optional |
|
|
14
|
+
| Footer | Links, year, attribution | yes |
|
|
15
|
+
|
|
16
|
+
## Wired infrastructure
|
|
17
|
+
|
|
18
|
+
None by default. Pure static.
|
|
19
|
+
|
|
20
|
+
If the brief includes `email` add-on (newsletter signup), the agent should wire Resend or a generic webhook for the form submission.
|
|
21
|
+
|
|
22
|
+
## What ships in this overlay
|
|
23
|
+
|
|
24
|
+
- `section-prompts.md` — concrete guidance for each section.
|
|
25
|
+
- Anything in `.additions` is appended to the matching scaffolded file.
|
|
26
|
+
|
|
27
|
+
## Hard rules
|
|
28
|
+
|
|
29
|
+
- Mobile-first. Test at 420x900 with `scripts/screenshot.sh`.
|
|
30
|
+
- No third-party tracking. No popups. No chat widget.
|
|
31
|
+
- One CTA per page. If a section has its own CTA, route it to the same destination as the hero CTA.
|
|
32
|
+
- All copy comes from `docs/brief.md`. The agent paraphrases for the page, never invents new claims.
|
|
33
|
+
|
|
34
|
+
## Acceptance
|
|
35
|
+
|
|
36
|
+
- Hero readable at 420x900.
|
|
37
|
+
- Single primary CTA visible above the fold.
|
|
38
|
+
- Lighthouse mobile Performance >= 90, Accessibility >= 95.
|
|
39
|
+
- No console errors.
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# Marketing profile section prompts
|
|
2
|
+
|
|
3
|
+
Agent: build each section using the brief in `docs/brief.md`. Do not invent claims.
|
|
4
|
+
|
|
5
|
+
## Hero
|
|
6
|
+
|
|
7
|
+
- 1 headline (5-9 words) drawn from `project.summary`.
|
|
8
|
+
- 1 subhead (one sentence) describing who it is for and what changes.
|
|
9
|
+
- 1 primary CTA button. Text is imperative, e.g. "Get the early access link" or "Start free."
|
|
10
|
+
- Optional: small visual (an SVG mark from `inputs/images/`, NOT a generic stock photo).
|
|
11
|
+
|
|
12
|
+
## Features (3-6 cards)
|
|
13
|
+
|
|
14
|
+
- Each card has: short title (3-5 words) + one-sentence description.
|
|
15
|
+
- Pull titles from `scope.must_have_sections` (skip "hero" and "footer").
|
|
16
|
+
- Description echoes the brief vibe in `brand.vibe`.
|
|
17
|
+
- Use a grid; on mobile stack 1 column.
|
|
18
|
+
|
|
19
|
+
## Pricing (if included)
|
|
20
|
+
|
|
21
|
+
- 1-3 tiers. Each tier: name, price (or "free"), 3-5 bullets, single CTA.
|
|
22
|
+
- Use the pricing notes in `business_model.pricing_notes`.
|
|
23
|
+
- If no pricing info in brief, omit the section entirely. Do not invent prices.
|
|
24
|
+
|
|
25
|
+
## Email signup
|
|
26
|
+
|
|
27
|
+
- One field (email) + one button.
|
|
28
|
+
- Submit to `/api/subscribe` (or `/api/contact`).
|
|
29
|
+
- Inline success message on submit: "You're on the list."
|
|
30
|
+
- No double opt-in flow v1.
|
|
31
|
+
|
|
32
|
+
## Footer
|
|
33
|
+
|
|
34
|
+
- Copyright year (current).
|
|
35
|
+
- 2-4 links max: GitHub, npm, docs, contact.
|
|
36
|
+
- No social icons unless the brief says social presence matters.
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# --- saas-dashboard profile additions ---
|
|
2
|
+
# Auth (Better Auth)
|
|
3
|
+
BETTER_AUTH_SECRET=
|
|
4
|
+
BETTER_AUTH_URL=http://localhost:3000
|
|
5
|
+
|
|
6
|
+
# Database (Neon recommended for Postgres)
|
|
7
|
+
DATABASE_URL=
|
|
8
|
+
|
|
9
|
+
# Stripe subscriptions
|
|
10
|
+
STRIPE_SECRET_KEY=
|
|
11
|
+
STRIPE_PUBLISHABLE_KEY=
|
|
12
|
+
STRIPE_WEBHOOK_SECRET=
|
|
13
|
+
STRIPE_PRICE_ID_SOLO=
|
|
14
|
+
STRIPE_PRICE_ID_TEAM=
|
|
15
|
+
|
|
16
|
+
# Public app URL
|
|
17
|
+
NEXT_PUBLIC_APP_URL=http://localhost:3000
|
|
18
|
+
|
|
19
|
+
# Email (for verification + password reset)
|
|
20
|
+
RESEND_API_KEY=
|
|
21
|
+
AUTH_FROM_EMAIL=noreply@example.com
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
# Profile: saas-dashboard
|
|
2
|
+
|
|
3
|
+
> SaaS MVP with auth, subscription billing skeleton, dashboard shell, settings. Pick the workflow over feature depth.
|
|
4
|
+
|
|
5
|
+
## Day-one scope
|
|
6
|
+
|
|
7
|
+
| Section | Purpose | Required |
|
|
8
|
+
|---|---|---|
|
|
9
|
+
| Landing hero | Convert visitor to signup | yes |
|
|
10
|
+
| Pricing | 1-3 tiers, monthly + annual toggle | yes |
|
|
11
|
+
| Sign up / Log in | Better Auth flow (email+password or magic link) | yes |
|
|
12
|
+
| Dashboard shell | Authenticated route, empty state with onboarding hint | yes |
|
|
13
|
+
| Settings | Profile + billing pages | yes |
|
|
14
|
+
| Billing | Stripe Customer Portal link OR a stub for "manage subscription" | yes |
|
|
15
|
+
| Footer | Links, year, GitHub, status page link if any | yes |
|
|
16
|
+
|
|
17
|
+
## Wired infrastructure
|
|
18
|
+
|
|
19
|
+
- **Better Auth** for authentication. Email+password v1; magic link v2.
|
|
20
|
+
- **Postgres** for `User` + any product entities from the brief.
|
|
21
|
+
- **Stripe** for subscriptions. Use Stripe Checkout for initial signup, Stripe Customer Portal for management.
|
|
22
|
+
- **Middleware** at the route level: unauthenticated visitors to `/dashboard/*` redirect to `/login`.
|
|
23
|
+
|
|
24
|
+
## Env additions
|
|
25
|
+
|
|
26
|
+
See `.env.example.additions`.
|
|
27
|
+
|
|
28
|
+
## API contracts
|
|
29
|
+
|
|
30
|
+
```
|
|
31
|
+
POST /api/auth/signup (Better Auth handles)
|
|
32
|
+
POST /api/auth/login (Better Auth handles)
|
|
33
|
+
POST /api/auth/logout (Better Auth handles)
|
|
34
|
+
GET /api/auth/session (Better Auth handles; returns user or 401)
|
|
35
|
+
|
|
36
|
+
POST /api/billing/checkout Body: { plan: 'solo' | 'team' }
|
|
37
|
+
Response: { url } (Stripe Checkout URL)
|
|
38
|
+
|
|
39
|
+
GET /api/billing/portal Response: { url } (Stripe Customer Portal URL)
|
|
40
|
+
|
|
41
|
+
POST /api/webhooks/stripe Handles subscription.created, .updated, .deleted
|
|
42
|
+
Updates User.plan
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
## Hard rules
|
|
46
|
+
|
|
47
|
+
- Auth gate runs at middleware level. Never serve dashboard UI to unauthenticated requests, even briefly.
|
|
48
|
+
- Session cookies are httpOnly, secure in production, sameSite=lax.
|
|
49
|
+
- Stripe webhook signature verification is mandatory. Reject on bad sig.
|
|
50
|
+
- Empty dashboard state has a clear "Get started" path. No dead-end empty UI.
|
|
51
|
+
- All errors during auth flow are user-facing (not stack traces).
|
|
52
|
+
- Settings → Billing links to Stripe Customer Portal, not a custom billing UI v1.
|
|
53
|
+
|
|
54
|
+
## Acceptance
|
|
55
|
+
|
|
56
|
+
- New user can sign up, see empty dashboard, log out, log back in.
|
|
57
|
+
- Stripe Checkout can be initiated; webhook updates user plan.
|
|
58
|
+
- Visiting `/dashboard` unauthenticated redirects to `/login`.
|
|
59
|
+
- Visiting `/login` while logged in redirects to `/dashboard`.
|
|
60
|
+
- Lighthouse landing-page Performance >= 90; dashboard >= 80 (slightly lower acceptable due to auth code).
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
# SaaS dashboard profile section prompts
|
|
2
|
+
|
|
3
|
+
Agent: build each section using the brief. Default auth library: Better Auth. Default DB: Postgres (Neon if no preference).
|
|
4
|
+
|
|
5
|
+
## Landing hero (unauthenticated)
|
|
6
|
+
|
|
7
|
+
- Single big claim: the change the product delivers (echo `project.summary`).
|
|
8
|
+
- One CTA: "Start free" or "Get started" → routes to `/signup`.
|
|
9
|
+
- Optional logo strip or "Used by" line if the brief mentions customers.
|
|
10
|
+
|
|
11
|
+
## Pricing
|
|
12
|
+
|
|
13
|
+
- 1-3 tiers from `business_model.pricing_notes`. If 1 tier: show it plus "Custom for teams >".
|
|
14
|
+
- Monthly + annual toggle. Annual = 2 months free (standard pattern).
|
|
15
|
+
- Each tier: name, price, 4-6 bullets, single CTA "Start free" or "Upgrade" depending on auth state.
|
|
16
|
+
|
|
17
|
+
## Sign up / Log in
|
|
18
|
+
|
|
19
|
+
- Two-tab UI on `/auth` OR separate `/signup` and `/login` routes.
|
|
20
|
+
- Email + password v1.
|
|
21
|
+
- Clear error states: "Email already in use", "Wrong password", "Too many attempts" (rate-limit).
|
|
22
|
+
- After signup: email verification flow (Resend).
|
|
23
|
+
- After login: redirect to `/dashboard`.
|
|
24
|
+
|
|
25
|
+
## Dashboard shell
|
|
26
|
+
|
|
27
|
+
- Sidebar nav (collapsible on mobile): Home, Settings, Billing, Logout.
|
|
28
|
+
- Header bar: user email + dropdown.
|
|
29
|
+
- Empty state: "Welcome to {{DISPLAY_NAME}}. Start by [first action from brief]."
|
|
30
|
+
- One primary action button in the empty state.
|
|
31
|
+
|
|
32
|
+
## Settings
|
|
33
|
+
|
|
34
|
+
- Two sub-pages: Profile, Billing.
|
|
35
|
+
- Profile: name, email (verified), change password.
|
|
36
|
+
- Billing: link to Stripe Customer Portal via `/api/billing/portal`. Show current plan + next renewal date.
|
|
37
|
+
|
|
38
|
+
## Billing
|
|
39
|
+
|
|
40
|
+
- Stripe Checkout via `/api/billing/checkout`. Redirect on success to `/dashboard?welcome=1`.
|
|
41
|
+
- Stripe Customer Portal for management.
|
|
42
|
+
- Webhook updates `User.plan` field.
|
|
43
|
+
|
|
44
|
+
## Footer
|
|
45
|
+
|
|
46
|
+
- Privacy, Terms, Status, GitHub.
|
|
47
|
+
- Year, copyright.
|
|
48
|
+
- No SSO / SAML claims v1 unless brief says so explicitly.
|
|
49
|
+
|
|
50
|
+
## Hard rule
|
|
51
|
+
|
|
52
|
+
- Middleware-level auth gate. Use Next.js middleware to protect `/dashboard/*` and `/settings/*`. Unauthenticated requests redirect to `/login`. Authenticated requests to `/login` redirect to `/dashboard`.
|