Skip to content

About

Web app for uploading photos and images so that everyone can see if anyone uploads media.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Latest commit

Β 

History

26 Commits

Folders and files

NameName
Last commit message
Last commit date
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

Party Photos πŸ“Έ

A private party media vault built with Flask and Google Cloud Storage.

CODE GENERATED ENTIRELY WITH AI TOOLS (CHATGPT and GEMINI)

Users can:

  • Upload multiple images
  • Take photos directly from supported mobile devices
  • Upload images later from their device
  • Upload videos directly to Google Cloud Storage
  • View recent photos and videos
  • View all photos in a masonry-style camera roll
  • See the current number of photos and videos
  • Load photos progressively with pagination
  • Open full-resolution images only when selected
  • Automatically generate thumbnails for uploaded images
  • Upload HEIC images
  • Generate secure signed URLs for direct video uploads
  • Automatically pause videos when they scroll out of view
  • Use a password-protected admin panel
  • Delete photos from the admin dashboard
  • Delete videos from a separate admin video management page

πŸ—οΈ Project Architecture

                         β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
                         β”‚                   β”‚
                         β”‚     User          β”‚
                         β”‚     Browser       β”‚
                         β”‚                   β”‚
                         β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                                   β”‚
                                   β–Ό
                           β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
                           β”‚                β”‚
                           β”‚    Cloud Run   β”‚
                           β”‚    Flask App   β”‚
                           β”‚                β”‚
                           β””β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                                   β”‚
                    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
                    β”‚                             β”‚
                    β–Ό                             β–Ό
             Image Upload                  Signed Video URL
                    β”‚                             β”‚
                    β–Ό                             β–Ό
             Flask receives                Browser uploads
             image files                   directly to GCS
                    β”‚                             β”‚
                    β–Ό                             β”‚
             Google Cloud Storage β—„β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                    β”‚
        β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
        β–Ό           β–Ό           β–Ό
     images/   thumbnails/   videos/

πŸ“ Project Structure

Recommended project structure:

partyphotos/
β”‚
β”œβ”€β”€ app.py
β”œβ”€β”€ requirements.txt
β”œβ”€β”€ Dockerfile
β”œβ”€β”€ .dockerignore
β”œβ”€β”€ .gitignore
β”œβ”€β”€ README.md
β”‚
β”œβ”€β”€ .env
β”‚
β”œβ”€β”€ service-account.json
β”‚
└── templates/
    β”‚
    β”œβ”€β”€ base.html
    β”œβ”€β”€ index.html
    β”œβ”€β”€ images.html
    β”œβ”€β”€ videos.html
    β”œβ”€β”€ admin.html
    └── admin_videos.html

Never commit .env or service-account.json to GitHub.


🐍 1. Python Requirements

This project requires Python 3.11+.

Python 3.13 should also work with the current dependencies.

Create a virtual environment:

python3 -m venv venv

Activate it on macOS/Linux:

source venv/bin/activate

On Windows:

venv\Scripts\activate

Install dependencies:

pip install -r requirements.txt

πŸ“¦ 2. requirements.txt

Create a file called:

requirements.txt

Add:

Flask
google-cloud-storage
google-auth
python-dotenv
Pillow
pillow-heif
gunicorn

Then install:

pip install -r requirements.txt

πŸ” 3. Environment Variables

Create a .env file in the root of the project:

BUCKET_NAME=your-google-cloud-storage-bucket-name

APP_FLASK_SECRET_KEY=replace-this-with-a-long-random-secret-key

ADMIN_PASSWORD=replace-this-with-a-strong-admin-password

FLASK_DEBUG=true

Example:

BUCKET_NAME=party28

APP_FLASK_SECRET_KEY=some-long-random-secret-key

ADMIN_PASSWORD=your-private-admin-password

FLASK_DEBUG=true

Environment Variable Explanation

BUCKET_NAME

The name of your Google Cloud Storage bucket.

Example:

BUCKET_NAME=party28

The bucket should contain:

party28/
β”‚
β”œβ”€β”€ images/
β”‚
β”œβ”€β”€ thumbnails/
β”‚
└── videos/

The folders do not necessarily need to be manually created.

Google Cloud Storage creates object prefixes when files are uploaded.


APP_FLASK_SECRET_KEY

Used by Flask for:

  • Sessions
  • Admin authentication sessions
  • Flash messages

Generate a secure secret key:

python -c "import secrets; print(secrets.token_hex(32))"

Example:

APP_FLASK_SECRET_KEY=8a9d4b...

