@everystack/mcp 0.2.2 → 0.3.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/LICENSE +681 -0
- package/README.md +45 -10
- package/dist/adding-database.md +169 -0
- package/dist/admin.md +81 -0
- package/dist/auth.md +115 -0
- package/dist/aws-setup.md +276 -0
- package/dist/cli.md +108 -0
- package/dist/client-api.md +145 -0
- package/dist/core.md +196 -0
- package/dist/deployment.md +146 -0
- package/dist/events.md +87 -0
- package/dist/first-run.md +100 -0
- package/dist/getting-started.md +75 -0
- package/dist/handler-options.md +114 -0
- package/dist/images.md +93 -0
- package/dist/index.cjs +23726 -0
- package/dist/jobs.md +97 -0
- package/dist/logging.md +91 -0
- package/dist/plugins.md +68 -0
- package/dist/project-claude-md.md +102 -0
- package/dist/query-protocol.md +129 -0
- package/dist/schema-patterns.md +167 -0
- package/dist/security-device.md +99 -0
- package/dist/security.md +270 -0
- package/dist/ssr.md +82 -0
- package/dist/storage.md +63 -0
- package/dist/testing.md +118 -0
- package/package.json +26 -14
- package/src/gates/detectors/embedded-data-bundle.ts +58 -0
- package/src/gates/detectors/hand-written-migration.ts +42 -0
- package/src/gates/detectors/secret-in-public-env.ts +41 -0
- package/src/gates/engine.ts +80 -0
- package/src/gates/registry.ts +25 -0
- package/src/gates/telemetry.ts +143 -0
- package/src/gates/types.ts +70 -0
- package/src/governance/cli.ts +193 -0
- package/src/governance/grounding.ts +344 -0
- package/src/index.ts +97 -50
- package/src/prompts/claude-md.ts +90 -0
- package/src/prompts/governance-setup.ts +85 -0
- package/src/prompts/index.ts +4 -0
- package/src/prompts/new-app.ts +4 -1
- package/src/resources/project-claude-md.md +69 -94
- package/src/tools/index.ts +6 -39
package/dist/core.md
ADDED
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
# everystack
|
|
2
|
+
|
|
3
|
+
Self-hosted application stack for Expo apps on AWS. Start with a static site, add database/auth/jobs as you grow. Each tier builds on the previous -- you never rip out what you have, you add to it.
|
|
4
|
+
|
|
5
|
+
## Tiers
|
|
6
|
+
|
|
7
|
+
### V1: Static Site (no database)
|
|
8
|
+
- Expo app exported to static assets, served from CloudFront
|
|
9
|
+
- Lambda SSR for SEO (server-rendered HTML with OG meta, JSON-LD)
|
|
10
|
+
- OTA updates via `everystack update` (instant deploys without redeploying infrastructure)
|
|
11
|
+
- **Packages:** `@everystack/server`, `@everystack/cli`, `@everystack/ui`
|
|
12
|
+
- **Infrastructure:** S3 + CloudFront + Lambda + S3 (updates bucket)
|
|
13
|
+
|
|
14
|
+
### V2: Dynamic App (database + auth)
|
|
15
|
+
- PostgreSQL via RDS Aurora Serverless
|
|
16
|
+
- PostgREST-compatible REST API (filters, pagination, relations, RPC)
|
|
17
|
+
- JWT auth (signup, signin, refresh, edge verification)
|
|
18
|
+
- Admin dashboard (config-driven, EverystackAdapter)
|
|
19
|
+
- Structured logging and analytics
|
|
20
|
+
- **Adds:** `@everystack/api`, `@everystack/auth`, `@everystack/admin`, `@everystack/logging`, `@everystack/query`, `@everystack/security`
|
|
21
|
+
- **Infrastructure:** V1 + RDS Aurora Serverless
|
|
22
|
+
|
|
23
|
+
### V3: Full Platform (jobs + media)
|
|
24
|
+
- SQS background workers with dead letter queue
|
|
25
|
+
- On-demand image resizing via Sharp on Lambda
|
|
26
|
+
- S3 file uploads with presigned URLs and CDN delivery
|
|
27
|
+
- **Adds:** `@everystack/jobs`, `@everystack/storage`, `@everystack/images`
|
|
28
|
+
- **Infrastructure:** V2 + SQS + Worker Lambda + Image Lambda + Media S3
|
|
29
|
+
|
|
30
|
+
## Package Map
|
|
31
|
+
|
|
32
|
+
| Package | Purpose |
|
|
33
|
+
|---------|---------|
|
|
34
|
+
| `@everystack/server` | Lambda handler, router, DB connection, SSR, image processing, worker, plugin system |
|
|
35
|
+
| `@everystack/api` | PostgREST-compatible handler (`createHandler`) + typed client (`createClient`) |
|
|
36
|
+
| `@everystack/auth` | JWT auth flows, OAuth, password hashing, edge verification, React AuthProvider |
|
|
37
|
+
| `@everystack/cli` | CLI binary (`everystack`), OTA updates handler, storage adapters |
|
|
38
|
+
| `@everystack/admin` | Declarative admin dashboard, EverystackAdapter, presets |
|
|
39
|
+
| `@everystack/logging` | Structured logging, crash reports, analytics, S3 storage, CloudWatch trigger |
|
|
40
|
+
| `@everystack/query` | React Query hooks for PostgREST APIs |
|
|
41
|
+
| `@everystack/security` | Device attestation (Apple/Google), biometric auth, RS256 keys |
|
|
42
|
+
| `@everystack/jobs` | SQS background workers, job dispatch, Postgres materialization |
|
|
43
|
+
| `@everystack/storage` | S3 uploads, presigned URLs, MIME validation, ownership enforcement |
|
|
44
|
+
| `@everystack/images` | Sharp image processing, variant generation, EXIF extraction |
|
|
45
|
+
| `@everystack/events` | PostgreSQL LISTEN/NOTIFY, WebSocket fan-out, Lambda event bridge |
|
|
46
|
+
| `@everystack/ui` | React Native components, charts, MDX support |
|
|
47
|
+
|
|
48
|
+
## Core Insight: Two Paths, One Database
|
|
49
|
+
|
|
50
|
+
The central design decision (V2+). SSR and mobile share the same PostgreSQL database but access it differently:
|
|
51
|
+
|
|
52
|
+
- **Mobile app** -> HTTP -> PostgREST handler -> Drizzle -> PostgreSQL
|
|
53
|
+
- **SSR loader** -> Drizzle directly -> PostgreSQL (same Lambda process, zero network overhead)
|
|
54
|
+
|
|
55
|
+
Both paths use the same Drizzle schema as source of truth. One deployment unit (single Lambda), shared connection pool, no inter-service latency.
|
|
56
|
+
|
|
57
|
+
## Project Structure Conventions
|
|
58
|
+
|
|
59
|
+
```
|
|
60
|
+
my-app/
|
|
61
|
+
├── app/ # Expo Router pages + API routes
|
|
62
|
+
│ ├── api/
|
|
63
|
+
│ │ └── [...path]+api.ts # Catch-all API route (mounts handler)
|
|
64
|
+
│ ├── admin/ # Admin dashboard pages
|
|
65
|
+
│ └── (tabs)/ # App screens
|
|
66
|
+
├── db/
|
|
67
|
+
│ └── schema.ts # Drizzle schema (your tables)
|
|
68
|
+
├── drizzle/ # SQL migration files (generated by drizzle-kit)
|
|
69
|
+
├── server/
|
|
70
|
+
│ ├── api.ts # Main Lambda handler (createLambdaHandler)
|
|
71
|
+
│ ├── worker.ts # Background worker handler (V3)
|
|
72
|
+
│ ├── image.ts # Image processing handler (V3)
|
|
73
|
+
│ ├── rpc/ # Custom RPC functions
|
|
74
|
+
│ └── plugins/ # Plugin compositions
|
|
75
|
+
├── lib/
|
|
76
|
+
│ ├── api.ts # Client re-exports (createClient config)
|
|
77
|
+
│ └── auth-context.tsx # Auth context provider
|
|
78
|
+
├── sst.config.ts # Infrastructure definition
|
|
79
|
+
├── app.json # Expo config
|
|
80
|
+
└── package.json
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
## Handler Quick Reference
|
|
84
|
+
|
|
85
|
+
```typescript
|
|
86
|
+
import { createHandler } from '@everystack/api/handler';
|
|
87
|
+
|
|
88
|
+
const handler = createHandler(db, schema, {
|
|
89
|
+
basePath: '/api', // URL prefix to strip
|
|
90
|
+
auth: {
|
|
91
|
+
verifyToken: async (token) => payload, // JWT verification
|
|
92
|
+
publicRoutes: ['GET'], // Methods that skip auth
|
|
93
|
+
publicRpc: ['health'], // RPC functions that skip auth
|
|
94
|
+
roleHierarchy: ['public', 'authenticated', 'admin'],
|
|
95
|
+
},
|
|
96
|
+
pgSettings: (user, client) => ({ // RLS context injection
|
|
97
|
+
role: user?.role === 'admin' ? 'admin' : user ? 'authenticated' : 'anon',
|
|
98
|
+
'request.jwt.claims': JSON.stringify(user || { role: 'anon' }),
|
|
99
|
+
}),
|
|
100
|
+
relations: { posts: { author: { table: 'users', from: 'authorId', to: 'id' } } },
|
|
101
|
+
rpc: { timeline: { fn: async (body, user) => {}, role: 'authenticated' } },
|
|
102
|
+
exposedTables: ['posts', 'profiles'], // Whitelist (404 for others)
|
|
103
|
+
hiddenColumns: { users: ['passwordHash'] }, // Strip from responses
|
|
104
|
+
protectedFields: { profiles: ['role'] }, // Strip from writes
|
|
105
|
+
rowOwnership: { posts: { column: 'authorId', userField: 'sub' } },
|
|
106
|
+
hooks: { posts: { beforeCreate: async (body, user) => ({ ...body, authorId: user?.sub }) } },
|
|
107
|
+
softDelete: { column: 'deletedAt', tables: ['posts'] },
|
|
108
|
+
maxEmbedDepth: 3,
|
|
109
|
+
maxLimit: 1000,
|
|
110
|
+
});
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
Returns `(request: Request) => Promise<Response>` -- Web Standard interface. Works with Expo Router, Cloudflare Workers, Deno, Bun.
|
|
114
|
+
|
|
115
|
+
## Lambda Handler
|
|
116
|
+
|
|
117
|
+
```typescript
|
|
118
|
+
import { createLambdaHandler } from '@everystack/server';
|
|
119
|
+
|
|
120
|
+
export const handler = createLambdaHandler({
|
|
121
|
+
init: async () => ({ api, auth }), // Lazy init, returns handler map
|
|
122
|
+
routes: (h) => [ // Route dispatch
|
|
123
|
+
{ path: '/api/auth/signup', method: 'POST', exact: true, handler: h.signup },
|
|
124
|
+
{ path: '/api', handler: h.api }, // Catch-all for PostgREST
|
|
125
|
+
],
|
|
126
|
+
onAction: async (action, payload) => { // CLI invocations via IAM
|
|
127
|
+
if (action === 'migrate') return runMigrations();
|
|
128
|
+
if (action === 'seed') return runSeed();
|
|
129
|
+
},
|
|
130
|
+
});
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
## Client
|
|
134
|
+
|
|
135
|
+
```typescript
|
|
136
|
+
import { createClient } from '@everystack/api/client';
|
|
137
|
+
|
|
138
|
+
const api = createClient({
|
|
139
|
+
baseUrl: '/api',
|
|
140
|
+
getToken: () => token,
|
|
141
|
+
onTokenExpired: async () => newToken, // Auto-refresh with deduplication
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
// Queries
|
|
145
|
+
const { data } = await api.from('posts').eq('status', 'published').order('createdAt', 'desc').limit(10).execute();
|
|
146
|
+
const { data } = await api.from('posts').select('*,author(email)').execute();
|
|
147
|
+
|
|
148
|
+
// Mutations
|
|
149
|
+
await api.from('posts').insert({ body: 'Hello', authorId: user.sub });
|
|
150
|
+
await api.from('posts').eq('id', 1).update({ body: 'Updated' });
|
|
151
|
+
await api.from('posts').eq('id', 1).delete();
|
|
152
|
+
|
|
153
|
+
// RPC
|
|
154
|
+
const { data } = await api.rpc('timeline', { limit: 20 });
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
## CLI Commands
|
|
158
|
+
|
|
159
|
+
All infrastructure commands use **AWS IAM credentials** (not shared secrets).
|
|
160
|
+
|
|
161
|
+
| Command | What it does |
|
|
162
|
+
|---------|-------------|
|
|
163
|
+
| `everystack update --channel production` | OTA deploy (no infrastructure changes) |
|
|
164
|
+
| `everystack db:migrate` | Run Drizzle migrations via Lambda invoke |
|
|
165
|
+
| `everystack db:seed` | Seed database via Lambda invoke (dev only) |
|
|
166
|
+
| `everystack db:psql --stage dev -c "SQL"` | Execute read-only SQL via Lambda |
|
|
167
|
+
| `everystack console --stage dev` | Interactive REPL with db + schema in scope |
|
|
168
|
+
| `everystack logs:errors --stage dev` | Query recent error logs |
|
|
169
|
+
| `everystack logs:tail --stage dev` | Tail CloudWatch Lambda logs |
|
|
170
|
+
| `everystack logs:query --stage dev` | Flexible log search with filters |
|
|
171
|
+
| `everystack cache:purge` | Bust CloudFront cache via KVS |
|
|
172
|
+
| `everystack certs:generate` | Generate RSA key pair for code signing |
|
|
173
|
+
| `everystack diag URL` | Diagnose deployed page freshness |
|
|
174
|
+
| `everystack analyze:ssr` | Static analysis for SSR anti-patterns |
|
|
175
|
+
|
|
176
|
+
## Key Patterns
|
|
177
|
+
|
|
178
|
+
**Schema-agnostic.** The library knows nothing about your tables. You pass your Drizzle schema to `createHandler()`. Your schema, your migrations, your database.
|
|
179
|
+
|
|
180
|
+
**Web Standards.** Handler uses Request/Response. No Express, no Fastify. Works with any Web Standard runtime.
|
|
181
|
+
|
|
182
|
+
**SST for infrastructure.** Resource linking injects secrets at deploy time (no env vars). `_action` dispatch lets the CLI invoke Lambda directly via IAM.
|
|
183
|
+
|
|
184
|
+
**Progressive complexity.** Install only what you need. V1 has zero database code. V2 adds it. V3 adds workers. Each tier is additive.
|
|
185
|
+
|
|
186
|
+
**Plugin architecture.** Packages provide plugins (`@everystack/auth/plugin`, `@everystack/jobs/plugin`) that compose into a single Lambda handler via `createPluginLambdaHandler`.
|
|
187
|
+
|
|
188
|
+
## Conventions
|
|
189
|
+
|
|
190
|
+
- TypeScript strict mode, named exports only (no default exports)
|
|
191
|
+
- Files: `kebab-case.ts`. Types: `PascalCase`. Functions: `camelCase`
|
|
192
|
+
- Tests in `__tests__/` mirroring source, named `{feature}.test.ts`
|
|
193
|
+
- Conventional commits: `feat:`, `fix:`, `chore:`, `docs:`, `test:`
|
|
194
|
+
- TDD: write failing test first, implement, refactor
|
|
195
|
+
- Zero runtime dependencies in the API library
|
|
196
|
+
- Peer dependencies for optional integrations
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
# Deployment Guide
|
|
2
|
+
|
|
3
|
+
> SST deployment: infrastructure setup, secrets, stages, CloudFront configuration.
|
|
4
|
+
|
|
5
|
+
## When to Use
|
|
6
|
+
Read this when deploying an everystack app to AWS for the first time or adding a new stage.
|
|
7
|
+
|
|
8
|
+
## Prerequisites
|
|
9
|
+
|
|
10
|
+
- Node.js 20+, pnpm
|
|
11
|
+
- AWS account with credentials (`aws configure`)
|
|
12
|
+
- SST CLI (`pnpm add -g sst`)
|
|
13
|
+
|
|
14
|
+
## SST Config
|
|
15
|
+
|
|
16
|
+
```typescript
|
|
17
|
+
// sst.config.ts
|
|
18
|
+
export default $config({
|
|
19
|
+
app(input) {
|
|
20
|
+
return {
|
|
21
|
+
name: 'my-app',
|
|
22
|
+
removal: input?.stage === 'production' ? 'retain' : 'remove',
|
|
23
|
+
home: 'aws',
|
|
24
|
+
};
|
|
25
|
+
},
|
|
26
|
+
async run() {
|
|
27
|
+
// V1: Static site
|
|
28
|
+
const updates = new sst.aws.Bucket('Updates');
|
|
29
|
+
|
|
30
|
+
// V2: Add database
|
|
31
|
+
const vpc = new sst.aws.Vpc('Vpc');
|
|
32
|
+
const database = new sst.aws.Postgres('Database', {
|
|
33
|
+
vpc,
|
|
34
|
+
scaling: { min: '0.5 ACU', max: '2 ACU' },
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
// V3: Add queues + media
|
|
38
|
+
const media = new sst.aws.Bucket('Media');
|
|
39
|
+
const dlq = new sst.aws.Queue('DeadLetterQueue');
|
|
40
|
+
const jobs = new sst.aws.Queue('Jobs', { dlq: dlq.arn });
|
|
41
|
+
|
|
42
|
+
// Lambda functions
|
|
43
|
+
const api = new sst.aws.Function('Api', {
|
|
44
|
+
handler: 'server/api.handler',
|
|
45
|
+
link: [database, updates],
|
|
46
|
+
vpc,
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
// V3: Worker + Image Lambdas
|
|
50
|
+
const worker = new sst.aws.Function('Worker', {
|
|
51
|
+
handler: 'server/worker.handler',
|
|
52
|
+
link: [database, jobs, media],
|
|
53
|
+
vpc,
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
// CDN
|
|
57
|
+
const router = new sst.aws.Router('Router', {
|
|
58
|
+
routes: { '/*': api.url },
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
// CLI needs these outputs
|
|
62
|
+
return {
|
|
63
|
+
routerUrl: router.url,
|
|
64
|
+
apiFunctionName: api.name,
|
|
65
|
+
updatesBucket: updates.name,
|
|
66
|
+
clientBundlesBucket: updates.name,
|
|
67
|
+
};
|
|
68
|
+
},
|
|
69
|
+
});
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
## Secrets
|
|
73
|
+
|
|
74
|
+
SST secrets are per-stage, encrypted, stored in S3:
|
|
75
|
+
|
|
76
|
+
```bash
|
|
77
|
+
pnpm sst secret set JwtSecret "$(openssl rand -base64 32)" --stage dev
|
|
78
|
+
pnpm sst secret set JwtSecret "$(openssl rand -base64 64)" --stage production
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
Access in code via Resource linking: `Resource.JwtSecret.value`. Never in env vars or code.
|
|
82
|
+
|
|
83
|
+
## Stages
|
|
84
|
+
|
|
85
|
+
```bash
|
|
86
|
+
pnpm sst deploy --stage dev # Development
|
|
87
|
+
pnpm sst deploy --stage production # Production
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
Each stage gets isolated resources (separate database, buckets, Lambda functions). Use `removal: 'retain'` for production to prevent accidental deletion.
|
|
91
|
+
|
|
92
|
+
## Deploy Flow
|
|
93
|
+
|
|
94
|
+
```bash
|
|
95
|
+
# 1. Deploy infrastructure + code
|
|
96
|
+
pnpm sst deploy --stage dev
|
|
97
|
+
|
|
98
|
+
# 2. Export + publish app bundles
|
|
99
|
+
everystack update --stage dev
|
|
100
|
+
|
|
101
|
+
# 3. Run migrations
|
|
102
|
+
everystack db:migrate
|
|
103
|
+
|
|
104
|
+
# 4. Seed database (dev only)
|
|
105
|
+
everystack db:seed
|
|
106
|
+
|
|
107
|
+
# 5. Subsequent content updates (no deploy needed)
|
|
108
|
+
everystack update --channel production
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
## Resource Linking
|
|
112
|
+
|
|
113
|
+
SST injects resource details into Lambda at deploy time:
|
|
114
|
+
|
|
115
|
+
```typescript
|
|
116
|
+
import { Resource } from 'sst';
|
|
117
|
+
|
|
118
|
+
// Database credentials (automatic from sst.aws.Postgres)
|
|
119
|
+
Resource.Database.host
|
|
120
|
+
Resource.Database.port
|
|
121
|
+
Resource.Database.database
|
|
122
|
+
Resource.Database.username
|
|
123
|
+
Resource.Database.password
|
|
124
|
+
|
|
125
|
+
// Secrets
|
|
126
|
+
Resource.JwtSecret.value
|
|
127
|
+
|
|
128
|
+
// Buckets
|
|
129
|
+
Resource.Updates.name
|
|
130
|
+
Resource.Media.name
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
No env vars needed. `@everystack/server/db` provides `createDb()` which reads these automatically.
|
|
134
|
+
|
|
135
|
+
## AWS IAM Profiles
|
|
136
|
+
|
|
137
|
+
See everystack://security for the three-profile model (everystack-create, everystack-manage, everystack-deploy).
|
|
138
|
+
|
|
139
|
+
## Gotchas
|
|
140
|
+
|
|
141
|
+
- First deploy creates VPC + RDS (can take 10-15 minutes)
|
|
142
|
+
- Database credentials are managed by SST/RDS (no manual password management)
|
|
143
|
+
- `sst dev` provides live Lambda debugging with hot reload
|
|
144
|
+
- `removal: 'remove'` deletes all resources when the stage is removed
|
|
145
|
+
- `removal: 'retain'` keeps RDS and S3 even if the stage is removed
|
|
146
|
+
- Outputs are written to `.sst/outputs.json` (used by CLI for auto-discovery)
|
package/dist/events.md
ADDED
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
# Events & WebSocket
|
|
2
|
+
|
|
3
|
+
> Real-time events via PostgreSQL LISTEN/NOTIFY and WebSocket fan-out. Import from `@everystack/events`.
|
|
4
|
+
|
|
5
|
+
## When to Use
|
|
6
|
+
Read this when adding real-time updates: live feeds, notifications, collaborative editing.
|
|
7
|
+
|
|
8
|
+
## Setup
|
|
9
|
+
|
|
10
|
+
```typescript
|
|
11
|
+
import { createEventHandler } from '@everystack/events/handler';
|
|
12
|
+
|
|
13
|
+
const events = createEventHandler({
|
|
14
|
+
db,
|
|
15
|
+
channels: ['table:posts', 'table:profiles', 'user:notifications'],
|
|
16
|
+
});
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## How It Works
|
|
20
|
+
|
|
21
|
+
1. Database change triggers NOTIFY on a channel
|
|
22
|
+
2. Listener Lambda receives the notification
|
|
23
|
+
3. Fan-out via WebSocket to connected clients
|
|
24
|
+
4. Client `useSignal` hook fires callback
|
|
25
|
+
|
|
26
|
+
## Client Hook
|
|
27
|
+
|
|
28
|
+
```typescript
|
|
29
|
+
import { useSignal } from '@everystack/events/client';
|
|
30
|
+
|
|
31
|
+
function PostList() {
|
|
32
|
+
const [posts, setPosts] = useState(initialPosts);
|
|
33
|
+
|
|
34
|
+
useSignal('table:posts', () => {
|
|
35
|
+
// Refetch when posts table changes
|
|
36
|
+
refetchPosts().then(setPosts);
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
return <FlatList data={posts} />;
|
|
40
|
+
}
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
## Database Trigger
|
|
44
|
+
|
|
45
|
+
```sql
|
|
46
|
+
CREATE OR REPLACE FUNCTION notify_table_change()
|
|
47
|
+
RETURNS trigger AS $$
|
|
48
|
+
BEGIN
|
|
49
|
+
PERFORM pg_notify('table:' || TG_TABLE_NAME, json_build_object(
|
|
50
|
+
'operation', TG_OP,
|
|
51
|
+
'id', COALESCE(NEW.id, OLD.id)
|
|
52
|
+
)::text);
|
|
53
|
+
RETURN COALESCE(NEW, OLD);
|
|
54
|
+
END;
|
|
55
|
+
$$ LANGUAGE plpgsql;
|
|
56
|
+
|
|
57
|
+
CREATE TRIGGER posts_notify
|
|
58
|
+
AFTER INSERT OR UPDATE OR DELETE ON posts
|
|
59
|
+
FOR EACH ROW EXECUTE FUNCTION notify_table_change();
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
## Actions
|
|
63
|
+
|
|
64
|
+
```typescript
|
|
65
|
+
import { createEventActions } from '@everystack/events/actions';
|
|
66
|
+
|
|
67
|
+
const actions = createEventActions({
|
|
68
|
+
invokeFunction: Resource.ListenerFunction.name,
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
// Trigger from API handler
|
|
72
|
+
await actions.notify('user:notifications', { userId: 'abc', message: 'New follower' });
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
## Schema
|
|
76
|
+
|
|
77
|
+
```typescript
|
|
78
|
+
import { eventsSchema } from '@everystack/events/schema';
|
|
79
|
+
// Adds: event_subscriptions table for persistent subscriptions
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
## Gotchas
|
|
83
|
+
|
|
84
|
+
- LISTEN/NOTIFY is per-database-connection (not per-Lambda)
|
|
85
|
+
- The listener Lambda must maintain a persistent connection
|
|
86
|
+
- WebSocket connections are managed separately from HTTP
|
|
87
|
+
- Payload size limit for NOTIFY is 8000 bytes
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
# Running Your App Locally
|
|
2
|
+
|
|
3
|
+
You have a project. Now let's see it work.
|
|
4
|
+
|
|
5
|
+
## Starting the dev server
|
|
6
|
+
|
|
7
|
+
Run this command from your project directory:
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
npx expo start
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
Or if you have pnpm installed:
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
pnpm dev
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## What you'll see
|
|
20
|
+
|
|
21
|
+
The terminal will show output like this:
|
|
22
|
+
|
|
23
|
+
```
|
|
24
|
+
Starting Metro Bundler
|
|
25
|
+
▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄
|
|
26
|
+
█ QR CODE HERE █
|
|
27
|
+
▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀
|
|
28
|
+
|
|
29
|
+
› Press w │ open web
|
|
30
|
+
› Press i │ open iOS simulator
|
|
31
|
+
› Press a │ open Android emulator
|
|
32
|
+
› Press r │ reload app
|
|
33
|
+
› Press j │ open debugger
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
**Metro Bundler** is the tool that packages your code so a browser or phone can run it. It starts automatically.
|
|
37
|
+
|
|
38
|
+
## Opening in a browser
|
|
39
|
+
|
|
40
|
+
Press **w** in the terminal. Your browser will open to something like `http://localhost:8081`. You should see your app's home screen.
|
|
41
|
+
|
|
42
|
+
If `w` doesn't work, open your browser manually and go to `http://localhost:8081`.
|
|
43
|
+
|
|
44
|
+
## Opening on your phone
|
|
45
|
+
|
|
46
|
+
Install the **Expo Go** app from the App Store (iPhone) or Google Play (Android). Then scan the QR code shown in the terminal with your phone's camera. The app will load on your phone over your local Wi-Fi network.
|
|
47
|
+
|
|
48
|
+
Your phone and computer must be on the same Wi-Fi network for this to work.
|
|
49
|
+
|
|
50
|
+
## Hot reload
|
|
51
|
+
|
|
52
|
+
When you change a file and save it, the app updates automatically. You don't need to restart anything. This is called **hot reload**.
|
|
53
|
+
|
|
54
|
+
Try it: open `app/index.tsx` in your editor, change some text, save the file, and watch the browser or phone update.
|
|
55
|
+
|
|
56
|
+
## Stopping the server
|
|
57
|
+
|
|
58
|
+
Press **Ctrl+C** in the terminal. This stops the dev server. Your app will stop working in the browser until you start it again.
|
|
59
|
+
|
|
60
|
+
## Common issues
|
|
61
|
+
|
|
62
|
+
### "Port 8081 is already in use"
|
|
63
|
+
|
|
64
|
+
Something else is using that port. Either stop the other program, or start Expo on a different port:
|
|
65
|
+
|
|
66
|
+
```bash
|
|
67
|
+
npx expo start --port 8082
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
### "Unable to resolve module"
|
|
71
|
+
|
|
72
|
+
A package is missing. Run:
|
|
73
|
+
|
|
74
|
+
```bash
|
|
75
|
+
pnpm install
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
Then try starting again.
|
|
79
|
+
|
|
80
|
+
### The app is stuck or shows an old version
|
|
81
|
+
|
|
82
|
+
Clear the Metro cache and restart:
|
|
83
|
+
|
|
84
|
+
```bash
|
|
85
|
+
npx expo start --clear
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
### "Network response timed out" on phone
|
|
89
|
+
|
|
90
|
+
Your phone and computer aren't on the same network, or a firewall is blocking the connection. Make sure both are on the same Wi-Fi.
|
|
91
|
+
|
|
92
|
+
### White screen or "Something went wrong"
|
|
93
|
+
|
|
94
|
+
Check the terminal for red error text. The error message will tell you what's wrong. Copy the error and ask Claude for help.
|
|
95
|
+
|
|
96
|
+
## What's next
|
|
97
|
+
|
|
98
|
+
Once your app runs locally and you can see changes in real time, you're ready to start building. Describe what you want to add and Claude will help you implement it.
|
|
99
|
+
|
|
100
|
+
When you're ready to put your app on the internet so others can use it, you'll set up AWS and deploy. That's a separate step — there's no rush. Build locally first, deploy when you're ready.
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
# What is everystack?
|
|
2
|
+
|
|
3
|
+
everystack helps you build apps. Real apps that work on iPhones, Android phones, tablets, computers, and the web — all from the same code.
|
|
4
|
+
|
|
5
|
+
You describe what you want. Claude helps you build it. everystack provides the building blocks.
|
|
6
|
+
|
|
7
|
+
**A note about difficulty:** Building software is hard. Professional engineers are paid well to do this, and projects often take months or years. Claude and everystack make it much more accessible, but you are still building real software with real infrastructure. Things will break. You will hit errors you don't understand. That's normal. The key is to keep going, ask questions, and learn as you go.
|
|
8
|
+
|
|
9
|
+
## How it works
|
|
10
|
+
|
|
11
|
+
You start simple: a running app on your screen. Then you build from there.
|
|
12
|
+
|
|
13
|
+
Every app starts the same way — a basic Expo app that works on phones, tablets, and the web. You build the screens, the navigation, the look and feel. Everything is visual and immediate.
|
|
14
|
+
|
|
15
|
+
When your app needs more — user accounts, saved data, file uploads — you add those capabilities one at a time. You never throw away what you already built. Your app grows with you.
|
|
16
|
+
|
|
17
|
+
## What you need to get started
|
|
18
|
+
|
|
19
|
+
These are tools that run on your computer. Claude will help you install each one.
|
|
20
|
+
|
|
21
|
+
**Node.js** — Runs your code. Your app is written in TypeScript (a programming language). Node.js is the engine that makes it work, like how a car needs an engine to drive.
|
|
22
|
+
- Without it: Nothing runs.
|
|
23
|
+
|
|
24
|
+
**git** — Tracks every change you make to your code. Like an unlimited undo button for your entire project. You can always go back to any previous version.
|
|
25
|
+
- Without it: You cannot track changes or undo mistakes.
|
|
26
|
+
|
|
27
|
+
**pnpm** (recommended) — A faster way to install code libraries your app depends on. Recommended but Claude can work without it.
|
|
28
|
+
|
|
29
|
+
That's it. Those three tools are all you need to create an app and see it running on your computer.
|
|
30
|
+
|
|
31
|
+
### When your app needs a database (later)
|
|
32
|
+
|
|
33
|
+
If your app needs user accounts or saved data, you'll add a database. This is not needed to start — only when a feature demands it.
|
|
34
|
+
|
|
35
|
+
**PostgreSQL** — A database that stores your app's data: users, posts, recipes, or whatever your app needs. Like a spreadsheet that your app reads and writes automatically. Read everystack://adding-database when you're ready for this step.
|
|
36
|
+
|
|
37
|
+
### To deploy to the internet (later)
|
|
38
|
+
|
|
39
|
+
You don't need these right away. Install them when you're ready to put your app online so other people can use it.
|
|
40
|
+
|
|
41
|
+
**AWS account + AWS CLI** — AWS (Amazon Web Services) is where your app lives on the internet. Other people's computers run your app so anyone can use it. The AWS CLI is a tool that lets Claude talk to AWS from your computer.
|
|
42
|
+
- Without it: Your app only works on your computer. Nobody else can use it.
|
|
43
|
+
- Setting up AWS requires a credit card for verification. AWS has a free tier for the first 12 months. You control all costs and can delete everything at any time.
|
|
44
|
+
|
|
45
|
+
**AWS credentials** — A password file that proves your computer is allowed to deploy to your AWS account. You create this once during setup.
|
|
46
|
+
- Without them: AWS will reject all deploy commands.
|
|
47
|
+
- New to AWS? Read everystack://aws-setup for a complete walkthrough of creating an account and setting up credentials.
|
|
48
|
+
|
|
49
|
+
## The path from idea to running app
|
|
50
|
+
|
|
51
|
+
1. **You describe your idea.** "I want to build a recipe sharing app."
|
|
52
|
+
2. **Claude checks your computer.** Runs a tool to see what's installed and what's missing.
|
|
53
|
+
3. **Claude helps you install anything missing.** Step by step, one tool at a time. Each one explained before you install it.
|
|
54
|
+
4. **Claude creates your app.** A stock Expo app with the everystack building blocks installed.
|
|
55
|
+
5. **You see it running on your computer.** Your app opens in a browser. You can change things and see updates instantly. Read everystack://first-run for details on this step.
|
|
56
|
+
6. **You build together.** Describe what you want — screens, buttons, colors, layout. Claude builds it. You see changes in real time. This is where most of the work happens.
|
|
57
|
+
7. **Your app grows when it needs to.** When a feature needs user accounts or saved data, Claude helps you add a database. When you need file uploads, you add that too. One thing at a time.
|
|
58
|
+
8. **When you're ready, you deploy.** Your app gets a real URL that anyone can visit. This is a separate step — there's no rush.
|
|
59
|
+
|
|
60
|
+
## Common questions
|
|
61
|
+
|
|
62
|
+
**Do I need to know how to code?**
|
|
63
|
+
Not to start. Claude writes the code and explains what it's doing. But you're building real software — the same kind that teams of engineers get paid to build. Things will break. You'll need to learn as you go. The more you understand, the better your app will be.
|
|
64
|
+
|
|
65
|
+
**How much does AWS cost?**
|
|
66
|
+
For a small app with low traffic, typically under $5/month for a static site and around $20/month once you add a database (the database is the main cost). AWS has a free tier for the first 12 months that covers most of what everystack uses. You can build and run locally for free with no AWS account at all.
|
|
67
|
+
|
|
68
|
+
**Can I change things later?**
|
|
69
|
+
Yes. everystack is built for this. Start with a simple app, add user accounts when you need them, add file uploads when you need them. You never throw away what you already built.
|
|
70
|
+
|
|
71
|
+
**What if something goes wrong?**
|
|
72
|
+
Claude can debug it. everystack has built-in tools that check your project for common mistakes and security issues. And git tracks every change, so you can always go back. Expect things to go wrong — that's part of building software. The tools are here to help you recover.
|
|
73
|
+
|
|
74
|
+
**Do I need a Mac?**
|
|
75
|
+
For now, yes. everystack's setup tools are designed for macOS. Windows and Linux support may come later.
|