Repository navigation
Releases: AbdoPrDZ/OTACenter
Releases · AbdoPrDZ/OTACenter
Release list
1.6.3
Fixed
- Long app descriptions failed to save with
value too long for type character varying(255).
apps.descriptionand theversions/bundleschangelogcolumns wereVARCHAR(255)while the API
accepts free text. A migration now makes all threeTEXT, so full descriptions and changelogs save.
1.6.2
Fixed
- The dashboard crashed when an app had no description. The
Appfrontend model decoded
description(andsummary) as required, but both columns are nullable — so a single app without
a description threwField description is requiredwhile loading, blanking the Home page and the apps
table. Both fields are now optional, matching the API.
1.6.1
Changed
- New brand mark. The hand-drawn SVG logo (a push arrow on an indigo→violet tile) is replaced by the
new cloud + push-arrow artwork everywhere it appears — the dashboard sidebar and home card, the auth
pages, the site header/footer shared by/,/storeand/docs, and the home hero.LogoMarkis now
a single<img>served frompublic/(/favicon.svg, so it stays sharp from the 36px sidebar chip up
to the 192px hero) with an optionalsrcoverride, instead of an inline SVG that generated a gradient
id per instance. - Favicons regenerated from the new artwork:
public/favicon.svgandpublic/favicon.ico, plus
Logo-32.png/Logo-64.png/Logo-192.png. The Blade layout declares the full set (SVG,.ico,
32px and 192px PNG and anapple-touch-icon); the SVG-onlymask-iconlink is gone. - Mark resized where it was too small to read: the home hero is now
size-32 sm:size-40 md:size-48
with adrop-shadowthat follows the artwork's alpha, the login brand blocksize-16with a larger
wordmark and heading, the dashboard home cardsize-16, and the site footersize-10.
1.6.0
Added
- App reviews & ratings. A signed-in user reviews an app once (one per user per app) with a 1–5
rating and an optional title and comment. Reviews publish immediately and can be moderated
(published/rejected) or deleted by an admin. App cards and detail now carryrating_avg/
rating_count, and the detail includes its published reviews.- New
reviewstable (soft-deleted — a re-submission reuses and restores the previous row so the
(user_id, app_id)unique index holds), aReviewmodel and aReviewController. - Endpoints:
GET /api/review,GET|POST /api/app/{app}/review,GET /api/app/{app}/review/me,
PUT|DELETE /api/app/{app}/review/{review},POST /api/app/{app}/review/{review}/moderate,
GET /api/public/apps/{app}/reviews(public) andGET /api/store/apps/{app}/reviews(authed).
- New
- Activity log. An append-only
logstable plus alog_holdersrelation, so one record can be
attached to several models (user, app, version, bundle, device, review…) at once — a relation, not a
JSON blob.Log::record()writes an entry, and the dashboard gains a global Activity page plus
per-app / per-user Activity tabs. Endpoints:GET /api/log,GET /api/app/{app}/log,
GET /api/user/{user}/log.- Logged server-side:
auth.login|failed|logout,download(public + private store),
version.install/bundle.install(OTA downloads),device.register,review.created|moderated
and the adminapp.*/version.*/bundle.*changes. - Client-reported events:
POST /ota-client/v1/app/event(API key + device) records
update.available|refused|downloaded|installed|failed|rollbackand
bundle.launch_confirmed|launch_failed, so a device's update decisions land in the same log.
- Logged server-side:
- Authenticated private store API.
GET /api/store/apps(the caller's domain-scoped catalogue),
GET /api/store/apps/{app},GET /api/store/apps/{app}/download(records history, sends
Content-Lengthand a filename; the bearer token may also travel as?token=for the browser
fallback) andGET /api/store/apps/{app}/reviews. - Reviews & Activity in the dashboard — new sidebar entries and route access, with a
ReviewsList
(moderation actions) and anActivityList(holders as chips) shared by the global pages and the
App/User inner tabs. - New seeded permissions:
review.view|create|update|delete|moderate,log.view|delete. GET /api/auth/meandPUT /api/auth/profilenow include the user'sdomains.
Changed
- CSRF is skipped for bearer-token requests. The JSON API lives in the
webgroup, so a mobile
client using a Sanctum bearer token could not satisfy CSRF and got a419. A request that carries
anAuthorization: Bearerheader is authenticated by that token and cannot be forged cross-site, so
VerifyCsrfTokennow lets it through; the dashboard SPA (cookie + CSRF) is unaffected. - Image/logo upload size limit raised from 2 MB to 4 MB (
App,Domain,User).
Fixed
- Re-submitting a review after deleting it no longer fails with a unique-constraint violation —
the soft-deleted review is reused and restored instead of inserted.
1.5.2
Fixed
- The APK install link failed with 401 in a browser. The SDK hands the APK download URL to the OS,
which opens it in a browser that cannot set theAPI-KEYheader.OtaApiKeyMiddlewarenow also
accepts the version's key from theapi_keyquery parameter (the header is still preferred and the
query is only read when the header is absent), so…/app/update/version/{version}?api_key=…works.
1.5.1
Fixed
- Form pages no longer shrink the page header. Every dashboard form page (
AppTab,VersionTab,
BundleTab— create and detail,DomainTab,SettingsTab) wrapped its entire content in a
max-w-2xlcontainer, so the breadcrumb bar and title were narrowed and centred along with the form.
The page wrapper is now full width and only the card keeps the width limit, so the header spans the
content area like it does everywhere else.
1.5.0
Added
- Forced vs optional updates. Versions and bundles now carry an
update_type(optional, the
default, orforce), set per row in the dashboard. The OTA update check reports it on each offer as
availableUpdates.version.updateType/availableUpdates.bundle.updateType, so the client can force
the user to install instead of offering a "Not now". Backward compatible: older clients ignore the
field, and a client talking to an older server treats the update asoptional.- New migrations add the column to
versionsandbundles; both models expose it intoArray()and
accept it in their validation rules (the rules are the write whitelist). AddsOtaUpdateTypeTest.
- New migrations add the column to
1.4.0
Added
- Public app store. A new public SPA at
/store(with a detail page at/store/apps/{id}) lists
every app that belongs to a domain flagged Public and has at least one published version, and
installs its published.apk— no account required. Domains gain anis_publicflag (new migration,
plus a boolean cast,toArray()and both validation rule sets — the rules are the write whitelist)
toggled from the domain form under the existingdomain.updatepermission. Domains stay private by
default.- Public JSON API, unauthenticated and throttled:
GET /api/public/apps(search,domain,
pagination),GET /api/public/domains,GET /api/public/apps/{app}and
GET /api/public/apps/{app}/download.PublicStoreControllerbuilds its own response shapes and
never returns the versionapi_key, stored file names or filesystem paths. …/downloadstreams the app's latest version when published (else the newest published one) and
records aDownloadHistoryrow./storeis the fifth Vite/React entry (resources/js/apps/store) with its own Blade shell, and a
Storelink in the public site header and footer.
- Public JSON API, unauthenticated and throttled:
Changed
npm run buildnow compiles five SPAs (home,store,docs,auth,dashboard).
1.3.0
Added
default_bundle_versionis now visible and editable. The column was fillable but missing from
Version::toArray()and from the version forms, so it never appeared in a response and could not be set
from the dashboard. The version endpoints now return it, and both the create and edit forms expose a
"Default bundle version" field.Version.tsdeclares the field as well — the frontend decoder only
keeps the fields a model lists, so a response key alone would still have been dropped.
Fixed
default_bundle_versioncould never be written through the API.VersionController::storeand
::updatederive the writable attributes from the model's validation rules
(array_diff(array_keys($rules), ['file'])), and the field was in neither the Create nor the Update
set. That is what made/ota-client/v1/app/infoanswer400 "Invalid bundle version"for a device
reporting the bundle name embedded in its APK — the casedefault_bundle_versionexists to accept.
1.2.0
Added
- Activate a bundle. A version's active bundle (
versions.latest_id) can be chosen from the dashboard:
POST /api/app/{app}/version/{version}/bundle/{bundle}/activate(gated bypermission:bundle.publish)
plus an Activate action on each inactive row of the bundles table. Nothing could set that pointer
before — only deleting a bundle cleared it — so which bundle the OTA API reports as
availableUpdates.bundlewas not changeable. - The version's APK file is visible. The version header now shows the attached file name
(Version 2 · APK: …apk), and the "Replace APK" field passes the current file so it no longer reads
"No file chosen" for a version that has one.
Fixed
tests/Feature/BundleTest.phpcreated versions withoutapi_key, which theversionstable declares
NOT NULL, so all six of its tests errored before reaching their assertions.