📸 Add screenshots, live demo section, and seed data
- 6 app screenshots (login, dashboard, kanban, card detail, users, email) - Live demo URL with 4 demo accounts (admin + 3 members) - Demo data: 3 boards, 21 cards, labels, comments, activity - Seed script for reproducible demo environment - Updated README with screenshots section and demo credentials
This commit is contained in:
101
server/seed-demo.cjs
Normal file
101
server/seed-demo.cjs
Normal file
@@ -0,0 +1,101 @@
|
||||
const bcrypt = require('bcryptjs');
|
||||
const db = require('better-sqlite3')('./data/teamflow.db');
|
||||
|
||||
db.exec(`DELETE FROM card_comments; DELETE FROM card_activity; DELETE FROM card_labels;
|
||||
DELETE FROM checklist_items; DELETE FROM checklists; DELETE FROM email_tokens;
|
||||
DELETE FROM cards; DELETE FROM lists; DELETE FROM board_members; DELETE FROM labels;
|
||||
DELETE FROM boards; DELETE FROM notifications; DELETE FROM email_log; DELETE FROM users;`);
|
||||
|
||||
const users = [
|
||||
{ email: 'admin@teamflow.local', name: 'Admin', role: 'admin', color: '#6366f1' },
|
||||
{ email: 'sarah@demo.teamflow', name: 'Sarah Chen', role: 'member', color: '#ec4899' },
|
||||
{ email: 'alex@demo.teamflow', name: 'Alex Rivera', role: 'member', color: '#14b8a6' },
|
||||
{ email: 'jordan@demo.teamflow', name: 'Jordan Lee', role: 'member', color: '#f97316' },
|
||||
];
|
||||
|
||||
const ins = db.prepare('INSERT INTO users (email, name, password, role, avatar_color) VALUES (?, ?, ?, ?, ?)');
|
||||
users.forEach(u => ins.run(u.email, u.name, bcrypt.hashSync('demo1234', 12), u.role, u.color));
|
||||
|
||||
const listIns = db.prepare('INSERT INTO lists (board_id, title, position) VALUES (?, ?, ?)');
|
||||
const labIns = db.prepare('INSERT INTO labels (board_id, name, color) VALUES (?, ?, ?)');
|
||||
const cardIns = db.prepare(`INSERT INTO cards (list_id, title, description, position, priority, assigned_to, created_by, due_date, estimated_hours, time_spent) VALUES (?,?,?,?,?,?,?,?,?,?)`);
|
||||
const clIns = db.prepare('INSERT OR IGNORE INTO card_labels (card_id, label_id) VALUES (?, ?)');
|
||||
const actIns = db.prepare('INSERT INTO card_activity (card_id, user_id, action, details) VALUES (?, ?, ?, ?)');
|
||||
const commIns = db.prepare('INSERT INTO card_comments (card_id, user_id, content) VALUES (?, ?, ?)');
|
||||
const bmIns = db.prepare('INSERT INTO board_members (board_id, user_id, role) VALUES (?, ?, ?)');
|
||||
const bIns = db.prepare('INSERT INTO boards (title, description, background, created_by) VALUES (?, ?, ?, ?)');
|
||||
|
||||
// Board 1: Sprint
|
||||
const b1 = bIns.run('Sprint 24 — Product Launch', 'Current sprint deliverables for Q2 product launch', 'gradient-indigo', 1);
|
||||
const b1id = b1.lastInsertRowid;
|
||||
[1,2,3,4].forEach((uid,i) => bmIns.run(b1id, uid, i===0?'admin':'member'));
|
||||
|
||||
const l1ids = ['📋 Backlog','🔄 In Progress','👀 In Review','✅ Done'].map((t,i) => listIns.run(b1id,t,i*65536).lastInsertRowid);
|
||||
const lab1ids = [
|
||||
['Bug','#ef4444'],['Feature','#3b82f6'],['Design','#a855f7'],['Urgent','#f97316'],['Documentation','#22c55e']
|
||||
].map(([n,c]) => labIns.run(b1id,n,c).lastInsertRowid);
|
||||
|
||||
const cards1 = [
|
||||
[0,'Fix payment gateway timeout','Users report intermittent 504 errors during checkout on mobile Safari.','urgent',3,[0,3],'2026-04-05',4,2],
|
||||
[0,'Design onboarding flow v2','New 5-step onboarding with progress indicator and skip option.','high',2,[2],'2026-04-10',8,3],
|
||||
[0,'Add SSO integration for enterprise','Support SAML and OIDC providers. Okta, Azure AD, Google Workspace.','medium',1,[1],'2026-04-15',16,0],
|
||||
[0,'Write API documentation','OpenAPI 3.0 spec for all public endpoints.','low',4,[4],'2026-04-20',6,0],
|
||||
[1,'Implement dark mode toggle','System preference detection + manual override.','medium',2,[1,2],'2026-04-08',3,2],
|
||||
[1,'Optimize image loading pipeline','Lazy loading, WebP conversion, responsive srcsets.','high',3,[1],'2026-04-07',5,4],
|
||||
[1,'Refactor auth middleware','JWT validation, refresh token rotation, rate limiting.','medium',1,[1],'2026-04-09',6,1],
|
||||
[2,'Dashboard analytics widgets','Revenue chart, user growth, conversion funnel.','medium',4,[1,2],'2026-04-06',5,5],
|
||||
[3,'Set up CI/CD pipeline','GitHub Actions with staging and production deployments.','high',1,[1],'2026-04-03',4,4],
|
||||
[3,'Fix email notification formatting','HTML templates breaking on Outlook. Switched to table-based layout.','medium',3,[0],'2026-04-02',2,1.5],
|
||||
[3,'Add rate limiting to API','Express-rate-limit with Redis backend.','low',1,[1],'2026-04-01',3,2],
|
||||
];
|
||||
|
||||
const cids1 = [];
|
||||
cards1.forEach((c,i) => {
|
||||
const [list,title,desc,pri,assign,labs,due,est,spent] = c;
|
||||
const r = cardIns.run(l1ids[list],title,desc,i*65536,pri,assign,assign,due,est,spent);
|
||||
const cid = r.lastInsertRowid;
|
||||
cids1.push(cid);
|
||||
labs.forEach(l => clIns.run(cid, lab1ids[l]));
|
||||
actIns.run(cid, assign, 'created', '');
|
||||
});
|
||||
|
||||
commIns.run(cids1[0], 3, 'I can reproduce this on iPhone 15 Pro with Safari 17.4. Request hangs ~30s then 504.');
|
||||
commIns.run(cids1[0], 1, 'Stripe webhook is timing out. Check the timeout config in our payment service.');
|
||||
commIns.run(cids1[0], 2, 'Related to the issue we saw in staging last week. Gateway config was set to 10s timeout.');
|
||||
commIns.run(cids1[4], 2, 'Using CSS custom properties with prefers-color-scheme. Manual toggle in localStorage.');
|
||||
commIns.run(cids1[4], 1, 'Great approach. Make sure email templates also respect the preference.');
|
||||
|
||||
// Board 2: Marketing
|
||||
const b2 = bIns.run('Marketing Campaigns', 'Q2 marketing initiatives and content calendar', 'gradient-pink', 2);
|
||||
const b2id = b2.lastInsertRowid;
|
||||
[1,2,4].forEach((uid,i) => bmIns.run(b2id, uid, i===0?'admin':'member'));
|
||||
const l2ids = ['📝 Ideas','🎨 Creating','📅 Scheduled','📊 Analytics'].map((t,i) => listIns.run(b2id,t,i*65536).lastInsertRowid);
|
||||
[
|
||||
[0,'Product demo video series','medium',2],
|
||||
[0,'Blog: 10 Tips for Remote Teams','low',4],
|
||||
[1,'Social media launch graphics','high',2],
|
||||
[1,'Email drip campaign for onboarding','medium',4],
|
||||
[2,'Launch announcement blog post','high',2],
|
||||
[3,'March analytics review','low',4],
|
||||
].forEach(([list,title,pri,assign],i) => cardIns.run(l2ids[list],title,'',i*65536,pri,assign,assign,null,0,0));
|
||||
|
||||
// Board 3: Bug Tracker
|
||||
const b3 = bIns.run('Bug Tracker', 'Open bugs and issue triage', 'gradient-red', 3);
|
||||
const b3id = b3.lastInsertRowid;
|
||||
[1,3].forEach((uid,i) => bmIns.run(b3id, uid, i===0?'admin':'member'));
|
||||
const l3ids = ['🐛 New','🔧 Fixing','✅ Resolved'].map((t,i) => listIns.run(b3id,t,i*65536).lastInsertRowid);
|
||||
[
|
||||
[0,'Memory leak in dashboard widgets','high',3],
|
||||
[0,'CSV export truncates at 10k rows','medium',1],
|
||||
[1,'Login redirect loop on Safari','urgent',3],
|
||||
[2,'Tooltip z-index overlap on modals','low',1],
|
||||
].forEach(([list,title,pri,assign],i) => cardIns.run(l3ids[list],title,'',i*65536,pri,assign,assign,null,0,0));
|
||||
|
||||
db.prepare('INSERT OR REPLACE INTO email_config (id, smtp_host, smtp_port, email, app_password) VALUES (1,?,?,?,?)')
|
||||
.run('smtp.gmail.com', 587, 'demo@teamflow.app', 'demo-app-password');
|
||||
|
||||
const jwt = require('jsonwebtoken');
|
||||
const token = jwt.sign({id:1,email:'admin@teamflow.local',role:'admin'},'teamflow-secret-change-in-production',{expiresIn:'365d'});
|
||||
|
||||
console.log('OK');
|
||||
console.log('TOKEN:' + token);
|
||||
Reference in New Issue
Block a user