Never commit this value to GitHub.


ADMIN_PASSWORD

The password required to access:

/admin

Example:

ADMIN_PASSWORD=your-strong-password

The admin password should be configured as an environment variable.

For Cloud Run, configure it in the Cloud Run service environment variables or secrets configuration.

Do not hardcode it in:

  • app.py
  • HTML templates
  • JavaScript
  • GitHub repositories

FLASK_DEBUG

For local development:

FLASK_DEBUG=true

For production:

FLASK_DEBUG=false

Cloud Run should always run with:

FLASK_DEBUG=false

☁️ 4. Google Cloud Project

Create or use a Google Cloud project.

The current project uses:

partyphotos-501522

If you use a different project, update the relevant configuration.

Enable the required APIs:

gcloud services enable storage.googleapis.com

Also enable:

gcloud services enable iamcredentials.googleapis.com

The IAM Credentials API is required for generating signed URLs using the Cloud Run service account.


πŸͺ£ 5. Create a Google Cloud Storage Bucket

Create a bucket:

gcloud storage buckets create gs://YOUR_BUCKET_NAME \
    --location=us-central1

Example:

gcloud storage buckets create gs://party28 \
    --location=us-central1

Your bucket name must match:

BUCKET_NAME=party28

The application uses:

images/
thumbnails/
videos/

as object prefixes.


πŸ‘€ 6. Create a Service Account

Create a service account for the application:

gcloud iam service-accounts create partyphotoslocal \
    --display-name="Party Photos Application"

This creates an email similar to:

partyphotoslocal@YOUR_PROJECT_ID.iam.gserviceaccount.com

The current project uses:

partyphotoslocal@partyphotos-501522.iam.gserviceaccount.com

The application uses this service account for Google Cloud Storage access and signed URL generation.


πŸ”‘ 7. Grant Storage Permissions

The service account needs permission to:

  • Upload original images
  • Upload thumbnails
  • Read images
  • Read thumbnails
  • Read videos
  • Delete objects through the admin panel
  • Generate signed URLs

Grant the Storage Object Admin role:

gcloud projects add-iam-policy-binding YOUR_PROJECT_ID \
    --member="serviceAccount:YOUR_SERVICE_ACCOUNT_EMAIL" \
    --role="roles/storage.objectAdmin"

Example:

gcloud projects add-iam-policy-binding partyphotos-501522 \
    --member="serviceAccount:partyphotoslocal@partyphotos-501522.iam.gserviceaccount.com" \
    --role="roles/storage.objectAdmin"

πŸ” 8. Allow the Service Account to Sign URLs

For signed video uploads, the service account needs permission to sign blobs.

Grant:

gcloud iam service-accounts add-iam-policy-binding \
    partyphotoslocal@partyphotos-501522.iam.gserviceaccount.com \
    --member="serviceAccount:partyphotoslocal@partyphotos-501522.iam.gserviceaccount.com" \
    --role="roles/iam.serviceAccountTokenCreator"

This permission is important for:

blob.generate_signed_url(
    version="v4",
    ...
)

πŸ’» 9. Local Development Credentials

For local development, create a service-account key.

Download the JSON credentials file from Google Cloud.

Save it locally as:

service-account.json

Example:

/Users/your-name/Desktop/partyphotos/service-account.json

Your local code can use:

if not os.getenv("K_SERVICE"):
    os.environ[
        "GOOGLE_APPLICATION_CREDENTIALS"
    ] = "/Users/your-name/Desktop/partyphotos/service-account.json"

Important:

service-account.json

must never be uploaded to GitHub.


🚫 10. .gitignore

Create:

.gitignore

Add:

venv/
.env
service-account.json
__pycache__/
*.pyc
.DS_Store

This protects your credentials.


πŸ–ΌοΈ 11. Image Upload Flow

Images are uploaded to Flask:

Browser
   ↓
POST /upload
   ↓
Flask
   ↓
Google Cloud Storage
   ↓
images/

The original image is stored in:

images/

Example:

images/
└── uuid_originalfilename.jpg

After the original image is uploaded, a background process creates a thumbnail.

The thumbnail is stored in:

thumbnails/

Example:

thumbnails/
└── uuid_originalfilename.jpg

The frontend initially displays thumbnails instead of full-resolution images.

This improves:

  • Page loading speed
  • Mobile performance
  • Data usage
  • Gallery scrolling performance

πŸ“Έ 12. Direct Camera Capture

The upload interface supports two main upload methods:

