Development Workflow

This guide covers the recommended development workflow for Vinoflare projects, from initial setup to deployment.

Initial Setup

1. Create Your Project

npm create vinoflare@latest my-app

Follow the interactive prompts to choose your template and features.

2. Environment Setup

After creation, set up your environment variables:

# Copy example file
cp .dev.vars.example .dev.vars
 
# Edit with your values
code .dev.vars

Required variables for auth-enabled templates:

BETTER_AUTH_SECRET=your-secret-key
DISCORD_CLIENT_ID=your-discord-client-id
DISCORD_CLIENT_SECRET=your-discord-client-secret

3. Database Setup (if applicable)

# Generate initial migration
npm run db:generate
 
# Apply to local database
npm run db:push:local
 
# Generate TypeScript types
npm run gen:types

Development Server

Start Everything

npm run dev

This starts:

  • 🚀 Vite dev server (port 5173)
  • 🔧 Wrangler dev server (port 8787)
  • 👀 File watchers for type generation

Access Points

  • Frontend: http://localhost:5173
  • API: http://localhost:8787
  • API Docs: http://localhost:8787/docs

Core Development Flow

1. API Development (Backend First)

Create a New Module

npm run gen:module posts

This generates:

Define the Schema

// posts.table.ts
export const posts = sqliteTable("posts", {
  id: text("id").primaryKey(),
  title: text("title").notNull(),
  content: text("content").notNull(),
  authorId: text("author_id").notNull(),
  published: integer("published", { mode: "boolean" }).default(false),
  createdAt: integer("created_at", { mode: "timestamp" }),
});

Implement Handlers

// posts.handlers.ts
export async function createPost(c: Context) {
  const user = c.get("user");
  const data = c.req.valid("json");
  
  const post = await db.insert(posts).values({
    ...data,
    authorId: user.id,
  }).returning();
  
  return c.json(post[0], 201);
}

2. Type Generation

After creating API endpoints:

# Generate OpenAPI schema
npm run gen:openapi
 
# For Orval templates
npm run gen:api
 
# For RPC templates
npm run gen:client

3. Frontend Development

Create Routes

// src/client/routes/posts/index.tsx
import { createFileRoute } from "@tanstack/react-router";
import { usePosts } from "@/client/hooks/use-posts";
 
export const Route = createFileRoute("/posts/")({
  component: PostsPage,
});
 
function PostsPage() {
  const { data: posts, isLoading } = usePosts();
  
  if (isLoading) return <div>Loading...</div>;
  
  return (
    <div className="container py-8">
      <h1>Posts</h1>
      {/* Your UI */}
    </div>
  );
}

Update Navigation

# Regenerate route tree
npm run gen:routes

Testing Strategy

1. Unit Tests (Vitest)

// posts.test.ts
describe("Posts API", () => {
  it("should create a post", async () => {
    const app = createApp();
    const res = await app.request("/api/posts", {
      method: "POST",
      json: { title: "Test", content: "Content" },
    });
    
    expect(res.status).toBe(201);
  });
});

Run tests:

npm test
npm test:watch

2. Integration Tests

describe("Posts Integration", () => {
  beforeEach(async () => {
    await resetDatabase();
  });
  
  it("should handle full post lifecycle", async () => {
    // Test create, read, update, delete
  });
});

3. E2E Tests (Optional)

# Install Playwright
npm install -D @playwright/test
 
# Run E2E tests
npm run test:e2e

Database Migrations

Create Migration

When you modify schema:

npm run db:generate

This creates a SQL migration file in drizzle/ directory.

Apply Migrations

# Local development
npm run db:push:local
 
# Production
npm run db:push:prod

Rollback (if needed)

# Create down migration
npm run db:generate -- --custom
 
# Apply specific migration
wrangler d1 execute DB --file=./drizzle/0001_rollback.sql

Git Workflow

1. Feature Branch

git checkout -b feature/add-comments

2. Commit Often

git add .
git commit -m "feat: add comment model and API endpoints"

3. Before Push

# Run linting
npm run lint
 
# Run type checking
npm run typecheck
 
# Run tests
npm test
 
# Build to verify
npm run build

4. Pull Request

Create PR with:

  • Clear description
  • Link to issue (if applicable)
  • Screenshots (for UI changes)
  • Test coverage

Debugging

Backend Debugging

// Add console logs (visible in terminal)
console.log("Debug:", data);
 
// Use Wrangler logs
wrangler tail

Frontend Debugging

  • React DevTools
  • Browser DevTools
  • Network tab for API calls

Database Debugging

# Open D1 console
wrangler d1 execute DB --command="SELECT * FROM posts"
 
# Use Drizzle Studio (if available)
npm run db:studio

Performance Optimization

1. API Optimization

// Use select specific columns
const posts = await db
  .select({
    id: posts.id,
    title: posts.title,
  })
  .from(posts);
 
// Add indexes
sqliteTable("posts", {
  // ...
}, (table) => ({
  authorIdx: index("author_idx").on(table.authorId),
}));

2. Frontend Optimization

// Lazy load routes
const PostsRoute = lazy(() => import("./routes/posts"));
 
// Optimize queries
const { data } = useQuery({
  queryKey: ["posts", { page }],
  queryFn: fetchPosts,
  staleTime: 5 * 60 * 1000, // 5 minutes
});

Deployment Preparation

1. Environment Check

# Verify all secrets are set
wrangler secret list
 
# Test production build
npm run build
npm run preview

2. Database Migration

# Apply migrations to production
npm run db:push:prod

3. Deploy

npm run deploy

Common Issues & Solutions

Types Not Updating

# Restart TS server
# In VS Code: Cmd+Shift+P -> "TypeScript: Restart TS Server"
 
# Clear cache and regenerate
rm -rf node_modules/.cache
npm run gen:types

Database Connection Issues

# Verify D1 binding
wrangler d1 list
 
# Check wrangler.toml
[[d1_databases]]
binding = "DB"
database_name = "your-db-name"
database_id = "your-db-id"

Build Failures

# Clear all caches
rm -rf node_modules/.vite
rm -rf dist
npm run build

Best Practices

  1. Commit generated files - Keep generated/ in git
  2. Run generators before commit - Ensure types are in sync
  3. Test before push - Run full test suite
  4. Use conventional commits - feat:, fix:, chore:
  5. Document API changes - Update OpenAPI descriptions
  6. Handle errors gracefully - Both frontend and backend
  7. Optimize for production - Check bundle size

Next Steps