Skip to content

Commit daf1d30

Browse files
bejarcodeclaude
andcommitted
feat(shopify): add Shopify app scaffold (Feature 006)
Complete implementation of the cornerKit Shopify embedded app: - OAuth 2.0 authentication with token exchange - Polaris-styled dashboard with App Bridge - Prisma session storage (SQLite dev, PostgreSQL prod) - Webhook handlers (uninstall, GDPR) - Unit and integration tests 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
2 parents a4c348c + f4b7838 commit daf1d30

37 files changed

+13853
-0
lines changed

apps/shopify/.env.example

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
# Shopify App Configuration
2+
# Copy this file to .env and fill in your values
3+
4+
# Shopify API credentials (from Partners Dashboard)
5+
SHOPIFY_API_KEY=your_api_key_here
6+
SHOPIFY_API_SECRET=your_api_secret_here
7+
8+
# OAuth scopes required by the app
9+
SCOPES=read_themes,write_themes
10+
11+
# Database URL
12+
# Development: SQLite file-based storage
13+
DATABASE_URL="file:./dev.db"
14+
# Production: PostgreSQL connection string
15+
# DATABASE_URL="postgresql://user:password@host:5432/database?schema=public"
16+
17+
# App URL (set automatically by Shopify CLI in development)
18+
# APP_URL=https://your-app.example.com
19+
20+
# Environment
21+
NODE_ENV=development

apps/shopify/.gitignore

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
# Dependencies
2+
node_modules/
3+
4+
# Build outputs
5+
build/
6+
dist/
7+
.cache/
8+
9+
# Environment files (contain secrets)
10+
.env
11+
.env.local
12+
.env.*.local
13+
14+
# Database (SQLite dev files only - migrations are tracked)
15+
*.db
16+
*.db-journal
17+
18+
# IDE
19+
.idea/
20+
.vscode/
21+
*.swp
22+
*.swo
23+
24+
# OS
25+
.DS_Store
26+
Thumbs.db
27+
28+
# Shopify
29+
.shopify/
30+
31+
# Logs
32+
*.log
33+
npm-debug.log*
34+
35+
# Coverage
36+
coverage/

apps/shopify/README.md

