All projects

ID photo management


I created an online photo submission and management app to be used with a higher-education enterprise campus card system. It replaced a process that consisted of manually downloading, identifying, and importing photos that cardholders submitted by email.

The app handles communication with cardholders regarding missing or rejected submissions, and performs two-way synchronization with the card system.

Ultimately, the app facilitates minimal input from office staff, allowing staff to efficiently process hundreds of submitted photos per day at peak times.


Incoming photo automation

  • Identification - In the weeks leading to the start of the academic year, the app checks the current list of incoming students for those who have not submitted a photo.
  • Communication - The app sends reminder emails to each student who needs to submit a photo; each message is sent one week after the last communication to that person.
  • Synchronization - When photos are approved and cropped by staff, the app uses Oracle Call Interface (OCI) to send edited photos to the Oracle database of the card system. Submitted photos are matched to the person in the card system by their ID number, which is available in the user object from the authentication system used to sign in to the app.

Time-saving features for staff

  • Editing - The app integrates crop and rotation editing with Cropper.js.
  • Workflow - The app provides multiple workflow options to conform to the editor's preference, such as a "save and next" button to move on to the next photo while the previous photo saves in the background.
  • Communication - For photos that do not meet the requirements, the editor can select multiple common issues and enter custom text for less common issues. The app bundles these issues into a notification email and triggers the weekly reminder email until the student submits a new photo.


  • Completeness - The app uses an Oracle query to detect new new photos added directly to the card system and adds them to the local database.
  • External systems - The ID Photo API is consumed by other institutional systems and databases. They can query for photos updated in the last n days in order to transfer recent photos to their local databases.
  • Flexibility and convenience - The photos are stored in AWS S3, but the current photo for each person is stored locally to provide flexible and performant hotlinking using Apache's mod_rewrite and mod_alias.

Implementation Highlights

Optimizing editor performance

When an image is uploaded, low- and medium-resolution images are stored alongside the original image. The low-resolution image is sent to the editor to minimize transfer time and optimize performance of the editor interface.

When the image is saved, only the rotation angle and crop dimensions are sent to the server. No image is sent back to the server. The app scales the dimensions up and applies them to the original image.

Flexible content delivery paths

A variety of external applications integrate ID photos, either embedding hotlinked images in web apps or downloading images to their own databases. Because these systems store ID numbers in a variety of formats, I configured Apache to accept multiple URL formats.

Photos are stored as nine-digit numbers, but the URLs can be padded by any number of zeros, and optionally preceded by a T:

# All of these paths resolve to 001234567.jpg

Applications can also embed preferences in the URL. If they prefer to have a blank image instead of a 404 response for people without an image, they can add blank to the path:


Some external applications have their own flag for each person to show or hide the photo. They can add none to the path to return a blank image in all cases, even if a photo does exist for that person:


These paths are supported by the following Apache configuration:

AliasMatch "^/photo/blank/?$" "/var/www/photos/blank_image.jpg"

<Macro PadPhoto ${digits} ${pad}>
  AliasMatch "^/photo/((blank|none)/)?T?0*(\d{${digits}})(\.jpg)?$" "/var/www/photos/${pad}$3.jpg"

Use PadPhoto 9 ""
Use PadPhoto 8 0
Use PadPhoto 7 00
Use PadPhoto 6 000
Use PadPhoto 5 0000
Use PadPhoto 4 00000
Use PadPhoto 3 000000
Use PadPhoto 2 0000000
Use PadPhoto 1 00000000

<Directory /var/www/photos>
  Options -Indexes +FollowSymLinks
  Require all granted
  ErrorDocument 404 "Photo not found"

  # If /none/ option is used, show blank image always. This provides an
  # easy URL pattern supporting those who do not want their picture shown
  RewriteCond %{REQUEST_URI} /none/
  RewriteRule (.*) /photo/blank/ [END]

  # If /blank/ option is used, show a blank image instead of a 404 for bad ID numbers
  RewriteCond %{REQUEST_FILENAME} !-f
  RewriteCond %{REQUEST_URI} /blank/
  RewriteRule (.*) /photo/blank/ [END]