create-atsdc-stack 1.0.1 → 1.2.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/.claude/settings.local.json +3 -1
- package/CLAUDE.md +236 -0
- package/CONTRIBUTING.md +342 -342
- package/INSTALLATION.md +359 -359
- package/LICENSE +201 -201
- package/README.md +405 -405
- package/app/.env.example +17 -17
- package/app/.github/labeler.yml +61 -0
- package/app/.github/workflows/browser-tests.yml +101 -0
- package/app/.github/workflows/check.yml +24 -0
- package/app/.github/workflows/greetings.yml +16 -0
- package/app/.github/workflows/label.yml +22 -0
- package/app/.github/workflows/stale.yml +27 -0
- package/app/.github/workflows/summary.yml +34 -0
- package/app/.stylelintrc.json +8 -0
- package/app/README.md +251 -251
- package/app/astro.config.mjs +83 -83
- package/app/drizzle.config.ts +16 -16
- package/app/package.json +66 -52
- package/app/playwright.config.ts +27 -0
- package/app/public/manifest.webmanifest +36 -36
- package/app/pwa-assets.config.ts +8 -0
- package/app/src/components/Card.astro +36 -36
- package/app/src/db/initialize.ts +107 -107
- package/app/src/db/schema.ts +72 -72
- package/app/src/db/validations.ts +158 -158
- package/app/src/layouts/Layout.astro +63 -63
- package/app/src/lib/config.ts +36 -36
- package/app/src/lib/content-converter.ts +141 -141
- package/app/src/lib/dom-utils.ts +230 -230
- package/app/src/lib/exa-search.ts +269 -269
- package/app/src/pages/api/chat.ts +91 -91
- package/app/src/pages/api/posts.ts +350 -350
- package/app/src/pages/index.astro +87 -87
- package/app/src/styles/components/button.scss +152 -152
- package/app/src/styles/components/card.scss +180 -180
- package/app/src/styles/components/form.scss +240 -240
- package/app/src/styles/global.scss +141 -141
- package/app/src/styles/pages/index.scss +80 -80
- package/app/src/styles/reset.scss +83 -83
- package/app/src/styles/variables/globals.scss +96 -96
- package/app/src/styles/variables/mixins.scss +238 -238
- package/app/tests/browser.test.nopause.ts +10 -0
- package/app/tests/browser.test.ts +13 -0
- package/bin/cli.js +1151 -1138
- package/package.json +8 -6
- package/app/.astro/settings.json +0 -5
- package/app/.astro/types.d.ts +0 -1
package/README.md
CHANGED
|
@@ -1,405 +1,405 @@
|
|
|
1
|
-
# ATSDC Stack
|
|
2
|
-
|
|
3
|
-
A production-ready, full-stack web application framework combining the best modern technologies for building secure, type-safe, and AI-ready web applications.
|
|
4
|
-
|
|
5
|
-
## 🚀 Stack Overview
|
|
6
|
-
|
|
7
|
-
The **ATSDC Stack** is a carefully curated combination of modern web technologies:
|
|
8
|
-
|
|
9
|
-
- **A** - [Astro](https://astro.build) - Lightning-fast static site generation with dynamic capabilities
|
|
10
|
-
- **T** - [TypeScript](https://www.typescriptlang.org) - Full type safety across your entire application
|
|
11
|
-
- **S** - [SCSS](https://sass-lang.com) - Powerful styling with variables, mixins, and modules
|
|
12
|
-
- **D** - [Drizzle ORM](https://orm.drizzle.team) - Type-safe database operations with PostgreSQL
|
|
13
|
-
- **C** - [Clerk](https://clerk.com) - Complete authentication and user management
|
|
14
|
-
|
|
15
|
-
### Additional Technologies
|
|
16
|
-
|
|
17
|
-
- **Zero** - Local-first sync engine for real-time data synchronization
|
|
18
|
-
- **Zod** - TypeScript-first schema validation with runtime type safety
|
|
19
|
-
- **Vercel AI SDK** - Seamless integration with AI language models
|
|
20
|
-
- **NanoID** - Secure, URL-friendly unique identifiers for database records
|
|
21
|
-
- **Vite PWA** - Progressive Web App capabilities with offline support
|
|
22
|
-
- **Cheerio** - Server-side jQuery for HTML/DOM manipulation
|
|
23
|
-
- **Marked** - Fast Markdown to HTML converter
|
|
24
|
-
- **Turndown** - HTML to Markdown converter
|
|
25
|
-
- **Exa** - AI-powered search for intelligent content discovery
|
|
26
|
-
|
|
27
|
-
## 📦 Installation
|
|
28
|
-
|
|
29
|
-
### Using NPX (Recommended)
|
|
30
|
-
|
|
31
|
-
Create a new project using the ATSDC Stack CLI:
|
|
32
|
-
|
|
33
|
-
```bash
|
|
34
|
-
# Fully interactive mode - prompts for everything
|
|
35
|
-
npx create-atsdc-stack
|
|
36
|
-
|
|
37
|
-
# Provide project name, get prompted for install/setup options
|
|
38
|
-
npx create-atsdc-stack my-app
|
|
39
|
-
|
|
40
|
-
# Skip prompts with explicit flags
|
|
41
|
-
npx create-atsdc-stack my-app --install
|
|
42
|
-
npx create-atsdc-stack my-app --install --setup-db
|
|
43
|
-
```
|
|
44
|
-
|
|
45
|
-
The CLI will interactively prompt you for any options you don't provide:
|
|
46
|
-
|
|
47
|
-
- **Project name** - if not provided as argument
|
|
48
|
-
- **Install dependencies** - if `--install` flag not provided
|
|
49
|
-
- **Setup database** - if `--setup-db` flag not provided (only when installing)
|
|
50
|
-
- **Vercel login** - prompted after installation to enable immediate deployment
|
|
51
|
-
|
|
52
|
-
### Manual Installation
|
|
53
|
-
|
|
54
|
-
```bash
|
|
55
|
-
# Clone this repository
|
|
56
|
-
git clone https://github.com/yourusername/atsdc-stack.git my-app
|
|
57
|
-
cd my-app
|
|
58
|
-
|
|
59
|
-
# Install dependencies
|
|
60
|
-
npm install
|
|
61
|
-
```
|
|
62
|
-
|
|
63
|
-
## ⚙️ Configuration
|
|
64
|
-
|
|
65
|
-
### 1. Environment Variables
|
|
66
|
-
|
|
67
|
-
**Note:** When using the CLI (`npx create-atsdc-stack`), the `.env` file is automatically created from `.env.example` - no manual copying needed!
|
|
68
|
-
|
|
69
|
-
If you're setting up manually, copy `.env.example` to `.env`:
|
|
70
|
-
|
|
71
|
-
```bash
|
|
72
|
-
cp .env.example .env
|
|
73
|
-
```
|
|
74
|
-
|
|
75
|
-
Required environment variables:
|
|
76
|
-
|
|
77
|
-
- `DATABASE_URL` - PostgreSQL connection string
|
|
78
|
-
- `PUBLIC_CLERK_PUBLISHABLE_KEY` - Clerk publishable key
|
|
79
|
-
- `CLERK_SECRET_KEY` - Clerk secret key
|
|
80
|
-
- `OPENAI_API_KEY` - OpenAI API key (for AI features)
|
|
81
|
-
|
|
82
|
-
### 2. Database Setup
|
|
83
|
-
|
|
84
|
-
**Note:** When using the CLI with the `--setup-db` flag, the database schema is automatically pushed for you!
|
|
85
|
-
|
|
86
|
-
```bash
|
|
87
|
-
npx create-atsdc-stack my-app --install --setup-db
|
|
88
|
-
```
|
|
89
|
-
|
|
90
|
-
If setting up manually or if you skipped the automatic setup, push your database schema to PostgreSQL:
|
|
91
|
-
|
|
92
|
-
```bash
|
|
93
|
-
npm run db:push
|
|
94
|
-
```
|
|
95
|
-
|
|
96
|
-
Generate migrations (optional):
|
|
97
|
-
|
|
98
|
-
```bash
|
|
99
|
-
npm run db:generate
|
|
100
|
-
```
|
|
101
|
-
|
|
102
|
-
### 3. Start Development Server
|
|
103
|
-
|
|
104
|
-
```bash
|
|
105
|
-
npm run dev
|
|
106
|
-
```
|
|
107
|
-
|
|
108
|
-
Your application will be available at `http://localhost:4321`
|
|
109
|
-
|
|
110
|
-
## 📁 Project Structure
|
|
111
|
-
|
|
112
|
-
```text
|
|
113
|
-
├── app/ # Astro application
|
|
114
|
-
│ ├── public/ # Static assets
|
|
115
|
-
│ ├── src/
|
|
116
|
-
│ │ ├── components/ # Reusable Astro components
|
|
117
|
-
│ │ ├── db/
|
|
118
|
-
│ │ │ ├── initialize.ts # Database client and initialization
|
|
119
|
-
│ │ │ ├── schema.ts # Drizzle ORM schema definitions
|
|
120
|
-
│ │ │ └── validations.ts # Zod validation schemas
|
|
121
|
-
│ │ ├── layouts/
|
|
122
|
-
│ │ │ └── Layout.astro # Base layout component
|
|
123
|
-
│ │ ├── lib/ # Utility libraries
|
|
124
|
-
│ │ │ ├── config.ts # Application configuration
|
|
125
|
-
│ │ │ ├── content-converter.ts # Markdown/HTML conversion
|
|
126
|
-
│ │ │ ├── dom-utils.ts # DOM manipulation utilities
|
|
127
|
-
│ │ │ └── exa-search.ts # AI-powered search
|
|
128
|
-
│ │ ├── pages/
|
|
129
|
-
│ │ │ ├── api/ # API routes
|
|
130
|
-
│ │ │ │ ├── chat.ts # Vercel AI SDK chat endpoint
|
|
131
|
-
│ │ │ │ └── posts.ts # CRUD operations for posts
|
|
132
|
-
│ │ │ └── index.astro # Home page
|
|
133
|
-
│ │ └── styles/
|
|
134
|
-
│ │ ├── variables/
|
|
135
|
-
│ │ │ ├── globals.scss # SCSS global variables
|
|
136
|
-
│ │ │ └── mixins.scss # SCSS mixins
|
|
137
|
-
│ │ ├── reset.scss # CSS reset
|
|
138
|
-
│ │ ├── global.scss # Global styles
|
|
139
|
-
│ │ ├── components/ # Component-specific styles
|
|
140
|
-
│ │ └── pages/ # Page-specific styles
|
|
141
|
-
│ ├── astro.config.mjs # Astro configuration
|
|
142
|
-
│ ├── drizzle.config.ts # Drizzle ORM configuration
|
|
143
|
-
│ ├── package.json # App dependencies
|
|
144
|
-
│ └── tsconfig.json # TypeScript configuration
|
|
145
|
-
├── bin/
|
|
146
|
-
│ └── cli.js # CLI entry point for scaffolding
|
|
147
|
-
└── package.json # Root workspace configuration
|
|
148
|
-
```
|
|
149
|
-
|
|
150
|
-
## 🎨 SCSS Architecture
|
|
151
|
-
|
|
152
|
-
This stack enforces a strict separation of concerns for styling with **semantic, readable class names** - no utility classes like Tailwind.
|
|
153
|
-
|
|
154
|
-
### Rules
|
|
155
|
-
|
|
156
|
-
1. **Semantic class names** - Use readable, meaningful class names (e.g., `.btn`, `.card`, `.header`) instead of utility classes (e.g., `.px-4`, `.bg-blue-500`)
|
|
157
|
-
2. **No inline `<style>` tags** in `.astro` files (except for truly standalone components)
|
|
158
|
-
3. **All styles in external SCSS files** for better maintainability and smaller CSS footprint
|
|
159
|
-
4. **Component-specific styles** in `app/src/styles/components/`
|
|
160
|
-
5. **Page-specific styles** in `app/src/styles/pages/`
|
|
161
|
-
6. **Use data attributes for modifiers** (preferred over BEM modifier classes)
|
|
162
|
-
7. **Use class chaining** when data attributes aren't appropriate
|
|
163
|
-
|
|
164
|
-
### Example Usage
|
|
165
|
-
|
|
166
|
-
```astro
|
|
167
|
-
---
|
|
168
|
-
// src/pages/example.astro
|
|
169
|
-
import Layout from '@/layouts/Layout.astro';
|
|
170
|
-
import '@/styles/components/button.scss';
|
|
171
|
-
import '@/styles/pages/example.scss';
|
|
172
|
-
---
|
|
173
|
-
|
|
174
|
-
<Layout pageTitle="Example Page">
|
|
175
|
-
<div class="example-page">
|
|
176
|
-
<h1>Hello World</h1>
|
|
177
|
-
<!-- Preferred: Data attributes for modifiers -->
|
|
178
|
-
<button class="btn" data-variant="primary" data-size="lg">Click Me</button>
|
|
179
|
-
|
|
180
|
-
<!-- Alternative: Class chaining -->
|
|
181
|
-
<button class="btn primary lg">Click Me Too</button>
|
|
182
|
-
</div>
|
|
183
|
-
</Layout>
|
|
184
|
-
```
|
|
185
|
-
|
|
186
|
-
### Styling Approach
|
|
187
|
-
|
|
188
|
-
#### Preferred: Data Attributes
|
|
189
|
-
|
|
190
|
-
```scss
|
|
191
|
-
.btn {
|
|
192
|
-
@include button-base;
|
|
193
|
-
|
|
194
|
-
&[data-variant='primary'] { /* styles */ }
|
|
195
|
-
&[data-size='lg'] { /* styles */ }
|
|
196
|
-
&[data-state='loading'] { /* styles */ }
|
|
197
|
-
}
|
|
198
|
-
```
|
|
199
|
-
|
|
200
|
-
#### Alternative: Class Chaining
|
|
201
|
-
|
|
202
|
-
```scss
|
|
203
|
-
.btn {
|
|
204
|
-
@include button-base;
|
|
205
|
-
|
|
206
|
-
&.primary { /* styles */ }
|
|
207
|
-
&.lg { /* styles */ }
|
|
208
|
-
&.loading { /* styles */ }
|
|
209
|
-
}
|
|
210
|
-
```
|
|
211
|
-
|
|
212
|
-
### Available Mixins
|
|
213
|
-
|
|
214
|
-
The stack provides readable, semantic mixins instead of cryptic utility names:
|
|
215
|
-
|
|
216
|
-
```scss
|
|
217
|
-
@import '@/styles/mixins';
|
|
218
|
-
|
|
219
|
-
.my-component {
|
|
220
|
-
@include flex-center; // Center content with flexbox
|
|
221
|
-
@include card; // Card styling
|
|
222
|
-
@include button-primary; // Primary button styles
|
|
223
|
-
@include heading-1; // H1 typography
|
|
224
|
-
}
|
|
225
|
-
```
|
|
226
|
-
|
|
227
|
-
### SCSS Variables
|
|
228
|
-
|
|
229
|
-
Use descriptive variable names that clearly indicate their purpose:
|
|
230
|
-
|
|
231
|
-
```scss
|
|
232
|
-
// ✅ Good: Readable, semantic names
|
|
233
|
-
$color-primary: #007bff;
|
|
234
|
-
$spacing-large: 2rem;
|
|
235
|
-
$border-radius-default: 0.5rem;
|
|
236
|
-
$font-size-heading: 2rem;
|
|
237
|
-
|
|
238
|
-
// ❌ Avoid: Cryptic abbreviations
|
|
239
|
-
$clr-1: #007bff;
|
|
240
|
-
$sp-lg: 2rem;
|
|
241
|
-
```
|
|
242
|
-
|
|
243
|
-
## 🗄️ Database Operations
|
|
244
|
-
|
|
245
|
-
### Schema Definition
|
|
246
|
-
|
|
247
|
-
Define your database schema using Drizzle ORM with NanoID:
|
|
248
|
-
|
|
249
|
-
```typescript
|
|
250
|
-
// src/db/schema.ts
|
|
251
|
-
import { pgTable, text, varchar } from 'drizzle-orm/pg-core';
|
|
252
|
-
import { nanoid } from 'nanoid';
|
|
253
|
-
|
|
254
|
-
export const posts = pgTable('posts', {
|
|
255
|
-
id: varchar('id', { length: 21 })
|
|
256
|
-
.primaryKey()
|
|
257
|
-
.$defaultFn(() => nanoid()),
|
|
258
|
-
title: varchar('title', { length: 255 }).notNull(),
|
|
259
|
-
content: text('content').notNull(),
|
|
260
|
-
});
|
|
261
|
-
```
|
|
262
|
-
|
|
263
|
-
### Validation with Zod
|
|
264
|
-
|
|
265
|
-
Create Zod schemas for runtime validation:
|
|
266
|
-
|
|
267
|
-
```typescript
|
|
268
|
-
// src/db/validations.ts
|
|
269
|
-
import { z } from 'zod';
|
|
270
|
-
|
|
271
|
-
export const createPostSchema = z.object({
|
|
272
|
-
title: z.string().min(1).max(255),
|
|
273
|
-
content: z.string().min(1),
|
|
274
|
-
});
|
|
275
|
-
```
|
|
276
|
-
|
|
277
|
-
### API Routes
|
|
278
|
-
|
|
279
|
-
Create type-safe API routes:
|
|
280
|
-
|
|
281
|
-
```typescript
|
|
282
|
-
// src/pages/api/posts.ts
|
|
283
|
-
import type { APIRoute } from 'astro';
|
|
284
|
-
import { db } from '@/db/initialize';
|
|
285
|
-
import { posts } from '@/db/schema';
|
|
286
|
-
import { createPostSchema } from '@/db/validations';
|
|
287
|
-
|
|
288
|
-
export const POST: APIRoute = async ({ request }) => {
|
|
289
|
-
const body = await request.json();
|
|
290
|
-
const validated = createPostSchema.parse(body);
|
|
291
|
-
|
|
292
|
-
const [newPost] = await db
|
|
293
|
-
.insert(posts)
|
|
294
|
-
.values(validated)
|
|
295
|
-
.returning();
|
|
296
|
-
|
|
297
|
-
return new Response(JSON.stringify(newPost), { status: 201 });
|
|
298
|
-
};
|
|
299
|
-
```
|
|
300
|
-
|
|
301
|
-
## 🤖 AI Integration
|
|
302
|
-
|
|
303
|
-
The stack includes Vercel AI SDK with AI Gateway for seamless AI integration - no provider-specific packages needed!
|
|
304
|
-
|
|
305
|
-
**Note:** AI Gateway requires Vercel AI SDK v5.0.0 or later (already configured in this stack).
|
|
306
|
-
|
|
307
|
-
```typescript
|
|
308
|
-
// src/pages/api/chat.ts
|
|
309
|
-
import type { APIRoute } from 'astro';
|
|
310
|
-
import { streamText } from 'ai';
|
|
311
|
-
|
|
312
|
-
export const POST: APIRoute = async ({ request }) => {
|
|
313
|
-
const { messages } = await request.json();
|
|
314
|
-
|
|
315
|
-
const result = streamText({
|
|
316
|
-
model: 'openai/gpt-4o', // Use model string directly - supports any provider
|
|
317
|
-
messages,
|
|
318
|
-
apiKey: process.env.OPENAI_API_KEY,
|
|
319
|
-
});
|
|
320
|
-
|
|
321
|
-
return result.toDataStreamResponse();
|
|
322
|
-
};
|
|
323
|
-
```
|
|
324
|
-
|
|
325
|
-
**Supported model formats:**
|
|
326
|
-
|
|
327
|
-
- OpenAI: `openai/gpt-4.1`, `openai/o4-mini`
|
|
328
|
-
- Anthropic: `anthropic/claude-3-5-sonnet-20241022`
|
|
329
|
-
- Google: `google/gemini-1.5-pro`
|
|
330
|
-
- And many more providers without extra dependencies!
|
|
331
|
-
|
|
332
|
-
## 🔐 Authentication
|
|
333
|
-
|
|
334
|
-
Clerk is pre-configured for authentication. Protect routes with middleware:
|
|
335
|
-
|
|
336
|
-
```typescript
|
|
337
|
-
// src/middleware.ts
|
|
338
|
-
import { clerkMiddleware } from '@clerk/astro/server';
|
|
339
|
-
|
|
340
|
-
export const onRequest = clerkMiddleware();
|
|
341
|
-
```
|
|
342
|
-
|
|
343
|
-
## 🚀 Deployment
|
|
344
|
-
|
|
345
|
-
### Vercel (Recommended)
|
|
346
|
-
|
|
347
|
-
The Vercel CLI is already included in the project! If you used the CLI setup, you may already be logged in.
|
|
348
|
-
|
|
349
|
-
```bash
|
|
350
|
-
# Login to Vercel (if not already logged in)
|
|
351
|
-
npx vercel login
|
|
352
|
-
|
|
353
|
-
# Deploy to production
|
|
354
|
-
npx vercel --prod
|
|
355
|
-
```
|
|
356
|
-
|
|
357
|
-
### Environment Variables on Vercel
|
|
358
|
-
|
|
359
|
-
Set these in your Vercel project settings:
|
|
360
|
-
|
|
361
|
-
- `DATABASE_URL`
|
|
362
|
-
- `CLERK_SECRET_KEY`
|
|
363
|
-
- `OPENAI_API_KEY`
|
|
364
|
-
|
|
365
|
-
## 📚 Documentation
|
|
366
|
-
|
|
367
|
-
- [Astro Documentation](https://docs.astro.build)
|
|
368
|
-
- [Drizzle ORM Documentation](https://orm.drizzle.team/docs)
|
|
369
|
-
- [Clerk Documentation](https://clerk.com/docs)
|
|
370
|
-
- [Zero Sync Documentation](https://zero.rocicorp.dev)
|
|
371
|
-
- [Zod Documentation](https://zod.dev)
|
|
372
|
-
- [Vercel AI SDK Documentation](https://sdk.vercel.ai/docs)
|
|
373
|
-
|
|
374
|
-
## 🛠️ Available Scripts
|
|
375
|
-
|
|
376
|
-
```bash
|
|
377
|
-
npm run dev # Start development server
|
|
378
|
-
npm run build # Build for production
|
|
379
|
-
npm run preview # Preview production build
|
|
380
|
-
npm run db:generate # Generate database migrations
|
|
381
|
-
npm run db:migrate # Run database migrations
|
|
382
|
-
npm run db:push # Push schema to database
|
|
383
|
-
npm run db:studio # Open Drizzle Studio
|
|
384
|
-
```
|
|
385
|
-
|
|
386
|
-
## 📄 License
|
|
387
|
-
|
|
388
|
-
MIT License - see LICENSE file for details
|
|
389
|
-
|
|
390
|
-
## 🤝 Contributing
|
|
391
|
-
|
|
392
|
-
Contributions are welcome! Please open an issue or submit a pull request.
|
|
393
|
-
|
|
394
|
-
## 💡 Why This Stack?
|
|
395
|
-
|
|
396
|
-
1. **Type Safety** - TypeScript + Drizzle + Zod ensure type safety from database to frontend
|
|
397
|
-
2. **Performance** - Astro's zero-JS by default approach for maximum performance
|
|
398
|
-
3. **Real-time Sync** - Zero provides local-first data synchronization for responsive UIs
|
|
399
|
-
4. **Developer Experience** - Modern tooling with excellent IDE support and automated setup
|
|
400
|
-
5. **Scalability** - PostgreSQL + serverless architecture scales effortlessly
|
|
401
|
-
6. **Security** - Clerk handles authentication, Zod validates inputs
|
|
402
|
-
7. **AI-Ready** - Vercel AI SDK integration for modern AI features
|
|
403
|
-
8. **PWA Support** - Offline-first capabilities with Vite PWA
|
|
404
|
-
9. **Clean Architecture** - Enforced separation of concerns, especially for styles
|
|
405
|
-
10. **Quick Start** - Automated environment setup and database initialization
|
|
1
|
+
# ATSDC Stack
|
|
2
|
+
|
|
3
|
+
A production-ready, full-stack web application framework combining the best modern technologies for building secure, type-safe, and AI-ready web applications.
|
|
4
|
+
|
|
5
|
+
## 🚀 Stack Overview
|
|
6
|
+
|
|
7
|
+
The **ATSDC Stack** is a carefully curated combination of modern web technologies:
|
|
8
|
+
|
|
9
|
+
- **A** - [Astro](https://astro.build) - Lightning-fast static site generation with dynamic capabilities
|
|
10
|
+
- **T** - [TypeScript](https://www.typescriptlang.org) - Full type safety across your entire application
|
|
11
|
+
- **S** - [SCSS](https://sass-lang.com) - Powerful styling with variables, mixins, and modules
|
|
12
|
+
- **D** - [Drizzle ORM](https://orm.drizzle.team) - Type-safe database operations with PostgreSQL
|
|
13
|
+
- **C** - [Clerk](https://clerk.com) - Complete authentication and user management
|
|
14
|
+
|
|
15
|
+
### Additional Technologies
|
|
16
|
+
|
|
17
|
+
- **Zero** - Local-first sync engine for real-time data synchronization
|
|
18
|
+
- **Zod** - TypeScript-first schema validation with runtime type safety
|
|
19
|
+
- **Vercel AI SDK** - Seamless integration with AI language models
|
|
20
|
+
- **NanoID** - Secure, URL-friendly unique identifiers for database records
|
|
21
|
+
- **Vite PWA** - Progressive Web App capabilities with offline support
|
|
22
|
+
- **Cheerio** - Server-side jQuery for HTML/DOM manipulation
|
|
23
|
+
- **Marked** - Fast Markdown to HTML converter
|
|
24
|
+
- **Turndown** - HTML to Markdown converter
|
|
25
|
+
- **Exa** - AI-powered search for intelligent content discovery
|
|
26
|
+
|
|
27
|
+
## 📦 Installation
|
|
28
|
+
|
|
29
|
+
### Using NPX (Recommended)
|
|
30
|
+
|
|
31
|
+
Create a new project using the ATSDC Stack CLI:
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
# Fully interactive mode - prompts for everything
|
|
35
|
+
npx create-atsdc-stack
|
|
36
|
+
|
|
37
|
+
# Provide project name, get prompted for install/setup options
|
|
38
|
+
npx create-atsdc-stack my-app
|
|
39
|
+
|
|
40
|
+
# Skip prompts with explicit flags
|
|
41
|
+
npx create-atsdc-stack my-app --install
|
|
42
|
+
npx create-atsdc-stack my-app --install --setup-db
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
The CLI will interactively prompt you for any options you don't provide:
|
|
46
|
+
|
|
47
|
+
- **Project name** - if not provided as argument
|
|
48
|
+
- **Install dependencies** - if `--install` flag not provided
|
|
49
|
+
- **Setup database** - if `--setup-db` flag not provided (only when installing)
|
|
50
|
+
- **Vercel login** - prompted after installation to enable immediate deployment
|
|
51
|
+
|
|
52
|
+
### Manual Installation
|
|
53
|
+
|
|
54
|
+
```bash
|
|
55
|
+
# Clone this repository
|
|
56
|
+
git clone https://github.com/yourusername/atsdc-stack.git my-app
|
|
57
|
+
cd my-app
|
|
58
|
+
|
|
59
|
+
# Install dependencies
|
|
60
|
+
npm install
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
## ⚙️ Configuration
|
|
64
|
+
|
|
65
|
+
### 1. Environment Variables
|
|
66
|
+
|
|
67
|
+
**Note:** When using the CLI (`npx create-atsdc-stack`), the `.env` file is automatically created from `.env.example` - no manual copying needed!
|
|
68
|
+
|
|
69
|
+
If you're setting up manually, copy `.env.example` to `.env`:
|
|
70
|
+
|
|
71
|
+
```bash
|
|
72
|
+
cp .env.example .env
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
Required environment variables:
|
|
76
|
+
|
|
77
|
+
- `DATABASE_URL` - PostgreSQL connection string
|
|
78
|
+
- `PUBLIC_CLERK_PUBLISHABLE_KEY` - Clerk publishable key
|
|
79
|
+
- `CLERK_SECRET_KEY` - Clerk secret key
|
|
80
|
+
- `OPENAI_API_KEY` - OpenAI API key (for AI features)
|
|
81
|
+
|
|
82
|
+
### 2. Database Setup
|
|
83
|
+
|
|
84
|
+
**Note:** When using the CLI with the `--setup-db` flag, the database schema is automatically pushed for you!
|
|
85
|
+
|
|
86
|
+
```bash
|
|
87
|
+
npx create-atsdc-stack my-app --install --setup-db
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
If setting up manually or if you skipped the automatic setup, push your database schema to PostgreSQL:
|
|
91
|
+
|
|
92
|
+
```bash
|
|
93
|
+
npm run db:push
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
Generate migrations (optional):
|
|
97
|
+
|
|
98
|
+
```bash
|
|
99
|
+
npm run db:generate
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
### 3. Start Development Server
|
|
103
|
+
|
|
104
|
+
```bash
|
|
105
|
+
npm run dev
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
Your application will be available at `http://localhost:4321`
|
|
109
|
+
|
|
110
|
+
## 📁 Project Structure
|
|
111
|
+
|
|
112
|
+
```text
|
|
113
|
+
├── app/ # Astro application
|
|
114
|
+
│ ├── public/ # Static assets
|
|
115
|
+
│ ├── src/
|
|
116
|
+
│ │ ├── components/ # Reusable Astro components
|
|
117
|
+
│ │ ├── db/
|
|
118
|
+
│ │ │ ├── initialize.ts # Database client and initialization
|
|
119
|
+
│ │ │ ├── schema.ts # Drizzle ORM schema definitions
|
|
120
|
+
│ │ │ └── validations.ts # Zod validation schemas
|
|
121
|
+
│ │ ├── layouts/
|
|
122
|
+
│ │ │ └── Layout.astro # Base layout component
|
|
123
|
+
│ │ ├── lib/ # Utility libraries
|
|
124
|
+
│ │ │ ├── config.ts # Application configuration
|
|
125
|
+
│ │ │ ├── content-converter.ts # Markdown/HTML conversion
|
|
126
|
+
│ │ │ ├── dom-utils.ts # DOM manipulation utilities
|
|
127
|
+
│ │ │ └── exa-search.ts # AI-powered search
|
|
128
|
+
│ │ ├── pages/
|
|
129
|
+
│ │ │ ├── api/ # API routes
|
|
130
|
+
│ │ │ │ ├── chat.ts # Vercel AI SDK chat endpoint
|
|
131
|
+
│ │ │ │ └── posts.ts # CRUD operations for posts
|
|
132
|
+
│ │ │ └── index.astro # Home page
|
|
133
|
+
│ │ └── styles/
|
|
134
|
+
│ │ ├── variables/
|
|
135
|
+
│ │ │ ├── globals.scss # SCSS global variables
|
|
136
|
+
│ │ │ └── mixins.scss # SCSS mixins
|
|
137
|
+
│ │ ├── reset.scss # CSS reset
|
|
138
|
+
│ │ ├── global.scss # Global styles
|
|
139
|
+
│ │ ├── components/ # Component-specific styles
|
|
140
|
+
│ │ └── pages/ # Page-specific styles
|
|
141
|
+
│ ├── astro.config.mjs # Astro configuration
|
|
142
|
+
│ ├── drizzle.config.ts # Drizzle ORM configuration
|
|
143
|
+
│ ├── package.json # App dependencies
|
|
144
|
+
│ └── tsconfig.json # TypeScript configuration
|
|
145
|
+
├── bin/
|
|
146
|
+
│ └── cli.js # CLI entry point for scaffolding
|
|
147
|
+
└── package.json # Root workspace configuration
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
## 🎨 SCSS Architecture
|
|
151
|
+
|
|
152
|
+
This stack enforces a strict separation of concerns for styling with **semantic, readable class names** - no utility classes like Tailwind.
|
|
153
|
+
|
|
154
|
+
### Rules
|
|
155
|
+
|
|
156
|
+
1. **Semantic class names** - Use readable, meaningful class names (e.g., `.btn`, `.card`, `.header`) instead of utility classes (e.g., `.px-4`, `.bg-blue-500`)
|
|
157
|
+
2. **No inline `<style>` tags** in `.astro` files (except for truly standalone components)
|
|
158
|
+
3. **All styles in external SCSS files** for better maintainability and smaller CSS footprint
|
|
159
|
+
4. **Component-specific styles** in `app/src/styles/components/`
|
|
160
|
+
5. **Page-specific styles** in `app/src/styles/pages/`
|
|
161
|
+
6. **Use data attributes for modifiers** (preferred over BEM modifier classes)
|
|
162
|
+
7. **Use class chaining** when data attributes aren't appropriate
|
|
163
|
+
|
|
164
|
+
### Example Usage
|
|
165
|
+
|
|
166
|
+
```astro
|
|
167
|
+
---
|
|
168
|
+
// src/pages/example.astro
|
|
169
|
+
import Layout from '@/layouts/Layout.astro';
|
|
170
|
+
import '@/styles/components/button.scss';
|
|
171
|
+
import '@/styles/pages/example.scss';
|
|
172
|
+
---
|
|
173
|
+
|
|
174
|
+
<Layout pageTitle="Example Page">
|
|
175
|
+
<div class="example-page">
|
|
176
|
+
<h1>Hello World</h1>
|
|
177
|
+
<!-- Preferred: Data attributes for modifiers -->
|
|
178
|
+
<button class="btn" data-variant="primary" data-size="lg">Click Me</button>
|
|
179
|
+
|
|
180
|
+
<!-- Alternative: Class chaining -->
|
|
181
|
+
<button class="btn primary lg">Click Me Too</button>
|
|
182
|
+
</div>
|
|
183
|
+
</Layout>
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
### Styling Approach
|
|
187
|
+
|
|
188
|
+
#### Preferred: Data Attributes
|
|
189
|
+
|
|
190
|
+
```scss
|
|
191
|
+
.btn {
|
|
192
|
+
@include button-base;
|
|
193
|
+
|
|
194
|
+
&[data-variant='primary'] { /* styles */ }
|
|
195
|
+
&[data-size='lg'] { /* styles */ }
|
|
196
|
+
&[data-state='loading'] { /* styles */ }
|
|
197
|
+
}
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
#### Alternative: Class Chaining
|
|
201
|
+
|
|
202
|
+
```scss
|
|
203
|
+
.btn {
|
|
204
|
+
@include button-base;
|
|
205
|
+
|
|
206
|
+
&.primary { /* styles */ }
|
|
207
|
+
&.lg { /* styles */ }
|
|
208
|
+
&.loading { /* styles */ }
|
|
209
|
+
}
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
### Available Mixins
|
|
213
|
+
|
|
214
|
+
The stack provides readable, semantic mixins instead of cryptic utility names:
|
|
215
|
+
|
|
216
|
+
```scss
|
|
217
|
+
@import '@/styles/mixins';
|
|
218
|
+
|
|
219
|
+
.my-component {
|
|
220
|
+
@include flex-center; // Center content with flexbox
|
|
221
|
+
@include card; // Card styling
|
|
222
|
+
@include button-primary; // Primary button styles
|
|
223
|
+
@include heading-1; // H1 typography
|
|
224
|
+
}
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
### SCSS Variables
|
|
228
|
+
|
|
229
|
+
Use descriptive variable names that clearly indicate their purpose:
|
|
230
|
+
|
|
231
|
+
```scss
|
|
232
|
+
// ✅ Good: Readable, semantic names
|
|
233
|
+
$color-primary: #007bff;
|
|
234
|
+
$spacing-large: 2rem;
|
|
235
|
+
$border-radius-default: 0.5rem;
|
|
236
|
+
$font-size-heading: 2rem;
|
|
237
|
+
|
|
238
|
+
// ❌ Avoid: Cryptic abbreviations
|
|
239
|
+
$clr-1: #007bff;
|
|
240
|
+
$sp-lg: 2rem;
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
## 🗄️ Database Operations
|
|
244
|
+
|
|
245
|
+
### Schema Definition
|
|
246
|
+
|
|
247
|
+
Define your database schema using Drizzle ORM with NanoID:
|
|
248
|
+
|
|
249
|
+
```typescript
|
|
250
|
+
// src/db/schema.ts
|
|
251
|
+
import { pgTable, text, varchar } from 'drizzle-orm/pg-core';
|
|
252
|
+
import { nanoid } from 'nanoid';
|
|
253
|
+
|
|
254
|
+
export const posts = pgTable('posts', {
|
|
255
|
+
id: varchar('id', { length: 21 })
|
|
256
|
+
.primaryKey()
|
|
257
|
+
.$defaultFn(() => nanoid()),
|
|
258
|
+
title: varchar('title', { length: 255 }).notNull(),
|
|
259
|
+
content: text('content').notNull(),
|
|
260
|
+
});
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
### Validation with Zod
|
|
264
|
+
|
|
265
|
+
Create Zod schemas for runtime validation:
|
|
266
|
+
|
|
267
|
+
```typescript
|
|
268
|
+
// src/db/validations.ts
|
|
269
|
+
import { z } from 'zod';
|
|
270
|
+
|
|
271
|
+
export const createPostSchema = z.object({
|
|
272
|
+
title: z.string().min(1).max(255),
|
|
273
|
+
content: z.string().min(1),
|
|
274
|
+
});
|
|
275
|
+
```
|
|
276
|
+
|
|
277
|
+
### API Routes
|
|
278
|
+
|
|
279
|
+
Create type-safe API routes:
|
|
280
|
+
|
|
281
|
+
```typescript
|
|
282
|
+
// src/pages/api/posts.ts
|
|
283
|
+
import type { APIRoute } from 'astro';
|
|
284
|
+
import { db } from '@/db/initialize';
|
|
285
|
+
import { posts } from '@/db/schema';
|
|
286
|
+
import { createPostSchema } from '@/db/validations';
|
|
287
|
+
|
|
288
|
+
export const POST: APIRoute = async ({ request }) => {
|
|
289
|
+
const body = await request.json();
|
|
290
|
+
const validated = createPostSchema.parse(body);
|
|
291
|
+
|
|
292
|
+
const [newPost] = await db
|
|
293
|
+
.insert(posts)
|
|
294
|
+
.values(validated)
|
|
295
|
+
.returning();
|
|
296
|
+
|
|
297
|
+
return new Response(JSON.stringify(newPost), { status: 201 });
|
|
298
|
+
};
|
|
299
|
+
```
|
|
300
|
+
|
|
301
|
+
## 🤖 AI Integration
|
|
302
|
+
|
|
303
|
+
The stack includes Vercel AI SDK with AI Gateway for seamless AI integration - no provider-specific packages needed!
|
|
304
|
+
|
|
305
|
+
**Note:** AI Gateway requires Vercel AI SDK v5.0.0 or later (already configured in this stack).
|
|
306
|
+
|
|
307
|
+
```typescript
|
|
308
|
+
// src/pages/api/chat.ts
|
|
309
|
+
import type { APIRoute } from 'astro';
|
|
310
|
+
import { streamText } from 'ai';
|
|
311
|
+
|
|
312
|
+
export const POST: APIRoute = async ({ request }) => {
|
|
313
|
+
const { messages } = await request.json();
|
|
314
|
+
|
|
315
|
+
const result = streamText({
|
|
316
|
+
model: 'openai/gpt-4o', // Use model string directly - supports any provider
|
|
317
|
+
messages,
|
|
318
|
+
apiKey: process.env.OPENAI_API_KEY,
|
|
319
|
+
});
|
|
320
|
+
|
|
321
|
+
return result.toDataStreamResponse();
|
|
322
|
+
};
|
|
323
|
+
```
|
|
324
|
+
|
|
325
|
+
**Supported model formats:**
|
|
326
|
+
|
|
327
|
+
- OpenAI: `openai/gpt-4.1`, `openai/o4-mini`
|
|
328
|
+
- Anthropic: `anthropic/claude-3-5-sonnet-20241022`
|
|
329
|
+
- Google: `google/gemini-1.5-pro`
|
|
330
|
+
- And many more providers without extra dependencies!
|
|
331
|
+
|
|
332
|
+
## 🔐 Authentication
|
|
333
|
+
|
|
334
|
+
Clerk is pre-configured for authentication. Protect routes with middleware:
|
|
335
|
+
|
|
336
|
+
```typescript
|
|
337
|
+
// src/middleware.ts
|
|
338
|
+
import { clerkMiddleware } from '@clerk/astro/server';
|
|
339
|
+
|
|
340
|
+
export const onRequest = clerkMiddleware();
|
|
341
|
+
```
|
|
342
|
+
|
|
343
|
+
## 🚀 Deployment
|
|
344
|
+
|
|
345
|
+
### Vercel (Recommended)
|
|
346
|
+
|
|
347
|
+
The Vercel CLI is already included in the project! If you used the CLI setup, you may already be logged in.
|
|
348
|
+
|
|
349
|
+
```bash
|
|
350
|
+
# Login to Vercel (if not already logged in)
|
|
351
|
+
npx vercel login
|
|
352
|
+
|
|
353
|
+
# Deploy to production
|
|
354
|
+
npx vercel --prod
|
|
355
|
+
```
|
|
356
|
+
|
|
357
|
+
### Environment Variables on Vercel
|
|
358
|
+
|
|
359
|
+
Set these in your Vercel project settings:
|
|
360
|
+
|
|
361
|
+
- `DATABASE_URL`
|
|
362
|
+
- `CLERK_SECRET_KEY`
|
|
363
|
+
- `OPENAI_API_KEY`
|
|
364
|
+
|
|
365
|
+
## 📚 Documentation
|
|
366
|
+
|
|
367
|
+
- [Astro Documentation](https://docs.astro.build)
|
|
368
|
+
- [Drizzle ORM Documentation](https://orm.drizzle.team/docs)
|
|
369
|
+
- [Clerk Documentation](https://clerk.com/docs)
|
|
370
|
+
- [Zero Sync Documentation](https://zero.rocicorp.dev)
|
|
371
|
+
- [Zod Documentation](https://zod.dev)
|
|
372
|
+
- [Vercel AI SDK Documentation](https://sdk.vercel.ai/docs)
|
|
373
|
+
|
|
374
|
+
## 🛠️ Available Scripts
|
|
375
|
+
|
|
376
|
+
```bash
|
|
377
|
+
npm run dev # Start development server
|
|
378
|
+
npm run build # Build for production
|
|
379
|
+
npm run preview # Preview production build
|
|
380
|
+
npm run db:generate # Generate database migrations
|
|
381
|
+
npm run db:migrate # Run database migrations
|
|
382
|
+
npm run db:push # Push schema to database
|
|
383
|
+
npm run db:studio # Open Drizzle Studio
|
|
384
|
+
```
|
|
385
|
+
|
|
386
|
+
## 📄 License
|
|
387
|
+
|
|
388
|
+
MIT License - see LICENSE file for details
|
|
389
|
+
|
|
390
|
+
## 🤝 Contributing
|
|
391
|
+
|
|
392
|
+
Contributions are welcome! Please open an issue or submit a pull request.
|
|
393
|
+
|
|
394
|
+
## 💡 Why This Stack?
|
|
395
|
+
|
|
396
|
+
1. **Type Safety** - TypeScript + Drizzle + Zod ensure type safety from database to frontend
|
|
397
|
+
2. **Performance** - Astro's zero-JS by default approach for maximum performance
|
|
398
|
+
3. **Real-time Sync** - Zero provides local-first data synchronization for responsive UIs
|
|
399
|
+
4. **Developer Experience** - Modern tooling with excellent IDE support and automated setup
|
|
400
|
+
5. **Scalability** - PostgreSQL + serverless architecture scales effortlessly
|
|
401
|
+
6. **Security** - Clerk handles authentication, Zod validates inputs
|
|
402
|
+
7. **AI-Ready** - Vercel AI SDK integration for modern AI features
|
|
403
|
+
8. **PWA Support** - Offline-first capabilities with Vite PWA
|
|
404
|
+
9. **Clean Architecture** - Enforced separation of concerns, especially for styles
|
|
405
|
+
10. **Quick Start** - Automated environment setup and database initialization
|