Take Photo
     β”‚
     β–Ό
Device Camera
     β”‚
     β–Ό
Selected File
     β”‚
     β–Ό
Upload

and:

Choose Memories
     β”‚
     β–Ό
Device File Picker
     β”‚
     β–Ό
Selected Files
     β”‚
     β–Ό
Upload

The camera input typically uses:

<input
    type="file"
    accept="image/*"
    capture="environment"
>

Important:

  • Camera support depends on the browser and device.
  • The file must be attached to the upload input before submitting.
  • iOS and Android may handle multiple file selection differently.
  • Direct camera capture generally selects one image at a time.
  • Users can still upload older photos through the normal file picker.

🍎 13. iOS Upload Considerations

iOS Safari can behave differently from Android browsers when selecting multiple files.

Recommended behavior:

  • Use the normal file picker for multiple photos.
  • Use the camera input for directly taking a new photo.
  • Do not rely on the camera capture input for multiple image selection.

For multiple uploads:

<input
    type="file"
    accept="image/*"
    multiple
>

For direct camera capture:

<input
    type="file"
    accept="image/*"
    capture="environment"
>

These should be treated as separate upload experiences.


πŸ–ΌοΈ 14. HEIC Support

The application supports HEIC images using:

import pillow_heif

and:

pillow_heif.register_heif_opener()

This allows:

Image.open(...)

to read HEIC images.

The thumbnail can be converted to JPEG:

img.save(
    thumb_io,
    format="JPEG",
    quality=80
)

The original HEIC file remains in Google Cloud Storage.


πŸŽ₯ 15. Video Upload Flow

Videos do not pass through Flask.

Instead:

Browser
   β”‚
   β”‚ 1. Request signed URL
   β–Ό
Flask
   β”‚
   β”‚ 2. Generate temporary signed URL
   β–Ό
Browser
   β”‚
   β”‚ 3. Upload video directly
   β–Ό
Google Cloud Storage

The signed URL is temporary.

The video is stored in:

videos/

Example:

videos/
└── uuid_video.mp4

This is better than sending large videos through Flask because:

  • Flask does not need to process the entire video.
  • Cloud Run receives less traffic.
  • Large video uploads are faster.
  • Memory usage is reduced.

πŸ”— 16. Public Application Routes

Home

GET /

Displays:

  • Upload interface
  • Recent images
  • Recent videos
  • Image and video counts

All Images

GET /images

Displays the camera roll.

Features:

  • Masonry-style layout
  • Thumbnail-first loading
  • Pagination
  • Full-resolution image loading only when opened
  • Current image count

Example:

Camera Roll
124 PHOTOS

Videos

GET /videos

Displays uploaded videos.

Features:

  • Video playback
  • Video count
  • Pagination
  • Automatic pause when a video scrolls out of view

Image Upload

POST /upload

Receives image files.

The maximum request size is currently:

app.config["MAX_CONTENT_LENGTH"] = 500 * 1024 * 1024

This equals:

500 MB

Signed Video URL

GET /get-signed-url

Example:

/get-signed-url?filename=video.mp4&content_type=video/mp4

Returns:

{
    "url": "temporary-signed-url"
}

🎬 17. Automatic Video Pause

The videos page uses browser visibility detection.

When a video leaves the visible viewport:

User watches video
        ↓
User scrolls down
        ↓
Video leaves screen
        ↓
Video automatically pauses

This prevents multiple videos from continuing to play while the user scrolls through the page.

This improves:

  • Mobile battery usage
  • Data usage
  • User experience
  • Audio control

A typical implementation uses:

IntersectionObserver

to monitor video visibility.


πŸ” 18. Admin Panel

The admin panel is available at:

/admin

The admin system uses:

ADMIN_PASSWORD

and a Flask session.

The flow is:

User
  β”‚
  β–Ό
/admin
  β”‚
  β–Ό
Enter password
  β”‚
  β”œβ”€β”€ Incorrect
  β”‚       β”‚
  β”‚       β–Ό
  β”‚   Login error
  β”‚
  └── Correct
          β”‚
          β–Ό
    Admin session created
          β”‚
          β–Ό
    Admin dashboard

After successful login:

session["is_admin"] = True

The session is protected using:

APP_FLASK_SECRET_KEY

πŸ› οΈ 19. Admin Dashboard

The admin dashboard is:

/admin

After authentication, it displays:

  • All uploaded images
  • Image thumbnails
  • Delete buttons
  • Link to admin videos
  • Logout button

The dashboard is intended to be the admin image management page.

