Claude-code-plugins-plus-skills replit-core-workflow-a
install
source · Clone the upstream repo
git clone https://github.com/jeremylongshore/claude-code-plugins-plus-skills
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/jeremylongshore/claude-code-plugins-plus-skills "$T" && mkdir -p ~/.claude/skills && cp -r "$T/plugins/saas-packs/replit-pack/skills/replit-core-workflow-a" ~/.claude/skills/jeremylongshore-claude-code-plugins-plus-skills-replit-core-workflow-a && rm -rf "$T"
manifest:
plugins/saas-packs/replit-pack/skills/replit-core-workflow-a/SKILL.mdsource content
Replit Core Workflow A — Full-Stack App
Overview
Build a production-ready web app on Replit: Express or Flask server, PostgreSQL database, Replit Auth for user login, Object Storage for file uploads, and Autoscale deployment. This is the primary money-path workflow for shipping apps on Replit.
Prerequisites
- Replit account (Core plan or higher for deployments)
and.replit
configured (seereplit.nix
)replit-install-auth- PostgreSQL provisioned in the Database pane
Instructions
Step 1: Project Structure
my-app/ ├── .replit # Run + deployment config ├── replit.nix # System dependencies ├── package.json ├── tsconfig.json ├── src/ │ ├── index.ts # Express entry point │ ├── routes/ │ │ ├── api.ts # API endpoints │ │ ├── auth.ts # Auth routes │ │ └── health.ts # Health check │ ├── services/ │ │ ├── db.ts # PostgreSQL pool │ │ └── storage.ts # Object Storage │ └── middleware/ │ ├── auth.ts # Replit Auth middleware │ └── errors.ts # Error handler └── tests/
Step 2: Configuration Files
# .replit entrypoint = "src/index.ts" run = "npx tsx src/index.ts" modules = ["nodejs-20:v8-20230920-bd784b9"] [nix] channel = "stable-24_05" [env] NODE_ENV = "development" [deployment] run = ["sh", "-c", "npx tsx src/index.ts"] build = ["sh", "-c", "npm ci"] deploymentTarget = "autoscale"
# replit.nix { pkgs }: { deps = [ pkgs.nodejs-20_x pkgs.nodePackages.typescript-language-server pkgs.postgresql ]; }
Step 3: Database Layer
// src/services/db.ts import { Pool } from 'pg'; const pool = new Pool({ connectionString: process.env.DATABASE_URL, ssl: { rejectUnauthorized: false }, max: 10, idleTimeoutMillis: 30000, connectionTimeoutMillis: 5000, }); // Initialize schema export async function initDB() { await pool.query(` CREATE TABLE IF NOT EXISTS users ( id TEXT PRIMARY KEY, username TEXT UNIQUE NOT NULL, profile_image TEXT, created_at TIMESTAMPTZ DEFAULT NOW() ); CREATE TABLE IF NOT EXISTS posts ( id SERIAL PRIMARY KEY, user_id TEXT REFERENCES users(id), title TEXT NOT NULL, content TEXT NOT NULL, created_at TIMESTAMPTZ DEFAULT NOW() ); `); } export async function upsertUser(id: string, username: string, image: string) { return pool.query( `INSERT INTO users (id, username, profile_image) VALUES ($1, $2, $3) ON CONFLICT (id) DO UPDATE SET username = $2, profile_image = $3 RETURNING *`, [id, username, image] ); } export async function createPost(userId: string, title: string, content: string) { return pool.query( 'INSERT INTO posts (user_id, title, content) VALUES ($1, $2, $3) RETURNING *', [userId, title, content] ); } export async function getPosts(limit = 20) { return pool.query( `SELECT p.*, u.username, u.profile_image FROM posts p JOIN users u ON p.user_id = u.id ORDER BY p.created_at DESC LIMIT $1`, [limit] ); } export { pool };
Step 4: Auth Middleware
// src/middleware/auth.ts import { Request, Response, NextFunction } from 'express'; import { upsertUser } from '../services/db'; export interface AuthedRequest extends Request { user: { id: string; name: string; image: string }; } export async function requireAuth(req: Request, res: Response, next: NextFunction) { const userId = req.headers['x-replit-user-id'] as string; if (!userId) return res.status(401).json({ error: 'Login required' }); const name = (req.headers['x-replit-user-name'] as string) || ''; const image = (req.headers['x-replit-user-profile-image'] as string) || ''; // Upsert user in database on every authenticated request await upsertUser(userId, name, image); (req as any).user = { id: userId, name, image }; next(); }
Step 5: API Routes
// src/routes/api.ts import { Router } from 'express'; import { requireAuth, AuthedRequest } from '../middleware/auth'; import { createPost, getPosts } from '../services/db'; import { Client as StorageClient } from '@replit/object-storage'; const router = Router(); const storage = new StorageClient(); // Public: list posts router.get('/posts', async (req, res) => { const { rows } = await getPosts(); res.json(rows); }); // Protected: create post router.post('/posts', requireAuth, async (req, res) => { const { title, content } = req.body; const user = (req as AuthedRequest).user; const { rows } = await createPost(user.id, title, content); res.status(201).json(rows[0]); }); // Protected: upload file to Object Storage router.post('/upload', requireAuth, async (req, res) => { const user = (req as AuthedRequest).user; const filename = `uploads/${user.id}/${Date.now()}-${req.body.name}`; await storage.uploadFromText(filename, req.body.content); res.json({ path: filename }); }); export default router;
Step 6: Entry Point
// src/index.ts import express from 'express'; import { initDB, pool } from './services/db'; import apiRoutes from './routes/api'; const app = express(); app.use(express.json()); // Health check (required for Replit deployments) app.get('/health', async (req, res) => { try { await pool.query('SELECT 1'); res.json({ status: 'ok', uptime: process.uptime() }); } catch { res.status(503).json({ status: 'degraded' }); } }); // Auth info endpoint (client-side: GET /__replauthuser) app.get('/api/me', (req, res) => { const id = req.headers['x-replit-user-id']; if (!id) return res.json({ loggedIn: false }); res.json({ loggedIn: true, id, name: req.headers['x-replit-user-name'], image: req.headers['x-replit-user-profile-image'], }); }); app.use('/api', apiRoutes); const PORT = parseInt(process.env.PORT || '3000'); initDB().then(() => { app.listen(PORT, '0.0.0.0', () => { console.log(`Server running on port ${PORT}`); }); });
Error Handling
| Error | Cause | Solution |
|---|---|---|
| DATABASE_URL undefined | PostgreSQL not provisioned | Create database in Database pane |
| Auth headers empty | Running in dev mode | Auth only works on deployed |
| Object Storage 403 | No bucket created | Provision bucket in Object Storage pane |
| Port conflict | Multiple services on same port | Use different ports, set |
Resources
Next Steps
For collaboration and admin workflows, see
replit-core-workflow-b.