Lines changed: 185 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,185 @@
1+
# cornerKit Shopify App
2+
3+
Shopify embedded app for applying iOS-style squircle corners to Shopify storefronts.
4+
5+
## Quick Start
6+
7+
### Prerequisites
8+
9+
- Node.js 20+
10+
- npm 10+
11+
- A [Shopify Partner account](https://partners.shopify.com/)
12+
- A development store
13+
14+
### Setup
15+
16+
1. **Clone and install dependencies:**
17+
```bash
18+
cd apps/shopify
19+
npm install
20+
```
21+
22+
2. **Set up environment:**
23+
```bash
24+
cp .env.example .env
25+
```
26+
27+
3. **Configure Shopify app:**
28+
29+
Create a new app in the [Shopify Partners Dashboard](https://partners.shopify.com/):
30+
- Go to Apps > Create app
31+
- Choose "Create app manually"
32+
- Note your API key and API secret
33+
34+
4. **Update configuration:**
35+
36+
Edit `.env` with your credentials:
37+
```env
38+
SHOPIFY_API_KEY=your_api_key
39+
SHOPIFY_API_SECRET=your_api_secret
40+
```
41+
42+
5. **Start development:**
43+
```bash
44+
npm run dev
45+
```
46+
47+
This will:
48+
- Start the Remix development server
49+
- Create a tunnel for Shopify to reach your local server
50+
- Open the app in your development store
51+
52+
## Project Structure
53+
54+
```
55+
apps/shopify/
56+
├── app/
57+
│ ├── routes/
58+
│ │ ├── _index.tsx # Root redirect
59+
│ │ ├── app.tsx # App layout with App Bridge
60+
│ │ ├── app._index.tsx # Dashboard route
61+
│ │ ├── auth.login.tsx # OAuth initiation
62+
│ │ └── auth.$.tsx # OAuth callback
63+
│ ├── components/
64+
│ │ ├── Dashboard.tsx # Main dashboard UI
65+
│ │ ├── LoadingState.tsx # Loading skeletons
66+
│ │ └── ErrorBoundary.tsx # Error displays
67+
│ ├── lib/
68+
│ │ ├── shopify.server.ts # Shopify app config
69+
│ │ ├── db.server.ts # Prisma client
70+
│ │ └── session.server.ts # Session utilities
71+
│ └── styles/
72+
│ └── app.css # Custom styles
73+
├── prisma/
74+
│ └── schema.prisma # Database schema
75+
├── extensions/
76+
│ └── theme-extension/ # Theme App Extension (Feature 007)
77+
└── shopify.app.toml # App manifest
78+
```
79+
80+
## Available Scripts
81+
82+
| Command | Description |
83+
|---------|-------------|
84+
| `npm run dev` | Start development with Shopify CLI |
85+
| `npm run build` | Build for production |
86+
| `npm run type-check` | Run TypeScript type checking |
87+
| `npm test` | Run tests |
88+
| `npm run setup` | Generate Prisma client and run migrations |
89+
90+
## Environment Variables
91+
92+
| Variable | Required | Description |
93+
|----------|----------|-------------|
94+
| `SHOPIFY_API_KEY` | Yes | App API key from Partners Dashboard |
95+
| `SHOPIFY_API_SECRET` | Yes | App API secret from Partners Dashboard |
96+
| `SCOPES` | Yes | OAuth scopes (default: `read_themes,write_themes`) |
97+
| `DATABASE_URL` | Yes | Database connection string |
98+
| `SHOPIFY_APP_URL` | No | App URL (auto-set by Shopify CLI in dev) |
99+
100+
## Database
101+
102+
### Development (SQLite)
103+
```env
104+
DATABASE_URL="file:./dev.db"
105+
```
106+
107+
### Production (PostgreSQL)
108+
```env
109+
DATABASE_URL="postgresql://user:password@host:5432/database"
110+
```
111+
112+
### Migrations
113+
114+
```bash
115+
# Create a migration
116+
npx prisma migrate dev --name migration_name
117+
118+
# Apply migrations in production
119+
npx prisma migrate deploy
120+
121+
# Reset database (development only)
122+
npx prisma migrate reset
123+
```
124+
125+
## Tech Stack
126+
127+
- **Framework**: Remix 2.x
128+
- **UI**: Shopify Polaris v13
129+
- **Embedded**: App Bridge React v4
130+
- **Auth**: @shopify/shopify-app-remix
131+
- **Database**: Prisma ORM (SQLite/PostgreSQL)
132+
- **Language**: TypeScript (strict mode)
133+
134+
## Deployment
135+
136+
### Fly.io (Recommended)
137+
138+
1. Install Fly CLI: `brew install flyctl`
139+
2. Login: `fly auth login`
140+
3. Create app: `fly launch`
141+
4. Set secrets:
142+
```bash
143+
fly secrets set SHOPIFY_API_KEY=your_key
144+
fly secrets set SHOPIFY_API_SECRET=your_secret
145+
fly secrets set SCOPES=read_themes,write_themes
146+
```
147+
5. Deploy: `fly deploy`
148+
149+
### Other Platforms
150+
151+
See [Shopify deployment docs](https://shopify.dev/docs/apps/deployment) for Heroku, Railway, Render, etc.
152+
153+
## Troubleshooting
154+
155+
### Common Issues
156+
157+
| Issue | Solution |
158+
|-------|----------|
159+
| "Invalid API key" | Check `SHOPIFY_API_KEY` in `.env` matches Partners Dashboard |
160+
| "App blocked by CSP" | Ensure app URL in Partners Dashboard matches `SHOPIFY_APP_URL` |
161+
| OAuth redirect loop | Clear browser cookies, check `authPathPrefix` matches route structure |
162+
| Prisma client error | Run `npm run setup` to regenerate Prisma client |
163+
| "Session not found" | Run `npx prisma migrate reset` to clear stale sessions |
164+
165+
### Debug Mode
166+
167+
Enable verbose logging:
168+
```bash
169+
DEBUG=shopify:* npm run dev
170+
```
171+
172+
### Resetting Development
173+
174+
```bash
175+
# Reset database and reinstall
176+
npx prisma migrate reset
177+
npm run dev
178+
```
179+
180+
## Learn More
181+
182+
- [Shopify App Development](https://shopify.dev/docs/apps)
183+
- [Remix Documentation](https://remix.run/docs)
184+
- [Polaris Components](https://polaris.shopify.com/)
185+
- [cornerKit Documentation](https://github.com/bejarcode/cornerKit)
Lines changed: 138 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,138 @@
1+
import {
2+
Page,
3+
Card,
4+
Text,
5+
BlockStack,
6+
InlineStack,
7+
Badge,
8+
Box,
9+
} from "@shopify/polaris";
10+
11+
/**
12+
* Dashboard Component
13+
*
14+
* Welcome dashboard for the cornerKit Shopify app.
15+
* Displays app status and provides navigation to features.
16+
*
17+
* @see FR-010: Polaris-styled admin interface
18+
* @see FR-012: Responsive layout (desktop/tablet)
19+
*/
20+
21+
interface DashboardProps {
22+
/** The shop's myshopify.com domain */
23+
shopName: string;
24+
}
25+
26+
export function Dashboard({ shopName }: DashboardProps) {
27+
// Extract friendly shop name (remove .myshopify.com)
28+
const friendlyName = shopName.replace(".myshopify.com", "");
29+
30+
return (
31+
<Page title="cornerKit">
32+
<BlockStack gap="500">
33+
{/* Welcome Card */}
34+
<Card>
35+
<BlockStack gap="400">
36+
<InlineStack align="space-between" blockAlign="center">
37+
<Text as="h2" variant="headingMd">
38+
Welcome to cornerKit
39+
</Text>
40+
<Badge tone="success">Connected</Badge>
41+
</InlineStack>
42+
43+
<Text as="p" variant="bodyMd" tone="subdued">
44+
Add beautiful iOS-style squircle corners to your Shopify store.
45+
cornerKit uses progressive enhancement to deliver the best
46+
possible experience across all browsers.
47+
</Text>
48+
49+
<Box paddingBlockStart="200">
50+
<Text as="p" variant="bodySm" tone="subdued">
51+
Store: <Text as="span" fontWeight="semibold">{friendlyName}</Text>
52+
</Text>
53+
</Box>
54+
</BlockStack>
55+
</Card>
56+
57+
{/* Quick Start Card */}
58+
<Card>
59+
<BlockStack gap="400">
60+
<Text as="h2" variant="headingMd">
61+
Getting Started
62+
</Text>
63+
64+
<BlockStack gap="200">
65+
<InlineStack gap="200" blockAlign="center">
66+
<Badge tone="info">1</Badge>
67+
<Text as="p" variant="bodyMd">
68+
Configure your squircle settings in the Settings tab
69+
</Text>
70+
</InlineStack>
71+
72+
<InlineStack gap="200" blockAlign="center">
73+
<Badge tone="info">2</Badge>
74+
<Text as="p" variant="bodyMd">
75+
Enable cornerKit on your theme via Theme App Extensions
76+
</Text>
77+
</InlineStack>
78+
79+
<InlineStack gap="200" blockAlign="center">
80+
<Badge tone="info">3</Badge>
81+
<Text as="p" variant="bodyMd">
82+
Preview your store to see squircle corners in action
83+
</Text>
84+
</InlineStack>
85+
</BlockStack>
86+
</BlockStack>
87+
</Card>
88+
89+
{/* Status Card */}
90+
<Card>
91+
<BlockStack gap="400">
92+
<Text as="h2" variant="headingMd">
93+
App Status
94+
</Text>
95+
96+
<InlineStack gap="400" wrap={false}>
97+
<Box
98+
background="bg-surface-secondary"
99+
padding="400"
100+
borderRadius="200"
101+
minWidth="120px"
102+
>
103+
<BlockStack gap="100" inlineAlign="center">
104+
<Text as="p" variant="headingLg" alignment="center">
105+
0
106+
</Text>
107+
<Text as="p" variant="bodySm" tone="subdued" alignment="center">
108+
Elements styled
109+
</Text>
110+
</BlockStack>
111+
</Box>
112+
113+
<Box
114+
background="bg-surface-secondary"
115+
padding="400"
116+
borderRadius="200"
117+
minWidth="120px"
118+
>
119+
<BlockStack gap="100" inlineAlign="center">
120+
<Text as="p" variant="headingLg" alignment="center">
121+
-
122+
</Text>
123+
<Text as="p" variant="bodySm" tone="subdued" alignment="center">
124+
Theme status
125+
</Text>
126+
</BlockStack>
127+
</Box>
128+
</InlineStack>
129+
130+
<Text as="p" variant="bodySm" tone="subdued">
131+
Theme configuration coming in a future update.
132+
</Text>
133+
</BlockStack>
134+
</Card>
135+
</BlockStack>
136+
</Page>
137+
);
138+
}

0 commit comments

Comments
 (0)