The public navigation remains separate.


πŸ—‘οΈ 20. Delete Images

The image delete route should be protected by the admin session.

Example:

POST /admin/delete-image/<filename>

The route should:

  1. Check whether the user is authenticated.
  2. Delete the original image.
  3. Delete the corresponding thumbnail if it exists.
  4. Redirect back to the admin dashboard.

The image deletion action should require confirmation in the browser:

Delete this photo permanently?

Deletion is permanent unless Google Cloud Storage versioning is enabled.


🎬 21. Admin Videos

Admin video management is separate from the public videos page.

The admin video page is:

/admin/videos

This page should display:

  • Uploaded videos
  • Video playback
  • Delete buttons
  • Admin navigation
  • Logout button

The admin videos page must not redirect to:

/videos

The public page:

/videos

is for viewing videos.

The admin page:

/admin/videos

is for managing and deleting videos.


πŸ—‘οΈ 22. Delete Videos

The video delete route should be protected by the admin session.

Example:

POST /admin/delete-video/<filename>

The route should:

  1. Check whether the user is authenticated.
  2. Delete the video object from:
videos/
  1. Redirect back to:
/admin/videos

The browser should ask for confirmation before deletion:

Delete this video permanently?

🧭 23. Navigation

The public navigation contains:

🏠 Home
πŸ“Έ Photos
🎬 Videos

The public navigation links:

/
 /images
 /videos

The admin management navigation should remain separate.

Recommended admin links:

πŸ“Έ Photos
🎬 Videos
πŸšͺ Logout

Admin navigation:

/admin
/admin/videos

Do not change the public Photos link to the admin page.

Public users should continue to access:

/images

The admin should access:

/admin

for image management.


πŸ§ͺ 24. Running Locally

Activate the virtual environment:

source venv/bin/activate

Make sure your .env exists.

Make sure your credentials exist:

service-account.json

Run:

python app.py

The application runs at:

http://localhost:8080

or:

http://127.0.0.1:8080

Open:

http://127.0.0.1:8080/admin

to test the admin panel.


πŸ› 25. Debug Mode

For local development:

FLASK_DEBUG=true

For production:

FLASK_DEBUG=false

Never run production applications with:

debug=True

πŸš€ 26. Production Deployment Using Cloud Run

Cloud Run automatically provides credentials to the application.

Therefore, you should not upload:

service-account.json

to Cloud Run.

The application detects Cloud Run using:

if not os.getenv("K_SERVICE"):

Locally:

GOOGLE_APPLICATION_CREDENTIALS

is used.

On Cloud Run:

Application Default Credentials

are used automatically.


🐳 27. Dockerfile

Create:

Dockerfile

with:

FROM python:3.13-slim

WORKDIR /app

ENV PYTHONDONTWRITEBYTECODE=1
ENV PYTHONUNBUFFERED=1

