update draw
This commit is contained in:
parent
e404721818
commit
c4439e76a8
|
|
@ -633,7 +633,7 @@ const deleteMonthlyDraw = async (req, res) => {
|
|||
const updateMonthlyDraw = async (req, res) => {
|
||||
try {
|
||||
const { draw_id } = req.params;
|
||||
const { winner_id, prize_amount, notes } = req.body;
|
||||
const { winner_id, prize_amount, notes, month, year, draw_date } = req.body;
|
||||
const managerId = req.user.id;
|
||||
|
||||
// Find the draw
|
||||
|
|
@ -664,41 +664,120 @@ const updateMonthlyDraw = async (req, res) => {
|
|||
|
||||
const updates = {};
|
||||
|
||||
// Update winner if provided
|
||||
if (winner_id) {
|
||||
// Verify the winner is a member of the group
|
||||
const member = await GroupMember.findOne({
|
||||
where: {
|
||||
group_id: monthlyDraw.ChitGroup.id,
|
||||
user_id: winner_id,
|
||||
status: 'active'
|
||||
},
|
||||
include: [{ model: User, attributes: ['id', 'full_name'] }]
|
||||
});
|
||||
let nextMonth = monthlyDraw.month;
|
||||
let nextYear = monthlyDraw.year;
|
||||
const monthProvided = month !== undefined && month !== null && month !== '';
|
||||
const yearProvided = year !== undefined && year !== null && year !== '';
|
||||
if (monthProvided) {
|
||||
nextMonth = parseInt(month, 10);
|
||||
}
|
||||
if (yearProvided) {
|
||||
nextYear = parseInt(year, 10);
|
||||
}
|
||||
|
||||
if (!member) {
|
||||
if (monthProvided || yearProvided) {
|
||||
if (Number.isNaN(nextMonth) || nextMonth < 1 || nextMonth > 12) {
|
||||
return res.status(400).json({
|
||||
success: false,
|
||||
message: 'Winner must be an active member of this group'
|
||||
message: 'Month must be between 1 and 12'
|
||||
});
|
||||
}
|
||||
if (Number.isNaN(nextYear) || nextYear < 2020) {
|
||||
return res.status(400).json({
|
||||
success: false,
|
||||
message: 'Year must be 2020 or later'
|
||||
});
|
||||
}
|
||||
const conflict = await MonthlyDraw.findOne({
|
||||
where: {
|
||||
group_id: monthlyDraw.group_id,
|
||||
month: nextMonth,
|
||||
year: nextYear,
|
||||
id: { [Op.ne]: draw_id }
|
||||
}
|
||||
});
|
||||
if (conflict) {
|
||||
return res.status(400).json({
|
||||
success: false,
|
||||
message: `Another draw already exists for ${nextMonth}/${nextYear}`
|
||||
});
|
||||
}
|
||||
updates.month = nextMonth;
|
||||
updates.year = nextYear;
|
||||
}
|
||||
|
||||
updates.winner_id = winner_id;
|
||||
if (!notes) {
|
||||
updates.notes = `Winner updated to: ${member.User.full_name}`;
|
||||
if (draw_date !== undefined && draw_date !== null && draw_date !== '') {
|
||||
const d = new Date(draw_date);
|
||||
if (Number.isNaN(d.getTime())) {
|
||||
return res.status(400).json({
|
||||
success: false,
|
||||
message: 'Invalid draw_date'
|
||||
});
|
||||
}
|
||||
updates.draw_date = d;
|
||||
}
|
||||
|
||||
// Update winner if provided and different from current
|
||||
if (winner_id) {
|
||||
const winnerStr = String(winner_id);
|
||||
const currentWinnerStr = monthlyDraw.winner_id != null ? String(monthlyDraw.winner_id) : '';
|
||||
if (winnerStr !== currentWinnerStr) {
|
||||
const member = await GroupMember.findOne({
|
||||
where: {
|
||||
group_id: monthlyDraw.ChitGroup.id,
|
||||
user_id: winner_id,
|
||||
status: 'active'
|
||||
},
|
||||
include: [{ model: User, attributes: ['id', 'full_name'] }]
|
||||
});
|
||||
|
||||
if (!member) {
|
||||
return res.status(400).json({
|
||||
success: false,
|
||||
message: 'Winner must be an active member of this group'
|
||||
});
|
||||
}
|
||||
|
||||
const duplicateWinner = await MonthlyDraw.findOne({
|
||||
where: {
|
||||
group_id: monthlyDraw.group_id,
|
||||
winner_id,
|
||||
id: { [Op.ne]: draw_id }
|
||||
}
|
||||
});
|
||||
if (duplicateWinner) {
|
||||
return res.status(400).json({
|
||||
success: false,
|
||||
message: `${member.User.full_name} has already won in another draw. Each member can only win once.`,
|
||||
alreadyWon: true,
|
||||
winnerName: member.User.full_name
|
||||
});
|
||||
}
|
||||
|
||||
updates.winner_id = winner_id;
|
||||
if (notes === undefined || notes === null) {
|
||||
updates.notes = `Winner updated to: ${member.User.full_name}`;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Update prize amount if provided
|
||||
if (prize_amount) {
|
||||
// Update prize amount if provided (including 0)
|
||||
if (prize_amount != null && prize_amount !== '') {
|
||||
updates.prize_amount = prize_amount;
|
||||
}
|
||||
|
||||
// Update notes if provided
|
||||
if (notes) {
|
||||
if (notes !== undefined && notes !== null) {
|
||||
updates.notes = notes;
|
||||
}
|
||||
|
||||
if (Object.keys(updates).length === 0) {
|
||||
return res.status(400).json({
|
||||
success: false,
|
||||
message: 'No valid fields to update'
|
||||
});
|
||||
}
|
||||
|
||||
// Perform update
|
||||
await monthlyDraw.update(updates);
|
||||
|
||||
|
|
|
|||
|
|
@ -581,13 +581,18 @@ class ApiService {
|
|||
if (e.response != null) {
|
||||
final responseData = e.response?.data;
|
||||
String message = 'Request failed';
|
||||
|
||||
|
||||
if (responseData is Map<String, dynamic>) {
|
||||
message = responseData['message']?.toString() ?? 'Request failed';
|
||||
final merged = Map<String, dynamic>.from(responseData);
|
||||
merged['success'] = false;
|
||||
merged['message'] = message;
|
||||
merged['statusCode'] = e.response?.statusCode;
|
||||
return merged;
|
||||
} else if (responseData is String) {
|
||||
message = responseData;
|
||||
}
|
||||
|
||||
|
||||
return {
|
||||
'success': false,
|
||||
'message': message,
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:flutter_screenutil/flutter_screenutil.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
import '../../core/services/chit_group_service.dart';
|
||||
import '../../core/services/api_service.dart';
|
||||
import '../../core/models/monthly_draw.dart';
|
||||
|
|
@ -26,6 +27,33 @@ class _EditDrawDialogState extends State<EditDrawDialog> {
|
|||
|
||||
String? _selectedMemberId;
|
||||
bool _isLoading = false;
|
||||
late int _editMonth;
|
||||
late int _editYear;
|
||||
late DateTime _drawDate;
|
||||
|
||||
static const _monthNames = <String>[
|
||||
'', 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec',
|
||||
];
|
||||
|
||||
DateTime _baselineDrawDate() {
|
||||
final d = widget.draw.drawDate;
|
||||
if (d.millisecondsSinceEpoch == 0) {
|
||||
return DateTime(widget.draw.year, widget.draw.month, 1);
|
||||
}
|
||||
return d;
|
||||
}
|
||||
|
||||
bool _sameCalendarDay(DateTime a, DateTime b) {
|
||||
return a.year == b.year && a.month == b.month && a.day == b.day;
|
||||
}
|
||||
|
||||
int _clampEditYear(int y) {
|
||||
final minY = 2020;
|
||||
final maxY = DateTime.now().year + 1;
|
||||
if (y < minY) return minY;
|
||||
if (y > maxY) return maxY;
|
||||
return y;
|
||||
}
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
|
|
@ -33,6 +61,9 @@ class _EditDrawDialogState extends State<EditDrawDialog> {
|
|||
_selectedMemberId = widget.draw.winnerId;
|
||||
_prizeAmountController.text = widget.draw.prizeAmount.toStringAsFixed(0);
|
||||
_notesController.text = widget.draw.notes ?? '';
|
||||
_editMonth = widget.draw.month.clamp(1, 12);
|
||||
_editYear = _clampEditYear(widget.draw.year);
|
||||
_drawDate = _baselineDrawDate();
|
||||
}
|
||||
|
||||
@override
|
||||
|
|
@ -42,6 +73,18 @@ class _EditDrawDialogState extends State<EditDrawDialog> {
|
|||
super.dispose();
|
||||
}
|
||||
|
||||
Future<void> _pickDrawDate() async {
|
||||
final picked = await showDatePicker(
|
||||
context: context,
|
||||
initialDate: _drawDate,
|
||||
firstDate: DateTime(2020),
|
||||
lastDate: DateTime.now().add(const Duration(days: 365 * 3)),
|
||||
);
|
||||
if (picked != null) {
|
||||
setState(() => _drawDate = picked);
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _handleSubmit() async {
|
||||
if (_formKey.currentState!.validate()) {
|
||||
if (_selectedMemberId == null) {
|
||||
|
|
@ -54,7 +97,16 @@ class _EditDrawDialogState extends State<EditDrawDialog> {
|
|||
try {
|
||||
final updates = <String, dynamic>{};
|
||||
|
||||
// Only include changed fields
|
||||
if (_editMonth != widget.draw.month) {
|
||||
updates['month'] = _editMonth;
|
||||
}
|
||||
if (_editYear != widget.draw.year) {
|
||||
updates['year'] = _editYear;
|
||||
}
|
||||
if (!_sameCalendarDay(_drawDate, _baselineDrawDate())) {
|
||||
updates['draw_date'] = _drawDate.toUtc().toIso8601String();
|
||||
}
|
||||
|
||||
if (_selectedMemberId != widget.draw.winnerId) {
|
||||
updates['winner_id'] = _selectedMemberId;
|
||||
}
|
||||
|
|
@ -64,7 +116,7 @@ class _EditDrawDialogState extends State<EditDrawDialog> {
|
|||
updates['prize_amount'] = newPrizeAmount;
|
||||
}
|
||||
|
||||
if (_notesController.text.isNotEmpty && _notesController.text != widget.draw.notes) {
|
||||
if (_notesController.text != (widget.draw.notes ?? '')) {
|
||||
updates['notes'] = _notesController.text;
|
||||
}
|
||||
|
||||
|
|
@ -83,10 +135,20 @@ class _EditDrawDialogState extends State<EditDrawDialog> {
|
|||
);
|
||||
Get.back(result: true);
|
||||
} else {
|
||||
SnackbarUtil.showError(
|
||||
response['message'] ?? 'Failed to update draw',
|
||||
title: 'Error',
|
||||
);
|
||||
final isAlreadyWon = response['alreadyWon'] ?? false;
|
||||
final winnerName = response['winnerName'] ?? '';
|
||||
if (isAlreadyWon && winnerName.isNotEmpty) {
|
||||
SnackbarUtil.showError(
|
||||
'$winnerName has already won in another draw.\nEach member can only win once.',
|
||||
title: 'Duplicate winner',
|
||||
duration: const Duration(seconds: 4),
|
||||
);
|
||||
} else {
|
||||
SnackbarUtil.showError(
|
||||
response['message'] ?? 'Failed to update draw',
|
||||
title: 'Error',
|
||||
);
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
SnackbarUtil.showError('Error: ${e.toString()}');
|
||||
|
|
@ -137,7 +199,7 @@ class _EditDrawDialogState extends State<EditDrawDialog> {
|
|||
),
|
||||
),
|
||||
Text(
|
||||
'Month ${widget.draw.month}/${widget.draw.year}',
|
||||
'Originally ${widget.draw.month}/${widget.draw.year}',
|
||||
style: TextStyle(
|
||||
fontSize: 14.sp,
|
||||
color: Colors.grey.shade600,
|
||||
|
|
@ -191,6 +253,108 @@ class _EditDrawDialogState extends State<EditDrawDialog> {
|
|||
),
|
||||
SizedBox(height: 24.h),
|
||||
|
||||
Text(
|
||||
'Draw month & year',
|
||||
style: TextStyle(
|
||||
fontSize: 16.sp,
|
||||
fontWeight: FontWeight.w600,
|
||||
),
|
||||
),
|
||||
SizedBox(height: 8.h),
|
||||
Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: DropdownButtonFormField<int>(
|
||||
value: _editMonth,
|
||||
decoration: InputDecoration(
|
||||
labelText: 'Month',
|
||||
border: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(12.r),
|
||||
),
|
||||
filled: true,
|
||||
fillColor: Colors.grey.shade50,
|
||||
),
|
||||
items: List.generate(12, (i) {
|
||||
final m = i + 1;
|
||||
return DropdownMenuItem(
|
||||
value: m,
|
||||
child: Text('${_monthNames[m]} ($m)'),
|
||||
);
|
||||
}),
|
||||
onChanged: (v) {
|
||||
if (v != null) setState(() => _editMonth = v);
|
||||
},
|
||||
),
|
||||
),
|
||||
SizedBox(width: 12.w),
|
||||
Expanded(
|
||||
child: DropdownButtonFormField<int>(
|
||||
value: _editYear,
|
||||
decoration: InputDecoration(
|
||||
labelText: 'Year',
|
||||
border: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(12.r),
|
||||
),
|
||||
filled: true,
|
||||
fillColor: Colors.grey.shade50,
|
||||
),
|
||||
items: List.generate(
|
||||
DateTime.now().year - 2019 + 2,
|
||||
(i) {
|
||||
final y = 2020 + i;
|
||||
return DropdownMenuItem(
|
||||
value: y,
|
||||
child: Text('$y'),
|
||||
);
|
||||
},
|
||||
),
|
||||
onChanged: (v) {
|
||||
if (v != null) setState(() => _editYear = v);
|
||||
},
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
SizedBox(height: 8.h),
|
||||
Text(
|
||||
'This is the calendar month this draw belongs to. It must not clash with another draw in this group.',
|
||||
style: TextStyle(fontSize: 12.sp, color: Colors.grey.shade600),
|
||||
),
|
||||
SizedBox(height: 20.h),
|
||||
|
||||
Text(
|
||||
'Draw date',
|
||||
style: TextStyle(
|
||||
fontSize: 16.sp,
|
||||
fontWeight: FontWeight.w600,
|
||||
),
|
||||
),
|
||||
SizedBox(height: 8.h),
|
||||
InkWell(
|
||||
onTap: _pickDrawDate,
|
||||
borderRadius: BorderRadius.circular(12.r),
|
||||
child: InputDecorator(
|
||||
decoration: InputDecoration(
|
||||
prefixIcon: const Icon(Icons.calendar_today_outlined),
|
||||
border: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(12.r),
|
||||
),
|
||||
filled: true,
|
||||
fillColor: Colors.grey.shade50,
|
||||
),
|
||||
child: Text(
|
||||
DateFormat('d MMM yyyy').format(_drawDate),
|
||||
style: TextStyle(fontSize: 16.sp),
|
||||
),
|
||||
),
|
||||
),
|
||||
SizedBox(height: 8.h),
|
||||
Text(
|
||||
'When the draw actually happened (shown in history).',
|
||||
style: TextStyle(fontSize: 12.sp, color: Colors.grey.shade600),
|
||||
),
|
||||
SizedBox(height: 20.h),
|
||||
|
||||
// Select Winner
|
||||
Text(
|
||||
'Winner',
|
||||
|
|
|
|||
|
|
@ -1,80 +1,147 @@
|
|||
#!/bin/bash
|
||||
#!/usr/bin/env bash
|
||||
#
|
||||
# LuckyChit deployment — backend (Node/PM2) + frontend (Flutter web + PM2).
|
||||
#
|
||||
# Usage:
|
||||
# ./scripts/deploy.sh # backend + frontend
|
||||
# ./scripts/deploy.sh backend # API only
|
||||
# ./scripts/deploy.sh frontend # Flutter web only
|
||||
# ./scripts/deploy.sh backend --force # e.g. wipe node_modules / flutter clean
|
||||
#
|
||||
# Env (optional):
|
||||
# LUCKYCHIT_ROOT Repo root (default: /home/luckychit/apps/chitfund)
|
||||
# DEPLOY_BRANCH Git branch to fast-forward to (default: prod_i8n)
|
||||
|
||||
# LuckyChit Unified Deployment Script
|
||||
# Usage: ./deploy.sh [backend|frontend|--force]
|
||||
set -eo pipefail
|
||||
|
||||
set -e
|
||||
|
||||
PROJECT_DIR="/home/luckychit/apps/chitfund"
|
||||
PROJECT_DIR="${LUCKYCHIT_ROOT:-/home/luckychit/apps/chitfund}"
|
||||
BRANCH="${DEPLOY_BRANCH:-prod_i8n}"
|
||||
FORCE_REBUILD=false
|
||||
TARGET=""
|
||||
|
||||
# Check for force flag
|
||||
if [ "$1" == "--force" ] || [ "$2" == "--force" ]; then
|
||||
FORCE_REBUILD=true
|
||||
usage() {
|
||||
echo "Usage: $0 [backend|frontend] [--force]"
|
||||
echo " (no args) deploy backend and frontend"
|
||||
echo " backend deploy Node API only (pm2: luckychit-api)"
|
||||
echo " frontend build Flutter web + restart static server (pm2: luckychit-web)"
|
||||
echo " --force aggressive clean (backend: rm node_modules; frontend: flutter clean)"
|
||||
exit 1
|
||||
}
|
||||
|
||||
for arg in "$@"; do
|
||||
case "$arg" in
|
||||
--force)
|
||||
FORCE_REBUILD=true
|
||||
;;
|
||||
backend|frontend)
|
||||
if [ -n "$TARGET" ] && [ "$TARGET" != "$arg" ]; then
|
||||
echo "Error: specify only one of backend or frontend."
|
||||
usage
|
||||
fi
|
||||
TARGET="$arg"
|
||||
;;
|
||||
-h|--help)
|
||||
usage
|
||||
;;
|
||||
*)
|
||||
echo "Unknown argument: $arg"
|
||||
usage
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
run_backend() {
|
||||
[ "$TARGET" = "" ] || [ "$TARGET" = "backend" ]
|
||||
}
|
||||
|
||||
run_frontend() {
|
||||
[ "$TARGET" = "" ] || [ "$TARGET" = "frontend" ]
|
||||
}
|
||||
|
||||
cd "$PROJECT_DIR"
|
||||
|
||||
echo "LuckyChit deployment"
|
||||
echo "===================="
|
||||
echo "Root: $PROJECT_DIR"
|
||||
echo "Branch: $BRANCH"
|
||||
echo "Target: ${TARGET:-backend+frontend} force=$FORCE_REBUILD"
|
||||
echo ""
|
||||
|
||||
if [ "$(id -u)" -eq 0 ]; then
|
||||
echo "Warning: running as root. Prefer a normal user so Flutter/npm caches stay consistent."
|
||||
echo ""
|
||||
fi
|
||||
|
||||
cd $PROJECT_DIR
|
||||
|
||||
echo "🚀 LuckyChit Deployment"
|
||||
echo "======================="
|
||||
echo "Pulling latest code..."
|
||||
git fetch origin "$BRANCH"
|
||||
if ! git rev-parse --verify "refs/remotes/origin/$BRANCH" >/dev/null 2>&1; then
|
||||
echo "Error: origin/$BRANCH not found. Fetch failed or branch missing on remote."
|
||||
exit 1
|
||||
fi
|
||||
git checkout "$BRANCH"
|
||||
git merge --ff-only "origin/$BRANCH"
|
||||
echo ""
|
||||
|
||||
# Git pull
|
||||
echo "📥 Pulling latest code..."
|
||||
git stash 2>/dev/null || true
|
||||
git pull origin prod_i8n
|
||||
echo ""
|
||||
if run_backend; then
|
||||
echo "Deploying backend..."
|
||||
cd "$PROJECT_DIR/backend"
|
||||
|
||||
# Deploy backend
|
||||
if [ "$1" == "" ] || [ "$1" == "backend" ] || [ "$1" == "--force" ]; then
|
||||
echo "🔧 Deploying Backend..."
|
||||
cd $PROJECT_DIR/backend
|
||||
|
||||
if [ "$FORCE_REBUILD" = true ]; then
|
||||
echo "🗑️ Force rebuild: Removing node_modules..."
|
||||
rm -rf node_modules package-lock.json
|
||||
fi
|
||||
|
||||
if [ "$FORCE_REBUILD" = true ]; then
|
||||
echo "Force rebuild: removing node_modules and lockfile..."
|
||||
rm -rf node_modules package-lock.json
|
||||
fi
|
||||
|
||||
if [ -f package-lock.json ]; then
|
||||
npm ci
|
||||
else
|
||||
npm install
|
||||
pm2 restart luckychit-api
|
||||
echo "✅ Backend deployed"
|
||||
echo ""
|
||||
fi
|
||||
|
||||
if pm2 describe luckychit-api >/dev/null 2>&1; then
|
||||
pm2 restart luckychit-api --update-env
|
||||
else
|
||||
pm2 start ecosystem.config.js --env production
|
||||
fi
|
||||
echo "Backend done."
|
||||
echo ""
|
||||
fi
|
||||
|
||||
# Deploy frontend
|
||||
if [ "$1" == "" ] || [ "$1" == "frontend" ] || [ "$1" == "--force" ]; then
|
||||
echo "🎨 Deploying Frontend..."
|
||||
cd $PROJECT_DIR/luckychit
|
||||
|
||||
if [ "$FORCE_REBUILD" = true ]; then
|
||||
echo "🗑️ Force rebuild: Cleaning Flutter cache..."
|
||||
flutter clean
|
||||
rm -rf .dart_tool build
|
||||
fi
|
||||
|
||||
flutter pub get
|
||||
|
||||
BUILD_NUMBER=$(date +%s)
|
||||
flutter build web --release --pwa-strategy=none --build-number=$BUILD_NUMBER
|
||||
echo "📦 Build version: $BUILD_NUMBER"
|
||||
|
||||
pm2 restart luckychit-frontend
|
||||
echo "✅ Frontend deployed"
|
||||
echo ""
|
||||
if run_frontend; then
|
||||
echo "Deploying frontend (Flutter web)..."
|
||||
cd "$PROJECT_DIR/luckychit"
|
||||
|
||||
if [ "$FORCE_REBUILD" = true ]; then
|
||||
echo "Force rebuild: flutter clean..."
|
||||
flutter clean
|
||||
rm -rf .dart_tool build
|
||||
fi
|
||||
|
||||
flutter pub get
|
||||
|
||||
if [ -f tool/sync_l10n.mjs ]; then
|
||||
node tool/sync_l10n.mjs
|
||||
fi
|
||||
|
||||
BUILD_NUMBER=$(date +%s)
|
||||
flutter build web --release --pwa-strategy=none --build-number="$BUILD_NUMBER"
|
||||
echo "Build number: $BUILD_NUMBER"
|
||||
|
||||
# Name must match luckychit/ecosystem.config.js (app name: luckychit-web)
|
||||
if pm2 describe luckychit-web >/dev/null 2>&1; then
|
||||
pm2 restart luckychit-web --update-env
|
||||
else
|
||||
pm2 start ecosystem.config.js --env production
|
||||
fi
|
||||
echo "Frontend done."
|
||||
echo ""
|
||||
fi
|
||||
|
||||
# Status
|
||||
echo "📊 PM2 Status:"
|
||||
echo "PM2 status:"
|
||||
pm2 status
|
||||
|
||||
echo ""
|
||||
echo "✅ Deployment complete!"
|
||||
echo ""
|
||||
echo "🧪 Test:"
|
||||
echo " Backend: curl http://localhost:3000/health"
|
||||
echo " Frontend: curl http://localhost:8080"
|
||||
echo " Domain: https://chitfund.deepteklabs.com"
|
||||
echo ""
|
||||
echo "📝 Check logs: pm2 logs --lines 20"
|
||||
echo "💡 Clear browser cache: Ctrl + Shift + R"
|
||||
|
||||
echo "Deployment complete."
|
||||
echo "Smoke tests:"
|
||||
echo " curl -sf http://localhost:3000/health || curl -sf http://localhost:3000/api/health"
|
||||
echo " curl -sfI http://localhost:8080/"
|
||||
echo "Logs: pm2 logs --lines 30"
|
||||
|
|
|
|||
Loading…
Reference in New Issue