@sylphx/flow 2.28.6 → 2.28.7
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/CHANGELOG.md +13 -0
- package/assets/skills/account-security/SKILL.md +35 -9
- package/assets/skills/admin/SKILL.md +51 -10
- package/assets/skills/auth/SKILL.md +23 -7
- package/assets/skills/billing/SKILL.md +36 -7
- package/assets/skills/data-modeling/SKILL.md +15 -1
- package/assets/skills/database/SKILL.md +25 -7
- package/assets/skills/i18n/SKILL.md +28 -17
- package/assets/skills/ledger/SKILL.md +15 -1
- package/assets/skills/observability/SKILL.md +9 -8
- package/assets/skills/pricing/SKILL.md +39 -10
- package/assets/skills/storage/SKILL.md +23 -8
- package/assets/skills/uiux/SKILL.md +32 -7
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,18 @@
|
|
|
1
1
|
# @sylphx/flow
|
|
2
2
|
|
|
3
|
+
## 2.28.7 (2026-01-04)
|
|
4
|
+
|
|
5
|
+
Align all skills with platform-led SSOT principles:
|
|
6
|
+
- billing/pricing: Platform is source of truth, Stripe syncs FROM platform
|
|
7
|
+
- uiux: Radix UI + UnoCSS
|
|
8
|
+
- admin: INITIAL_SUPERADMIN_EMAIL bootstrap
|
|
9
|
+
- auth: Better Auth, database: Drizzle, i18n: next-intl, storage: Vercel Blob
|
|
10
|
+
- account-security: Re-authentication flow
|
|
11
|
+
|
|
12
|
+
### 📚 Documentation
|
|
13
|
+
|
|
14
|
+
- **skills:** align skills with SSOT platform-led principles ([dbb868b](https://github.com/SylphxAI/flow/commit/dbb868be48a24b672fb739f81c5dd3590f3cbe29))
|
|
15
|
+
|
|
3
16
|
## 2.28.6 (2026-01-04)
|
|
4
17
|
|
|
5
18
|
Switch styling from Tailwind to UnoCSS + Iconify
|
|
@@ -7,26 +7,52 @@ description: Account security - MFA, sessions, recovery. Use when protecting use
|
|
|
7
7
|
|
|
8
8
|
## Tech Stack
|
|
9
9
|
|
|
10
|
-
* **Auth**:
|
|
10
|
+
* **Auth**: Better Auth
|
|
11
11
|
* **Framework**: Next.js
|
|
12
|
+
* **Database**: Neon (Postgres)
|
|
13
|
+
|
|
14
|
+
## Re-authentication Flow
|
|
15
|
+
|
|
16
|
+
All sensitive operations require explicit re-authentication:
|
|
17
|
+
|
|
18
|
+
```
|
|
19
|
+
Sensitive action triggered
|
|
20
|
+
↓
|
|
21
|
+
Check verified session
|
|
22
|
+
↓
|
|
23
|
+
Does the user have a password?
|
|
24
|
+
├─ Yes → Verify password
|
|
25
|
+
└─ No → Send email OTP (6 digits, 10-minute expiry)
|
|
26
|
+
↓
|
|
27
|
+
Verification succeeds
|
|
28
|
+
↓
|
|
29
|
+
Mark session as verified
|
|
30
|
+
↓
|
|
31
|
+
Allow scoped, time-bound sensitive actions
|
|
32
|
+
(2FA setup, email change, account deletion, etc.)
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
The verified state must:
|
|
36
|
+
- Have explicit scope
|
|
37
|
+
- Have explicit expiration
|
|
38
|
+
- Never be implicitly reused
|
|
39
|
+
- Never be shared across sessions or contexts
|
|
12
40
|
|
|
13
41
|
## Non-Negotiables
|
|
14
42
|
|
|
15
43
|
* Session/device visibility and revocation must exist
|
|
16
44
|
* All security-sensitive actions must be server-enforced and auditable
|
|
17
45
|
* Account recovery must require step-up verification
|
|
46
|
+
* MFA via Better Auth (no custom implementation)
|
|
18
47
|
|
|
19
48
|
## Context
|
|
20
49
|
|
|
21
50
|
Account security is about giving users control over their own safety. Users should be able to see what's accessing their account, remove suspicious sessions, and understand when something unusual happens.
|
|
22
51
|
|
|
23
|
-
But it's also about protecting users from threats they don't know about. Compromised credentials, session hijacking, social engineering attacks on support — these require proactive detection, not just user vigilance.
|
|
24
|
-
|
|
25
52
|
## Driving Questions
|
|
26
53
|
|
|
27
|
-
* Can
|
|
28
|
-
*
|
|
29
|
-
*
|
|
30
|
-
*
|
|
31
|
-
*
|
|
32
|
-
* What would a truly paranoid user want that we don't offer?
|
|
54
|
+
* Can users see all active sessions and revoke them?
|
|
55
|
+
* Is re-authentication required for all sensitive actions?
|
|
56
|
+
* What happens when an account is compromised?
|
|
57
|
+
* How does the recovery flow prevent social engineering?
|
|
58
|
+
* What security events trigger user notification?
|
|
@@ -10,25 +10,66 @@ description: Admin panel - RBAC, config, admin tools. Use when building admin UI
|
|
|
10
10
|
* **Framework**: Next.js
|
|
11
11
|
* **API**: tRPC
|
|
12
12
|
* **Database**: Neon (Postgres)
|
|
13
|
+
* **ORM**: Drizzle
|
|
14
|
+
* **Components**: Radix UI
|
|
15
|
+
* **Styling**: UnoCSS
|
|
16
|
+
|
|
17
|
+
## Bootstrap: Super Admin
|
|
18
|
+
|
|
19
|
+
Simplest possible approach:
|
|
20
|
+
|
|
21
|
+
```
|
|
22
|
+
INITIAL_SUPERADMIN_EMAIL=your@email.com
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
Flow:
|
|
26
|
+
1. Set env variable
|
|
27
|
+
2. Register with that email
|
|
28
|
+
3. Automatically elevated to super_admin
|
|
29
|
+
4. Done
|
|
30
|
+
|
|
31
|
+
Why singular:
|
|
32
|
+
- Only one initial super_admin needed
|
|
33
|
+
- They promote others via admin UI
|
|
34
|
+
- Simple = fewer bugs
|
|
35
|
+
|
|
36
|
+
The bootstrap must:
|
|
37
|
+
- Execute exactly once
|
|
38
|
+
- Be non-reentrant
|
|
39
|
+
- Not be bypassable
|
|
40
|
+
- Not become permanent logic dependency
|
|
13
41
|
|
|
14
42
|
## Non-Negotiables
|
|
15
43
|
|
|
16
|
-
* Admin bootstrap
|
|
44
|
+
* Admin bootstrap via INITIAL_SUPERADMIN_EMAIL only
|
|
17
45
|
* All privilege grants must be audited (who/when/why)
|
|
18
|
-
* Actions affecting money/access/security require step-up
|
|
46
|
+
* Actions affecting money/access/security require step-up verification
|
|
19
47
|
* Secrets must never be exposed through admin UI
|
|
48
|
+
* MFA required for admin roles
|
|
20
49
|
|
|
21
|
-
##
|
|
50
|
+
## Role Hierarchy
|
|
51
|
+
|
|
52
|
+
```
|
|
53
|
+
super_admin
|
|
54
|
+
↓ (can promote to)
|
|
55
|
+
admin
|
|
56
|
+
↓ (can manage)
|
|
57
|
+
users
|
|
58
|
+
```
|
|
22
59
|
|
|
23
|
-
|
|
60
|
+
Only super_admin can:
|
|
61
|
+
- Promote users to admin
|
|
62
|
+
- Access system configuration
|
|
63
|
+
- View audit logs
|
|
64
|
+
|
|
65
|
+
## Context
|
|
24
66
|
|
|
25
|
-
|
|
67
|
+
The admin platform is where operational power lives — and where operational mistakes happen. A well-designed admin reduces human error while giving operators tools to resolve issues quickly.
|
|
26
68
|
|
|
27
69
|
## Driving Questions
|
|
28
70
|
|
|
29
|
-
*
|
|
30
|
-
*
|
|
31
|
-
* How would we detect
|
|
71
|
+
* Is bootstrap using INITIAL_SUPERADMIN_EMAIL correctly?
|
|
72
|
+
* Can an admin accidentally cause serious damage?
|
|
73
|
+
* How would we detect admin access misuse?
|
|
32
74
|
* What repetitive admin tasks should be automated?
|
|
33
|
-
* Where is audit logging missing
|
|
34
|
-
* What would make the admin experience both safer and faster?
|
|
75
|
+
* Where is audit logging missing?
|
|
@@ -7,26 +7,42 @@ description: Authentication patterns - sign-in, SSO, passkeys, sessions. Use whe
|
|
|
7
7
|
|
|
8
8
|
## Tech Stack
|
|
9
9
|
|
|
10
|
-
* **Auth**:
|
|
10
|
+
* **Auth**: Better Auth
|
|
11
11
|
* **Framework**: Next.js
|
|
12
|
+
* **Database**: Neon (Postgres)
|
|
13
|
+
* **ORM**: Drizzle
|
|
12
14
|
|
|
13
15
|
## Non-Negotiables
|
|
14
16
|
|
|
15
17
|
* All authorization decisions must be server-enforced (no client-trust)
|
|
16
18
|
* Email verification required for high-impact capabilities
|
|
17
19
|
* If SSO provider secrets are missing, hide the option (no broken UI)
|
|
20
|
+
* Session management via Better Auth (no custom implementation)
|
|
21
|
+
|
|
22
|
+
## Auth Flow
|
|
23
|
+
|
|
24
|
+
```
|
|
25
|
+
User initiates sign-in
|
|
26
|
+
↓
|
|
27
|
+
Better Auth handles provider/credentials
|
|
28
|
+
↓
|
|
29
|
+
Session created server-side
|
|
30
|
+
↓
|
|
31
|
+
Session token in httpOnly cookie
|
|
32
|
+
↓
|
|
33
|
+
All requests validated server-side
|
|
34
|
+
```
|
|
18
35
|
|
|
19
36
|
## Context
|
|
20
37
|
|
|
21
|
-
Authentication is the front door to every user's data. It needs to be both secure and frictionless
|
|
38
|
+
Authentication is the front door to every user's data. It needs to be both secure and frictionless. Users abandon products with painful sign-in flows, but weak auth leads to compromised accounts.
|
|
22
39
|
|
|
23
|
-
|
|
40
|
+
Better Auth is the SSOT for authentication. No custom auth implementations.
|
|
24
41
|
|
|
25
42
|
## Driving Questions
|
|
26
43
|
|
|
27
|
-
*
|
|
28
|
-
*
|
|
44
|
+
* Is all auth handled by Better Auth?
|
|
45
|
+
* Are we building custom auth logic that Better Auth already provides?
|
|
46
|
+
* What's the sign-in experience for first-time vs returning users?
|
|
29
47
|
* What happens when a user loses access to their primary auth method?
|
|
30
|
-
* How does the system handle auth provider outages gracefully?
|
|
31
|
-
* What would passwordless-first auth look like here?
|
|
32
48
|
* Where is auth complexity hiding bugs or security issues?
|
|
@@ -9,26 +9,55 @@ description: Billing - Stripe, webhooks, subscriptions. Use when implementing pa
|
|
|
9
9
|
|
|
10
10
|
* **Payments**: Stripe
|
|
11
11
|
* **Workflows**: Upstash Workflows + QStash
|
|
12
|
+
* **Database**: Neon (Postgres)
|
|
13
|
+
* **ORM**: Drizzle
|
|
14
|
+
|
|
15
|
+
## Platform-Led Billing
|
|
16
|
+
|
|
17
|
+
Platform is the source of truth. Stripe syncs FROM platform, not TO it.
|
|
18
|
+
|
|
19
|
+
- Platform defines products, prices, features, entitlements
|
|
20
|
+
- Stripe is synced to match platform state
|
|
21
|
+
- No manual Stripe dashboard configuration
|
|
22
|
+
- Platform state → Stripe sync (never reverse)
|
|
23
|
+
- Stripe webhooks confirm sync success, not drive state
|
|
12
24
|
|
|
13
25
|
## Non-Negotiables
|
|
14
26
|
|
|
15
27
|
* Webhook signature must be verified (reject unverifiable events)
|
|
16
28
|
* Stripe event ID must be used for idempotency
|
|
17
29
|
* Webhooks must handle out-of-order delivery
|
|
18
|
-
*
|
|
19
|
-
*
|
|
30
|
+
* UI must only display states derivable from platform-truth
|
|
31
|
+
* No Stripe dashboard design — all configuration in code
|
|
32
|
+
|
|
33
|
+
## Subscription Lifecycle
|
|
34
|
+
|
|
35
|
+
```
|
|
36
|
+
Platform defines plan
|
|
37
|
+
↓
|
|
38
|
+
Sync to Stripe (create Product + Price)
|
|
39
|
+
↓
|
|
40
|
+
User selects plan in UI
|
|
41
|
+
↓
|
|
42
|
+
Create Stripe Checkout Session
|
|
43
|
+
↓
|
|
44
|
+
User completes payment
|
|
45
|
+
↓
|
|
46
|
+
Webhook confirms → Update platform state
|
|
47
|
+
↓
|
|
48
|
+
Entitlements derived from platform state
|
|
49
|
+
```
|
|
20
50
|
|
|
21
51
|
## Context
|
|
22
52
|
|
|
23
53
|
Billing is where trust meets money. A bug here isn't just annoying — it's a financial and legal issue. Users must always see accurate state, and the system must never lose or duplicate charges.
|
|
24
54
|
|
|
25
|
-
|
|
55
|
+
The platform owns billing logic. Stripe is a payment processor, not a product catalog.
|
|
26
56
|
|
|
27
57
|
## Driving Questions
|
|
28
58
|
|
|
59
|
+
* Is all billing configuration in code, not Stripe dashboard?
|
|
60
|
+
* Can we switch payment processors without redesigning billing?
|
|
29
61
|
* What happens when webhooks arrive out of order?
|
|
30
|
-
* Where could revenue leak (failed renewals, unhandled states)?
|
|
31
|
-
* What billing states are confusing to users?
|
|
32
62
|
* How are disputes and chargebacks handled end-to-end?
|
|
33
|
-
*
|
|
34
|
-
* What would make the billing experience genuinely excellent?
|
|
63
|
+
* Where could revenue leak (failed renewals, unhandled states)?
|
|
@@ -15,10 +15,24 @@ description: Data modeling - entities, relationships, schemas. Use when designin
|
|
|
15
15
|
## Non-Negotiables
|
|
16
16
|
|
|
17
17
|
* All authorization must be server-enforced (no client-trust)
|
|
18
|
-
*
|
|
18
|
+
* Platform is source of truth for billing/entitlements (Stripe syncs FROM platform)
|
|
19
19
|
* UI must never contradict server-truth
|
|
20
20
|
* High-value mutations must have audit trail (who/when/why/before/after)
|
|
21
21
|
|
|
22
|
+
## Platform-Led Data Flow
|
|
23
|
+
|
|
24
|
+
```
|
|
25
|
+
Platform State (SSOT)
|
|
26
|
+
↓
|
|
27
|
+
Third-party services sync FROM platform
|
|
28
|
+
↓
|
|
29
|
+
Webhooks confirm sync success
|
|
30
|
+
↓
|
|
31
|
+
Never reverse the flow
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
Platform defines products, prices, entitlements. External services reflect platform state.
|
|
35
|
+
|
|
22
36
|
## Context
|
|
23
37
|
|
|
24
38
|
Data architecture determines what's possible and what's painful. Good architecture makes new features easy; bad architecture makes everything hard. The question isn't "does it work today?" but "will it work when requirements change?"
|
|
@@ -9,24 +9,42 @@ description: Database - schema, indexes, migrations. Use when working with datab
|
|
|
9
9
|
|
|
10
10
|
* **Database**: Neon (Postgres)
|
|
11
11
|
* **ORM**: Drizzle
|
|
12
|
+
* **Migrations**: Drizzle Kit
|
|
12
13
|
|
|
13
14
|
## Non-Negotiables
|
|
14
15
|
|
|
15
16
|
* Migration files must exist, be complete, and be committed
|
|
16
17
|
* CI must fail if schema changes aren't represented by migrations
|
|
17
18
|
* No schema drift between environments
|
|
19
|
+
* All queries through Drizzle (no raw SQL unless necessary)
|
|
20
|
+
|
|
21
|
+
## Schema Design
|
|
22
|
+
|
|
23
|
+
```typescript
|
|
24
|
+
// Drizzle schema is SSOT
|
|
25
|
+
export const users = pgTable('users', {
|
|
26
|
+
id: text('id').primaryKey(),
|
|
27
|
+
email: text('email').notNull().unique(),
|
|
28
|
+
role: text('role').notNull().default('user'),
|
|
29
|
+
createdAt: timestamp('created_at').defaultNow(),
|
|
30
|
+
})
|
|
31
|
+
|
|
32
|
+
// Relations explicit
|
|
33
|
+
export const usersRelations = relations(users, ({ many }) => ({
|
|
34
|
+
sessions: many(sessions),
|
|
35
|
+
}))
|
|
36
|
+
```
|
|
18
37
|
|
|
19
38
|
## Context
|
|
20
39
|
|
|
21
|
-
The database schema is the foundation everything else is built on. A bad schema creates friction for every feature built on top of it. Schema changes are expensive and risky —
|
|
40
|
+
The database schema is the foundation everything else is built on. A bad schema creates friction for every feature built on top of it. Schema changes are expensive and risky — get the design right.
|
|
22
41
|
|
|
23
|
-
|
|
42
|
+
Drizzle is the SSOT for database access. Type-safe, end-to-end.
|
|
24
43
|
|
|
25
44
|
## Driving Questions
|
|
26
45
|
|
|
27
|
-
*
|
|
28
|
-
*
|
|
29
|
-
* What data relationships are awkward or incorrectly modeled?
|
|
30
|
-
* How does the schema handle data lifecycle (soft deletes, archival, retention)?
|
|
46
|
+
* Is all database access through Drizzle?
|
|
47
|
+
* Are migrations complete and committed?
|
|
31
48
|
* What constraints are missing that would prevent invalid state?
|
|
32
|
-
* Where
|
|
49
|
+
* Where are missing indexes causing slow queries?
|
|
50
|
+
* How does the schema handle data lifecycle?
|
|
@@ -15,27 +15,38 @@ description: Internationalization - localization, translations. Use when adding
|
|
|
15
15
|
* `/en/*` must not exist (permanently redirect to non-prefixed)
|
|
16
16
|
* Missing translation keys must fail build
|
|
17
17
|
* No hardcoded user-facing strings outside localization
|
|
18
|
-
* Translation bundles must be split by namespace
|
|
18
|
+
* Translation bundles must be split by namespace (no monolithic files)
|
|
19
|
+
* Server Components for translations wherever possible
|
|
20
|
+
|
|
21
|
+
## Bundle Strategy
|
|
22
|
+
|
|
23
|
+
```
|
|
24
|
+
messages/
|
|
25
|
+
├── en/
|
|
26
|
+
│ ├── common.json # Shared strings
|
|
27
|
+
│ ├── auth.json # Auth flow
|
|
28
|
+
│ ├── dashboard.json # Dashboard
|
|
29
|
+
│ └── settings.json # Settings
|
|
30
|
+
└── zh/
|
|
31
|
+
├── common.json
|
|
32
|
+
├── auth.json
|
|
33
|
+
├── dashboard.json
|
|
34
|
+
└── settings.json
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
Each route loads only its required namespaces.
|
|
38
|
+
Client bundles must not include server-only translations.
|
|
19
39
|
|
|
20
40
|
## Context
|
|
21
41
|
|
|
22
|
-
Internationalization isn't just translation — it's making the product feel native to each market. Bad i18n
|
|
42
|
+
Internationalization isn't just translation — it's making the product feel native to each market. Bad i18n signals users are second-class citizens. Good i18n is invisible.
|
|
23
43
|
|
|
24
|
-
|
|
44
|
+
next-intl is the SSOT for i18n. No custom implementations.
|
|
25
45
|
|
|
26
46
|
## Driving Questions
|
|
27
47
|
|
|
28
|
-
*
|
|
29
|
-
*
|
|
30
|
-
* What
|
|
31
|
-
*
|
|
32
|
-
*
|
|
33
|
-
* Where do we fall back to English in ways users would notice?
|
|
34
|
-
* How large are the translation bundles, and what's being sent to the client?
|
|
35
|
-
|
|
36
|
-
## Bundle Constraints
|
|
37
|
-
|
|
38
|
-
* No monolithic language files — split by namespace (`common`, `auth`, `dashboard`, etc.)
|
|
39
|
-
* Server Components for translations wherever possible — client bundles must not include translations that could stay on server
|
|
40
|
-
* Each route should load only its required namespaces
|
|
41
|
-
* Measure client bundle size impact of translations
|
|
48
|
+
* Is next-intl handling all translations?
|
|
49
|
+
* Are bundles split by namespace?
|
|
50
|
+
* What would make the product feel native to non-English users?
|
|
51
|
+
* Where do translations feel awkward?
|
|
52
|
+
* How large are client-side translation bundles?
|
|
@@ -16,7 +16,21 @@ description: Financial ledger - transactions, audit trails. Use when tracking mo
|
|
|
16
16
|
* Balances must be immutable ledger (append-only), not mutable fields
|
|
17
17
|
* No floating-point for money (use deterministic precision)
|
|
18
18
|
* All financial mutations must be idempotent
|
|
19
|
-
*
|
|
19
|
+
* Platform ledger is source of truth (Stripe syncs FROM platform)
|
|
20
|
+
|
|
21
|
+
## Platform-Led Financial State
|
|
22
|
+
|
|
23
|
+
```
|
|
24
|
+
Platform Ledger (SSOT)
|
|
25
|
+
↓
|
|
26
|
+
Stripe syncs from platform
|
|
27
|
+
↓
|
|
28
|
+
Webhooks confirm sync success
|
|
29
|
+
↓
|
|
30
|
+
Reconciliation verifies alignment
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
Platform defines credits, balances, transactions. Stripe reflects platform state, not the reverse.
|
|
20
34
|
|
|
21
35
|
## Context
|
|
22
36
|
|
|
@@ -14,19 +14,20 @@ description: Observability - logging, metrics, tracing. Use when adding monitori
|
|
|
14
14
|
## Non-Negotiables
|
|
15
15
|
|
|
16
16
|
* Correlation IDs must exist end-to-end (request → job → webhook)
|
|
17
|
-
* Alerts must exist for critical failures
|
|
17
|
+
* Alerts must exist for critical failures
|
|
18
|
+
* No PII in logs or error tracking
|
|
19
|
+
* Errors must be actionable, not noise
|
|
18
20
|
|
|
19
21
|
## Context
|
|
20
22
|
|
|
21
|
-
Observability is about answering questions when things go wrong. It's 3am, something is broken
|
|
23
|
+
Observability is about answering questions when things go wrong. It's 3am, something is broken — can you figure out what happened? How fast?
|
|
22
24
|
|
|
23
|
-
Good observability makes debugging easy. Bad observability means
|
|
25
|
+
Good observability makes debugging easy. Bad observability means guessing, adding logs, redeploying, hoping.
|
|
24
26
|
|
|
25
27
|
## Driving Questions
|
|
26
28
|
|
|
27
|
-
* If something breaks
|
|
29
|
+
* If something breaks now, how would we find out?
|
|
28
30
|
* What blind spots exist where errors go unnoticed?
|
|
29
|
-
* How long
|
|
30
|
-
* What alerts exist, and do they fire
|
|
31
|
-
* Where
|
|
32
|
-
* What production issue in the last month was hard to debug, and why?
|
|
31
|
+
* How long to trace a request through the system?
|
|
32
|
+
* What alerts exist, and do they fire correctly?
|
|
33
|
+
* Where is noise training people to ignore alerts?
|
|
@@ -8,24 +8,53 @@ description: Pricing strategy - tiers, feature gating. Use when designing pricin
|
|
|
8
8
|
## Tech Stack
|
|
9
9
|
|
|
10
10
|
* **Payments**: Stripe
|
|
11
|
+
* **Database**: Neon (Postgres)
|
|
12
|
+
* **ORM**: Drizzle
|
|
13
|
+
|
|
14
|
+
## Platform-Led Pricing
|
|
15
|
+
|
|
16
|
+
Platform is the source of truth for all pricing.
|
|
17
|
+
|
|
18
|
+
- Products, prices, tiers, features defined in platform code
|
|
19
|
+
- Stripe Products/Prices created via sync, not manually
|
|
20
|
+
- No Stripe dashboard configuration
|
|
21
|
+
- Pricing changes → code change → sync to Stripe
|
|
22
|
+
- Historical prices remain in Stripe (immutable)
|
|
11
23
|
|
|
12
24
|
## Non-Negotiables
|
|
13
25
|
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
26
|
+
* All pricing configuration must be in code
|
|
27
|
+
* No manual Stripe dashboard changes
|
|
28
|
+
* Pricing drift must be detectable and auto-correctable
|
|
29
|
+
* Feature entitlements derived from platform state, not Stripe metadata
|
|
30
|
+
|
|
31
|
+
## Pricing Model
|
|
32
|
+
|
|
33
|
+
```typescript
|
|
34
|
+
// Platform defines pricing (code is SSOT)
|
|
35
|
+
const plans = {
|
|
36
|
+
free: { price: 0, features: ['basic'] },
|
|
37
|
+
pro: { price: 29, features: ['basic', 'advanced', 'priority'] },
|
|
38
|
+
enterprise: { price: 299, features: ['basic', 'advanced', 'priority', 'sla'] }
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// Sync to Stripe on deploy/startup
|
|
42
|
+
await syncPricingToStripe(plans)
|
|
43
|
+
```
|
|
17
44
|
|
|
18
45
|
## Context
|
|
19
46
|
|
|
20
|
-
Pricing is strategy, not just configuration. The right pricing captures value, reduces friction, and aligns incentives.
|
|
47
|
+
Pricing is strategy, not just configuration. The right pricing captures value, reduces friction, and aligns incentives.
|
|
21
48
|
|
|
22
|
-
|
|
49
|
+
Platform owns pricing. Stripe is the payment processor. This separation allows:
|
|
50
|
+
- A/B testing pricing without Stripe changes
|
|
51
|
+
- Switching processors without repricing
|
|
52
|
+
- Complex entitlement logic beyond Stripe's model
|
|
23
53
|
|
|
24
54
|
## Driving Questions
|
|
25
55
|
|
|
26
|
-
*
|
|
27
|
-
*
|
|
56
|
+
* Is all pricing defined in code?
|
|
57
|
+
* Can we change pricing without touching Stripe dashboard?
|
|
58
|
+
* How do we test pricing changes before going live?
|
|
28
59
|
* What would make upgrading feel like an obvious decision?
|
|
29
|
-
* How do we communicate value at each
|
|
30
|
-
* What pricing experiments would teach us the most?
|
|
31
|
-
* If we could change one thing about pricing, what would have the biggest impact?
|
|
60
|
+
* How do we communicate value at each tier?
|
|
@@ -9,24 +9,39 @@ description: File storage - uploads, CDN, blobs. Use when handling files.
|
|
|
9
9
|
|
|
10
10
|
* **Storage**: Vercel Blob
|
|
11
11
|
* **Platform**: Vercel
|
|
12
|
+
* **Framework**: Next.js
|
|
12
13
|
|
|
13
14
|
## Non-Negotiables
|
|
14
15
|
|
|
15
|
-
* Uploads must be intent-based and server-verified
|
|
16
|
+
* Uploads must be intent-based and server-verified
|
|
17
|
+
* No direct client uploads to permanent storage
|
|
16
18
|
* Server must validate blob ownership before attaching to resources
|
|
17
19
|
* Abandoned uploads must be cleanable
|
|
18
20
|
|
|
21
|
+
## Upload Flow
|
|
22
|
+
|
|
23
|
+
```
|
|
24
|
+
Client requests upload URL
|
|
25
|
+
↓
|
|
26
|
+
Server creates signed upload token
|
|
27
|
+
↓
|
|
28
|
+
Client uploads to Vercel Blob
|
|
29
|
+
↓
|
|
30
|
+
Server validates and attaches to resource
|
|
31
|
+
↓
|
|
32
|
+
Orphaned blobs cleaned periodically
|
|
33
|
+
```
|
|
34
|
+
|
|
19
35
|
## Context
|
|
20
36
|
|
|
21
|
-
File uploads are a common attack vector. Users upload things you don't expect. Files live longer than you plan. Storage costs accumulate quietly.
|
|
37
|
+
File uploads are a common attack vector. Users upload things you don't expect. Files live longer than you plan. Storage costs accumulate quietly.
|
|
22
38
|
|
|
23
|
-
|
|
39
|
+
Vercel Blob is the SSOT for file storage. No custom implementations.
|
|
24
40
|
|
|
25
41
|
## Driving Questions
|
|
26
42
|
|
|
27
|
-
*
|
|
28
|
-
*
|
|
29
|
-
*
|
|
43
|
+
* Is all storage through Vercel Blob?
|
|
44
|
+
* Are uploads validated server-side?
|
|
45
|
+
* What happens to orphaned files?
|
|
30
46
|
* What file types do we accept, and should we?
|
|
31
|
-
* How
|
|
32
|
-
* What content validation exists (type, size, safety)?
|
|
47
|
+
* How much are we spending on storage?
|
|
@@ -8,23 +8,48 @@ description: UI/UX - design system, accessibility. Use when building interfaces.
|
|
|
8
8
|
## Tech Stack
|
|
9
9
|
|
|
10
10
|
* **Framework**: Next.js
|
|
11
|
+
* **Components**: Radix UI
|
|
12
|
+
* **Styling**: UnoCSS
|
|
11
13
|
* **Icons**: Iconify
|
|
12
14
|
|
|
15
|
+
## Radix UI Everywhere
|
|
16
|
+
|
|
17
|
+
Use Radix UI comprehensively. If Radix has a primitive for it, use it.
|
|
18
|
+
No custom implementations of solved problems.
|
|
19
|
+
No alternative component libraries.
|
|
20
|
+
|
|
21
|
+
Radix primitives are the SSOT for:
|
|
22
|
+
- Dialogs, modals, sheets
|
|
23
|
+
- Dropdowns, menus, context menus
|
|
24
|
+
- Popovers, tooltips, hover cards
|
|
25
|
+
- Tabs, accordions, collapsibles
|
|
26
|
+
- Select, combobox, radio, checkbox, switch
|
|
27
|
+
- Sliders, progress, scroll areas
|
|
28
|
+
- Navigation, breadcrumbs
|
|
29
|
+
- Toasts, alerts
|
|
30
|
+
- Avatar, aspect ratio, separator
|
|
31
|
+
|
|
32
|
+
When similar UI problems arise, solve once with Radix, then reuse.
|
|
33
|
+
|
|
13
34
|
## Non-Negotiables
|
|
14
35
|
|
|
15
36
|
* WCAG AA accessibility compliance
|
|
37
|
+
* Radix UI for all interactive components
|
|
38
|
+
* UnoCSS for styling (no Tailwind)
|
|
39
|
+
* Iconify for all icons
|
|
40
|
+
* Responsive design for all viewports
|
|
16
41
|
|
|
17
42
|
## Context
|
|
18
43
|
|
|
19
44
|
UI/UX determines how users perceive and interact with the product. A great UI isn't just "correct" — it's delightful, intuitive, and makes complex tasks feel simple.
|
|
20
45
|
|
|
21
|
-
|
|
46
|
+
Radix provides accessible, unstyled primitives. UnoCSS provides atomic styling. Together they enable consistent, accessible UI without reinventing components.
|
|
22
47
|
|
|
23
48
|
## Driving Questions
|
|
24
49
|
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
*
|
|
28
|
-
*
|
|
29
|
-
* What
|
|
30
|
-
*
|
|
50
|
+
* Is every interactive component using Radix?
|
|
51
|
+
* Are we building custom components Radix already provides?
|
|
52
|
+
* Is the design consistent across the product?
|
|
53
|
+
* Where do users get confused or frustrated?
|
|
54
|
+
* What would make this experience genuinely delightful?
|
|
55
|
+
* How does the UI behave on mobile vs desktop?
|
package/package.json
CHANGED