RUN apt-get update \
    && apt-get install -y \
        libheif1 \
        libheif-dev \
    && rm -rf /var/lib/apt/lists/*

COPY requirements.txt .

RUN pip install --no-cache-dir -r requirements.txt

COPY . .

ENV PORT=8080

CMD exec gunicorn \
    --bind :$PORT \
    --workers 1 \
    --threads 8 \
    --timeout 0 \
    app:app

🚫 28. .dockerignore

Create:

.dockerignore

Add:

venv/
.env
service-account.json
.git/
__pycache__/
*.pyc
.DS_Store

☁️ 29. Deploy to Cloud Run

Build and deploy:

gcloud run deploy partyphotos \
    --source . \
    --region us-central1 \
    --allow-unauthenticated

Set the environment variables:

gcloud run services update partyphotos \
    --region us-central1 \
    --set-env-vars BUCKET_NAME=party28,FLASK_DEBUG=false

Set the Flask secret:

gcloud run services update partyphotos \
    --region us-central1 \
    --set-env-vars APP_FLASK_SECRET_KEY="YOUR_SECRET_KEY"

Set the admin password:

gcloud run services update partyphotos \
    --region us-central1 \
    --set-env-vars ADMIN_PASSWORD="YOUR_ADMIN_PASSWORD"

For a production application, Secret Manager is preferable to storing sensitive values directly as plain environment variables.


πŸ‘€ 30. Configure the Cloud Run Service Account

The Cloud Run service should run as:

partyphotoslocal@partyphotos-501522.iam.gserviceaccount.com

Deploy using:

gcloud run deploy partyphotos \
    --source . \
    --region us-central1 \
    --service-account partyphotoslocal@partyphotos-501522.iam.gserviceaccount.com \
    --allow-unauthenticated

This allows the application to use:

google.auth.default()

without a local JSON file.


πŸ”’ 31. Important Security Rules

Never commit:

.env
service-account.json

Never hardcode:

APP_FLASK_SECRET_KEY

Never hardcode:

ADMIN_PASSWORD

Never expose your service-account private key.

Never place your Google Cloud private key inside:

templates/
static/

or any public directory.

The admin panel should always verify:

session.get("is_admin")

before allowing deletion.


πŸ› οΈ 32. Common Problems

Problem: Duplicate Flask Endpoint

Error:

AssertionError:
View function mapping is overwriting an existing endpoint function

This means two routes are using the same endpoint function name.

For example:

@app.route("/admin")
def admin():
    ...

and later:

@app.route("/admin")
def admin():
    ...

Only define one function with the endpoint name:

admin

Remove duplicate admin routes or rename the function.


Problem: Admin Password Gives Internal Server Error

Check:

  1. ADMIN_PASSWORD exists in Cloud Run.
  2. The environment variable name is exactly:
ADMIN_PASSWORD
  1. APP_FLASK_SECRET_KEY is also configured.
  2. The Cloud Run service account has required permissions.
  3. The Cloud Run logs contain the actual traceback.

Check logs:

gcloud run services logs read partyphotos \
    --region us-central1

If the password is configured after deployment, make sure a new revision was created and traffic is directed to the latest revision.


Problem: 404 Thumbnail

Example:

No such object:
thumbnails/filename.jpg

This usually means:

  • The original image exists.
  • The thumbnail does not exist.
  • Thumbnail generation failed.
  • The image was uploaded before thumbnail generation was implemented.

Possible solutions:

  1. Delete old images and re-upload them.
  2. Generate missing thumbnails.
  3. Add a fallback to the original image.

The frontend can use:

onerror="this.onerror=null; this.src='{{ img.original }}';"

Problem: Images Are Square

Make sure your image uses:

class="w-full h-auto block"

Do not use:

class="aspect-square"

or:

class="h-full object-cover"

if you want portrait and landscape proportions preserved.

For masonry layouts:

<div class="columns-2 gap-3 space-y-3">

    <div class="break-inside-avoid">

        <img
            src="{{ img.thumbnail }}"
            class="w-full h-auto block"
        >

    </div>

</div>

Problem: Full Images Load Too Early

The gallery should use:

src="{{ img.thumbnail }}"

not:

src="{{ img.original }}"

The full image should only be inserted when the modal opens.

This reduces initial data usage and improves gallery performance.


Problem: Signed URL Error

Check:

  1. The service account exists.
  2. The service account has Storage permissions.
  3. The IAM Credentials API is enabled.
  4. The service account has:
roles/iam.serviceAccountTokenCreator
  1. The service account email is correct.
  2. Cloud Run is running under the expected service account.

Problem: Admin Delete Button Does Not Work

Check:

  1. The user successfully logged in.
  2. The session contains:
session["is_admin"] = True
  1. The delete route checks:
if not session.get("is_admin"):
  1. The route is using the correct storage object path.
  2. The form action points to the admin delete route.

The public videos page should not be used for admin deletion.

Use:

/admin/videos

for admin video management.


πŸ“Š 33. Storage Layout

The bucket should eventually look like:

party28/
β”‚
β”œβ”€β”€ images/
β”‚   β”œβ”€β”€ uuid_photo1.jpg
β”‚   β”œβ”€β”€ uuid_photo2.heic
β”‚   └── uuid_photo3.png
β”‚
β”œβ”€β”€ thumbnails/
β”‚   β”œβ”€β”€ uuid_photo1.jpg
β”‚   β”œβ”€β”€ uuid_photo2.jpg
β”‚   └── uuid_photo3.jpg
β”‚
└── videos/
    β”œβ”€β”€ uuid_video1.mp4
    └── uuid_video2.mov

πŸ’° 34. Google Cloud Costs

This project may incur costs for:

  • Google Cloud Storage storage
  • Storage operations
  • Data transfer
  • Cloud Run usage

For a small party application, usage may remain very low, but monitor your Google Cloud billing dashboard.

Consider setting up a billing budget alert.


🧹 35. Cleaning Up Old Files

List images:

gcloud storage ls gs://YOUR_BUCKET_NAME/images/

List thumbnails:

gcloud storage ls gs://YOUR_BUCKET_NAME/thumbnails/

List videos:

gcloud storage ls gs://YOUR_BUCKET_NAME/videos/

Delete a file:

gcloud storage rm gs://YOUR_BUCKET_NAME/images/FILENAME

Be careful when deleting files because Google Cloud Storage deletion is permanent unless versioning is enabled.


πŸ”„ 36. Recommended Deployment Checklist

Before deploying:

[ ] requirements.txt exists
[ ] Dockerfile exists
[ ] .dockerignore exists
[ ] .gitignore exists
[ ] .env is not committed
[ ] service-account.json is not committed
[ ] BUCKET_NAME is correct
[ ] APP_FLASK_SECRET_KEY is configured
[ ] ADMIN_PASSWORD is configured
[ ] FLASK_DEBUG=false
[ ] Cloud Storage API is enabled
[ ] IAM Credentials API is enabled
[ ] Cloud Run service account has Storage permissions
[ ] Service account has Token Creator permissions
[ ] Bucket exists
[ ] Image uploads work
[ ] Direct camera capture works
[ ] Multiple image uploads work
[ ] Video uploads work
[ ] Signed URLs work
[ ] Thumbnail generation works
[ ] HEIC uploads work
[ ] Public image gallery works
[ ] Public video gallery works
[ ] Videos pause when scrolled off-screen
[ ] Admin login works
[ ] Admin image deletion works
[ ] Admin video deletion works
[ ] Admin logout works

πŸ§ͺ 37. Recommended Local Testing

Image Upload

[ ] JPG
[ ] PNG
[ ] HEIC
[ ] Portrait image
[ ] Landscape image
[ ] Multiple images
[ ] Direct camera photo
[ ] iPhone photo upload
[ ] Android photo upload

Video Upload

[ ] MP4
[ ] MOV
[ ] Large video
[ ] Video-only upload

Gallery

[ ] Thumbnail loads
[ ] Original does not load immediately
[ ] Full image opens when clicked
[ ] Portrait proportions are preserved
[ ] Landscape proportions are preserved
[ ] Load More works
[ ] Image count is displayed
[ ] Video count is displayed
[ ] Off-screen videos pause

Admin

[ ] /admin login works
[ ] Incorrect password is rejected
[ ] Correct password opens dashboard
[ ] Images are displayed
[ ] Images can be deleted
[ ] /admin/videos opens admin video page
[ ] Videos are displayed
[ ] Videos can be deleted
[ ] Logout works
[ ] Public /images remains public
[ ] Public /videos remains public

🏁 38. Final Production Architecture

                         β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
                         β”‚                   β”‚
                         β”‚     User          β”‚
                         β”‚     Browser       β”‚
                         β”‚                   β”‚
                         β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                                   β”‚
                                   β–Ό
                           β”Œβ”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”
                           β”‚                 β”‚
                           β”‚    Cloud Run    β”‚
                           β”‚    Flask App    β”‚
                           β”‚                 β”‚
                           β””β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                                   β”‚
                    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
                    β”‚                             β”‚
                    β”‚                             β”‚
            β”Œβ”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”           β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”
            β”‚                 β”‚           β”‚                 β”‚
            β”‚  Google Cloud  β”‚           β”‚  Signed Video   β”‚
            β”‚  Storage       β”‚           β”‚  Upload URL     β”‚
            β”‚                 β”‚           β”‚                 β”‚
            β””β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜           β””β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                    β”‚                              β”‚
                    β”‚                              β”‚
        β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”                  β”‚
        β”‚           β”‚           β”‚                  β”‚
        β–Ό           β–Ό           β–Ό                  β–Ό
    images/    thumbnails/   videos/       Browser β†’ GCS

πŸŽ‰ Done

The Party Photos application is designed to be a lightweight media-sharing application using:

  • Flask
  • Google Cloud Run
  • Google Cloud Storage
  • Signed URLs
  • Pillow
  • HEIC support
  • Background thumbnail generation
  • Responsive frontend layouts
  • Mobile camera capture
  • Progressive image loading
  • Automatic video pausing
  • Password-protected administration
  • Admin photo deletion
  • Admin video deletion

The most important production rules are:

Keep large video uploads away from Flask whenever possible. Use signed URLs and upload directly to Google Cloud Storage.

Keep admin credentials and Flask session secrets outside the source code.

Keep public viewing routes separate from admin management routes.

This keeps the application faster, cheaper, safer, and easier to maintain.

About

Web app for uploading photos and images so that everyone can see if anyone uploads media.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages