Build Flick
KINDAback to the verdict
A personal social content planner whose honest core is a hand-posting queue that needs no API at all, with official publishing and hashtag research layered on top inside the limits each platform publishes, rather than a tool that pretends the platforms' rules do not apply.
Before step 1
Everything below is assumed from the first step. Tick each one when you actually have it, not when you plan to.
- installfree
Why Runs the server and the publishing worker.
Get it nodejs.org, or nvm install 22. open ↗
Verify
node --version prints v22 or higher - installfree locally
Why The queue lease and the attempt log need transactions so two workers never publish the same item.
Get it Docker or your package manager. open ↗
Verify
psql connects and creates a table - accountfree, and the review takes time
Why The publishing and research APIs require a professional account type and app permissions the platform reviews, and a personal account cannot use them at all.
Get it Convert or create the account type the developer documentation names, create an app, and request the permissions it lists; the hashtag endpoint needs a separate feature approval. open ↗
Verify
A test publish through the API succeeds on the account - have readyfree
Why Caption lengths, hashtag counts, image formats, carousel size, the publishing rate and the hashtag quota are all published and all change, and they live here as data.
Get it Read the content publishing and hashtag search documentation and copy the current numbers into the limits file with today's date.
Verify
The limits file has a checked date and a source for every value - have readypennies per month
Why If your platform's publishing API fetches media from an address rather than accepting an upload, local files need a temporary public one.
Get it Object storage with signed expiring links, or a small host with tokens; skip it if the API accepts uploads.
Verify
A link works for the stated period and then stops - have readyfree
Why The only honest hashtag performance data is your own, and the metrics phase needs real posts to fetch against.
Get it Import them from the platform's data export or paste their links into the queue as already posted.
Verify
Fifty posted items exist with links
Data model
Create these before the first phase that stores anything. Changing a table later is the expensive kind of change.
- drafts(id, idea, body, media_ids_json, created_at, updated_at) - variants(id, draft_id, platform, caption, hashtags_json, media_order_json, limits_version) - platform_limits(platform, version, caption_max, hashtag_max, image_formats_json, carousel_max, checked_on, source_url) · data, not code - queue_items(id, variant_id, publish_at, mode, state, published_id, attempts, last_error) · mode is by_hand or api - publish_attempts(id, queue_item_id, at, container_id, result, error_json) · so a retry can check before posting again - hashtag_lookups(id, hashtag, platform, looked_up_at, hashtag_id, result_json) · counted against the weekly quota - metrics_snapshots(id, published_id, platform, fetched_at, values_json) · every figure carries the time it was fetched - A queue item is by_hand or api, and the by_hand path is complete on its own, so the tool is useful before any platform has approved anything.
Environment variables
These go in a .env file the app reads at startup. The pack's .env.example is this table as a file · copy it, never commit the filled-in version.
| Variable | Needed | Example | Where the value comes from |
|---|---|---|---|
DATABASE_URLsecret | required | postgres://localhost:5432/planner | Drafts, queue, attempts, lookups and snapshots. |
PLATFORM_APP_ID | optional | an app id from the developer console | Only for API publishing. The by-hand queue works without it. |
PLATFORM_APP_SECRETsecret | optional | app-secret-...redacted | Only for API publishing. Never logged. |
LIMITS_PATH | required | ./config/platform-limits.json | Dated limits per platform. A data edit, not a deploy. |
HASHTAG_QUOTA_PER_WINDOW | required | 30 | Copied from the published limit with its date. Recheck before changing. |
HASHTAG_QUOTA_WINDOW_DAYS | required | 7 | The window the quota applies to. Lookups are counted against it. |
MEDIA_LINK_TTL_MINUTES | optional | 60 | Only where the API fetches from a URL. The link stops working after this. |
SCRAPE_OR_DRIVE_BROWSER | required | never | Present as a constant. There is no other value that keeps the account. |
The build, in order
Drafts and platform variants as data
One idea becomes per-platform versions checked against limits that are stored, dated and changeable.
Caption, hashtags, formats, carousel size, checked date, source.
Files
config/platform-limits.jsonsrc/limits.tsWith the limit and when it was checked.
Files
src/editor/validate.tsWhat the platform will show is what matters.
Files
src/editor/preview.ts
done when · tick each as it passeswatch out- Hard-coding a caption length or a carousel size means the tool is silently wrong the day the platform changes it, and the failure appears as a rejected post at publish time rather than in the editor. Store limits as data with the date they were checked, show that date, and make updating one a data change.
A queue that needs no API
Posting by hand is fast enough that the tool is useful with zero platform access.
Copy, media, open, paste link, done.
Files
src/queue/byhand.tsA reminder an hour off is a post that misses its slot.
Files
src/queue/reminders.tsSo the plan is visible where the person already looks.
Files
src/queue/ics.ts
done when · tick each as it passeswatch out- Building the API integration first means the tool does nothing until an app review completes, which can take weeks and may not succeed for a personal account. Build the by-hand path first and make it complete, since it works for every network.
Publishing through the official API, once
An eligible account publishes on schedule and a retry never posts twice.
So a retry can check instead of guess.
Files
src/publish/worker.tssrc/publish/attempts.tsInjected timeout after publish, one post.
Files
tests/publish-retry.test.tsThe limit is published, and the endpoint reports where you are against it.
Files
src/publish/limits.ts
done when · tick each as it passeswatch out- Retrying a publish call that timed out after the platform had already posted creates a duplicate the account owner sees before you do. Record the container id before publishing, and on retry query its status rather than publishing again. For the platform built here the published limit is a hundred API-published posts in a moving twenty-four hours, and the usage endpoint exists to be read before scheduling.
Hashtag research inside the quota
Research uses the official endpoint, spends its small weekly budget deliberately, and learns from your own posts.
Thirty unique in seven days is the budget, and the cache stretches it.
Files
src/research/quota.tssrc/research/quota.test.tsA refusal here beats an error at the platform.
Files
src/research/search.tsReal metrics on your own hashtags, not a guess about anyone else's.
Files
src/research/own.ts
done when · tick each as it passeswatch out- Building research on scraped hashtag pages or an unofficial endpoint breaks the platform's terms and puts the account at risk, and the alternative of burning the weekly quota on the first day leaves nothing for the rest of the week. Count every lookup, cache, and show the budget.
Metrics with a date on them, and leavingproduct builder
Every figure says when it was fetched, tokens expire gracefully, and everything exports.
A figure without a date is a claim without a basis.
Files
src/metrics/snapshots.tsThe queue is still useful without the API.
Files
src/publish/tokens.tsContent stays, tokens go.
Files
src/export.tssrc/disconnect.ts
done when · tick each as it passeswatch out- Displaying the last fetched engagement as though it were current, or comparing snapshots taken days apart as though they were a trend, turns the metrics page into fiction. Date every figure, compare only like with like, and say what was not fetched.
That is the whole plan for Flick. What it deliberately does not cover is below · check the gaps before you call it a replacement.
- Scraping, hidden browsers or unofficial endpoints.
- Reach estimates, predictions and best time to post.
- Team approvals and asset libraries.
- Every network at once.
- reliable direct publishing across networks
- analytics history and attribution
- team approvals and asset workflows
- protection from API and policy changes
- calendar-provider edge cases and timezone correctness
- A second platform done to the same standard, once the first has run for a month without a duplicate
- A content calendar grouped by theme, which is the planning view people actually want
- First-comment hashtags as a variant option, if the platform's API supports it when you check
Need the files? The project pack on the verdict page hands your agent the whole brief · more social media.