Photos
The project photo log, with albums, capture dates read from the camera, AI tagging you confirm, and revocable share links
Photos is the project's photograph log. Upload from the field, file into
albums, tag by trade and location, and attach a photograph to the record it is
evidence for. The bytes live in the project's Drive under Shared/Photos; the
photo record is the construction metadata bolted on top.
Upload
- Open Photos in the project.
- Click Upload photos, or drag files onto the grid.
- Files are screened before anything leaves your device: anything that is not an image, anything over 64 MB, and anything empty is refused by name with the reason. Nothing is silently dropped.
Accepted: JPEG, PNG, WebP, HEIC, HEIF, GIF, BMP, TIFF, and AVIF. HEIC from an iPhone is accepted even when the browser hands over an empty MIME type, which Safari and some Android pickers do.
Four files upload at once. Past 200 files in one batch, the rest are refused by name rather than queued.
A partial batch always names what failed and why. A bulk operation that only partly worked returns HTTP 207 with the failures listed, so a client that only checks for success cannot mistake it for a clean run.
Capture date, and the day a photo belongs to
Two different facts, kept separate on purpose:
- Taken at is an instant, read from the camera's EXIF
DateTimeOriginalwhen it is there. When it is not, it falls back to the upload time, and the record says which of the two it is. - Day is the calendar day the photographer was standing in, read off the camera's wall clock with no timezone arithmetic.
The distinction matters because a photograph shot at 8pm can read as the next day in UTC, and because telling the confirm dialog "these four undated photos are Tuesday's" answers a question about the day without pretending to know the minute. Struxen does not write a fabricated noon into the instant to express that.
The day is what the daily album files on and what Daily logs picks up for the day's report.
Albums
Two kinds:
- Daily albums are created automatically, one per calendar day, by the auto-filing flow.
- Manual albums are the ones you name.
The album rail shows a photo count. Treat it as a hint: it is maintained with atomic increments and a crash between the photo write and the counter can leave it off by one, so nothing in the product depends on it.
Unfiled selects photos in no album. Moving photos between albums is a bulk action on the grid.
Filtering and search
The grid filters by album, trade, location, uploader, capture-date range, and a free-text search over filename, description and location. Two AI-derived filters exist as well: photos flagged as a safety concern, and photos by quality read (Good work, Quality issues, Neutral).
Trades
Trades are a closed list of 26 values, ordered roughly by construction sequence: Sitework, Earthwork, Utilities, Concrete, Masonry, Structural Steel, Carpentry, Waterproofing, Roofing, Doors & Windows, Glazing, Framing & Drywall, Finishes, Flooring, Painting, Specialties, Equipment, Elevators, Fire Protection, Plumbing, HVAC, Electrical, Low Voltage, Landscaping, Safety, and General Conditions.
Free text was deliberately not offered: six spellings of "HVAC" make the filter bar useless inside a week.
AI tagging
Select photographs on the grid and click Auto-tag. One vision pass runs over the selection and writes back a caption, up to three trades, a safety flag, and a quality read. The write rules are the point:
- AI never overwrites what you typed. Your description, trade and location are untouched. The AI caption renders only where there is no description of yours, and it is visibly attributed.
- A proposed trade or location is a suggestion until you accept it. The AI proposes, you dispose.
- A response that fails validation stores nothing. A photo with no caption is honest; a hallucinated one is not.
- Rotation you set beats rotation the model proposes, including an explicit 0 degrees. A person who pressed rotate until the photograph looked right has answered the question.
This is a metered AI operation and runs against the project's credit pool. It is capped at 12 photos per batch and 3 trades per photo.
Attaching a photo to a record
A photograph can be attached to a punch item, a daily log, an inspection, an RFI, an observation, a meeting, a submittal, a drawing, or a safety incident. The photo detail panel lists everything it is attached to.
Attaching does not copy the file. The link is the record, and detaching leaves the photograph in the log.
Share links
Share album on an open album, or Share link on a single photograph, opens the share dialog. Name the link, choose an expiry, and click Create link; the URL is copied to your clipboard.
A share link is a revocable deep link, not a password. Redeeming one still requires a signed-in Struxen session with at least READ_ONLY on this project's Photos tool. An unauthenticated visitor is refused, and so is somebody who has a Struxen account but no access to the project. There is deliberately no public or anonymous variant: job-site photographs are evidence, and an unauthenticated URL that escapes into a forwarded email is a discovery problem.
What the link adds is a stable, revocable pointer that survives being pasted into a thread.
- Expiry options are Until revoked, 7, 30, or 90 days.
- Revoke takes effect immediately and is checked on every redemption before anything is read.
- Recipients see a read-only view: no editing, no bulk actions, no upload.
- Refusals are specific. A revoked link, an expired link, and a viewer without project access are told three different things, because the next action differs in each case.
Deleting
Deletion is tiered:
| Level | What you can delete |
|---|---|
| STANDARD | Photographs you uploaded |
| ADMIN | Anybody's photographs, plus albums and anybody's share links |
Deleting a photo is a soft delete. The row is never hard-deleted, and the Drive file's own recycle bin is the recovery path for the bytes. An audit trail of who removed the photograph of the thing that later became a claim is worth more than the storage.
Permissions
Photos gate on the Photos tool. See Permissions.
| Action | Level |
|---|---|
| List, view, redeem a share link | READ_ONLY |
| Upload, edit, bulk tag and move, create albums, create share links, run AI analysis | STANDARD |
| Delete your own photographs | STANDARD |
| Delete anybody's photographs, delete albums, revoke anybody's share links | ADMIN |
Limits
| Limit | Value |
|---|---|
| File size | 64 MB per photo |
| Batch size | 200 photos |
| Concurrent uploads | 4 |
| AI analysis batch | 12 photos |
| Trades per photo | 3 |
| AI caption | 280 characters |
Every enforced limit across Struxen is collected at Limits.
Troubleshooting
A file was refused as "not an image". The browser reported a non-image MIME type and the extension is not one of the accepted image extensions. Rename or re-export it.
A 300 MB file was refused before uploading. That is deliberate. Screening runs locally, so you learn that a video from the same camera roll is not a photograph before spending job-site bandwidth on it, not after.
Some photos in a batch uploaded and some did not. That is a partial result, reported as one. Read the failure list: each entry names the file and the reason.
A recipient says the share link asks them to sign in. It does, and it is supposed to. The link is not a capability. Give them project access with at least READ_ONLY on Photos, or send them the photographs another way.
The album count looks wrong by one. It is advisory. Open the album; the listing is the truth.
A photo is on the wrong day's report. The day is read from the camera's wall clock. Correct it on the photo, or untick the photo on that day's report in Daily logs if it belongs to a different day.
The AI caption did not appear. Either you already wrote a description, in which case yours wins, or the model's response failed validation and nothing was stored. Run it again.