Skip to main content

Posted v1 requirements and evidence

Product scope

Posted saves drafts and publishes text, image and video posts for X, LinkedIn, Bluesky and Threads. Each installation has a team, human members and team-owned social connections. Multiple accounts from each provider are supported.

Delivery semantics

One group represents a posting request. The team-scoped request key is bound permanently to a content hash. Reusing a key with different content returns conflict. Every chosen connection receives one delivery record. Posted reports scheduled, publishing, published, failed, partial and uncertain outcomes truthfully. Worker claims use database leases; leases never authorize a second publish after an external request may already have reached a provider.

External verification

Provider application credentials and approved scopes are operator configuration. Local contract and integration tests do not establish that a real provider application is approved or that a real post was published. Those gates must remain explicit when reporting readiness.

Earlier local verification

On 13 October 2026, pnpm verify passed formatting, lint, strict types, all 38 integration/contract tests with no skips, and the production build using published @avgeek-oss/design-system@1.2.17. Desktop/mobile light/dark browser review covered composition, schedule editing and shared API-key/MCP tables. The API, worker and UI images were built as version 0.1.0 and started against an isolated empty PostgreSQL database. All were ready, ran as UID 1000 with read-only filesystems and dropped capabilities, and used separate API/UI origins. CORS admitted only the configured UI origin; deep UI routes, runtime configuration and the installation-secret form worked in the built containers. Runtime evidence is saved locally in artifacts/container-verification.json and browser captures in artifacts/. These are local verification images. No Posted repository publication, registry release, deployment or real social post has been made. The 13 October follow-up passed pnpm verify with 42 tests and no failures or skips. The guarded dev:preview API supports adding sample connections for all four providers while production OAuth remains configuration-gated; tests cover session, role, origin, input and installation boundaries. Browser review added LinkedIn on desktop and Bluesky on mobile, verified plain permission labels in personal/team key tables, and checked delivery counts, relative scheduled time and shared pagination outside the table at desktop and 390px mobile widths. Captures are saved in artifacts/posted-followup-desktop.png, artifacts/posted-followup-mobile.png and artifacts/posted-fixture-add-mobile.png. The subsequent UI review covered desktop, tablet and mobile routes, shared settings and MCP compositions, keyboard interaction, uploads and unavailable-API behavior. It corrected profile-menu labels, accessible provider/account names, provider-load recovery and mobile control sizes. The final verification again passed all 42 tests and a fresh UI image’s startup, readiness and deep-route checks.

Compact composer and account text

The composer separates master content and account editing/preview into two shared HeroUI Cards. A HeroUI ButtonGroup in the page header provides Post now and a Schedule dropdown on desktop and mobile. Post now requires confirmation in the shared modal before queuing the draft. Schedule opens the shared modal with a date/time picker and confirmation, using the account’s presentation time zone. Cancel leaves the draft’s schedule unchanged; existing scheduled posts retain Save changes and can change their scheduled time through the same modal. Textarea labels remain available to screen readers, and account text retains its character counter. Account chooser controls and rows both support selection. Updated provider badges come from the Sketch source. Confirmed Post now requests navigate to /posts/{id}, a dedicated delivery-set page with per-account effective content, status, published time and result in the shared responsive table. Post History links to this route; Scheduled Posts shows only Edit/Cancel actions for editable sets. Schedule editing uses Scheduled Posts / short ID / Edit Schedule breadcrumbs, with the ID linking to the delivery page and the full ID available in its tooltip. The scheduling menu/confirmation action for existing sets is Save & Update Schedule. History’s Requested column uses the creation time, matching the delivery page. The account picker stays in one row: selected avatars scroll on the left without a scrollbar, and Choose Accounts moves between the empty-state left position and the selected-state right position with reduced-motion support. Account text starts at three rows. Publish actions appear in the page header on desktop and mobile, without a delivery-count footer or divider. Account avatars show immediate error badges for over-limit or empty content and disconnected accounts. The shared horizontal ScrollShadow fades only edges with more accounts to reveal. Uploaded images can be reordered by pointer or keyboard; saved order determines priority. The API accepts the full valid image pool and the worker processes only each provider’s supported prefix, which is also used by its live preview. Reordering reuses existing image preview URLs. The compact composer now starts with master text, followed by a searchable account chooser and an avatar strip with provider badges. The strip scrolls horizontally instead of growing into multiple account-card rows. Clicking an avatar opens the account-specific text editor and live preview; unchanged accounts inherit master text and custom accounts can reset to it. The chooser has no filters or pagination. Images are shared across accounts. Delivery records persist optional custom text, the API validates each effective account payload, and workers claim the effective text. All 44 tests passed, including provider limits, save/edit/reset persistence, idempotency conflicts and separate per-account queue claims. See the UI review for responsive and container evidence. The connection preview now uses the same Add connection UI, expiring actor-bound OAuth requests and callback persistence as production. A local provider authorization page supports approval and cancellation instead of immediately creating a connection. Only external provider authorization/token transport is simulated. Reconnection, expiry, one-use callbacks and role changes are tested; all 49 tests, strict types, lint, formatting and production builds passed. Desktop approval and mobile cancellation were reviewed through the rendered app.

