feat: add email verification, profile pictures, deposits, and calendar

export
Backend:
- Add email verification code generation and verification endpoints
- Add profile picture upload with S3 storage and image processing
- Add deposit_required field to users with 48h advance booking
  requirement
- Add loyalty stamps that accumulate on completed bookings
- Auto-transition bookings: confirmed → in_progress → completed
- Add booking cancellation handler with no-show detection
- Add ICS calendar file download endpoint for bookings
- Sync bookings to CalDAV on confirmation
  Frontend:
- Add schedule page route
- Add avatar and image-cropper UI components
- Update shadcn-svelte components (button, dialog)
- Add "Add to Calendar" button in booking modal
  Database:
- Add verification_codes table
- Add profile_pic_url, loyalty_stamps, deposits_required to users
- Various schema updates
This commit is contained in:
2026-02-21 18:48:29 +00:00
parent 88d8469180
commit 970cc5554d
48 changed files with 1984 additions and 175 deletions
+34
View File
@@ -66,6 +66,11 @@ func Connect() error {
bucket = "crussell"
}
profilePicsBucket := os.Getenv("S3_PROFILE_PICS_BUCKET")
if profilePicsBucket == "" {
profilePicsBucket = "crussell-profile-pics"
}
region := os.Getenv("AWS_REGION")
if region == "" {
region = "eu-west-2"
@@ -129,6 +134,35 @@ func Connect() error {
log.Printf("Bucket policy: %v (may already exist)", err)
}
// Create profile pics bucket if it doesn't exist
if profilePicsBucket != bucket {
_, err = s3Client.CreateBucket(ctx, &s3.CreateBucketInput{
Bucket: aws.String(profilePicsBucket),
})
if err != nil {
log.Printf("Profile pics bucket creation: %v (may already exist)", err)
}
// Set bucket policy for public read access
profilePolicy := fmt.Sprintf(`{
"Version": "2012-10-17",
"Statement": [{
"Sid": "PublicReadGetObject",
"Effect": "Allow",
"Principal": "*",
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::%s/*"
}]
}`, profilePicsBucket)
_, err = s3Client.PutBucketPolicy(ctx, &s3.PutBucketPolicyInput{
Bucket: aws.String(profilePicsBucket),
Policy: aws.String(profilePolicy),
})
if err != nil {
log.Printf("Profile pics bucket policy: %v (may already exist)", err)
}
}
log.Printf("Connected to local S3 (Rustfs): bucket=%s, endpoint=%s", bucket, endpoint)
return nil
}