Team drafts

The Posts sidebar section orders Drafts, Scheduled Posts and Post History, with the same order in mobile navigation. Save as draft appears as a secondary action before the publishing button group on desktop and mobile. Draft saving permits empty content, no accounts, disconnected accounts and text exceeding provider limits. Drafts preserve master text, account overrides, selected accounts and ordered images. They use a separate database table and never create delivery jobs. The Drafts sidebar entry opens a shared responsive table with pagination outside the table, edit/view actions and confirmed deletion. Publishing still validates every target and atomically marks the source draft as converted; failed validation leaves it intact. Version checks prevent stale overwrites and request keys make retries safe. The same draft read/save/delete operations are available through REST and MCP within current permissions.

Delivery set attribution

Delivery details show Requested and Scheduled for in the shared Attributes card above the per-account delivery table. Both timestamps use the current user’s date, time and time-zone preferences. Scheduled Posts and Post History include Posted by, showing the last editor’s shared avatar and name. Creation, successful content/schedule changes and cancellation persist the authenticated human responsible, including REST and MCP callers. Failed requests, idempotent retries and background delivery work do not transfer attribution. The response contains a user ID, name and avatar URL, without exposing an email address for this column. Untouched legacy sets use their creator; previously edited sets show Not recorded until their next successful save because the previous editor was not stored. Drafts include Drafted by with the last successful saver’s shared avatar and name. The API records the authenticated actor in the same transaction as the save. Replayed requests and rejected edits preserve attribution. Untouched legacy drafts use their creator; historically edited drafts show Not recorded until saved again. The Scheduled Posts and Drafts sidebar entries show team-wide totals through the shared sidebar badge contract, including zero after loading. Scheduled totals count sets with at least one scheduled, preparing or publishing delivery, matching the list. Draft totals exclude converted drafts and are independent of pagination. Successful browser mutations refresh the badges immediately, with five-second foreground polling for worker, REST and MCP changes.

Image and video media

Single images in the live preview preserve their proportions within a 192 px maximum height and 320 px maximum width, shrinking further to fit the available card width. Preview text uses its natural content height, followed by a 12 px gap before media. Short text does not reserve blank space above images. The composer uploads JPEG, PNG and WebP images or MP4/MOV videos through the shared FileUpload control. It displays native inline video controls in the media strip and social preview, preserves ordering, and saves media in drafts and schedules. Images retain a 20 MiB upload bound. Video uploads are capped at 100 MiB and normalized asynchronously to H.264/AAC MP4, at up to 1280×720 with metadata removed. Original files remain private. Processing must finish before scheduling. Initial video duration bounds are 3–140 seconds for X, 3–180 seconds for Bluesky, 3–300 seconds for Threads and 3–1800 seconds for LinkedIn. X, Bluesky and LinkedIn accept images or the first prioritized video. Threads can use the first 20 media items in mixed carousels. Incompatible media combinations or durations appear in account error badges and are rejected by REST/MCP before queueing. Provider processing finishes during preparation, before the durable publishing boundary. Provider protocol references: X media upload, LinkedIn Videos API, Bluesky’s multipart video client, and Meta’s Threads collection. Duration bounds are conservative application limits; account quotas and access are still enforced by providers.

Release preparation, 14 October 2026

The final source gate passed formatting, lint, strict types, 67 application tests and 2 release integrity tests without failures or skips, full dependency audit and production builds. Public npm replaces the former private-registry build dependency. Version-matched Compose images, a source-build overlay, pinned CI/release actions and exact-commit/immutable-image validation are prepared. A fresh ARM64 installation passed setup-secret enforcement, verified first admin, separate-origin routing, non-root/read-only images, private video preparation, durable drafts/future schedules, retry replay, branded Mailpit email and database/private-media restoration. Final source and all three image scans have zero HIGH/CRITICAL findings. The documentation contains 24 navigation routes, generated schemas for 19 REST/MCP operations and 12 desktop/mobile theme captures; native Mintlify build and broken-link checks passed. Local AMD64 emulation failed twice with a Node/libuv assertion during dependency installation. Native AMD64/ARM64 CI remains a required publication gate. The hosted documentation domain still serves the Mintlify starter kit, and no public Posted repository, packages or release was published. See release sign-off for the completed checks, evidence and pending external gates.