{"id":22407705,"url":"https://github.com/roadiz/skeleton","last_synced_at":"2025-07-29T05:35:28.758Z","repository":{"id":37846598,"uuid":"445237175","full_name":"roadiz/skeleton","owner":"roadiz","description":"Project skeleton to start new headless projects with Roadiz v2 and Symfony.","archived":false,"fork":false,"pushed_at":"2025-07-28T18:02:37.000Z","size":1008,"stargazers_count":12,"open_issues_count":0,"forks_count":2,"subscribers_count":3,"default_branch":"develop","last_synced_at":"2025-07-28T19:15:11.395Z","etag":null,"topics":["bundle","cms","symfony"],"latest_commit_sha":null,"homepage":"http://www.roadiz.io","language":"PHP","has_issues":false,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/roadiz.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2022-01-06T16:30:10.000Z","updated_at":"2025-07-28T18:02:41.000Z","dependencies_parsed_at":"2024-05-03T17:01:51.423Z","dependency_job_id":"ea2ed797-965e-4f13-b823-e23b6f73cb5c","html_url":"https://github.com/roadiz/skeleton","commit_stats":{"total_commits":151,"total_committers":1,"mean_commits":151.0,"dds":0.0,"last_synced_commit":"8713cf627c958f19d802901a984d9e21a50ba991"},"previous_names":[],"tags_count":62,"template":false,"template_full_name":null,"purl":"pkg:github/roadiz/skeleton","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/roadiz%2Fskeleton","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/roadiz%2Fskeleton/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/roadiz%2Fskeleton/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/roadiz%2Fskeleton/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/roadiz","download_url":"https://codeload.github.com/roadiz/skeleton/tar.gz/refs/heads/develop","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/roadiz%2Fskeleton/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":267573744,"owners_count":24109844,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-07-28T02:00:09.689Z","response_time":68,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["bundle","cms","symfony"],"created_at":"2024-12-05T11:15:09.873Z","updated_at":"2025-07-29T05:35:28.726Z","avatar_url":"https://github.com/roadiz.png","language":"PHP","funding_links":[],"categories":[],"sub_categories":[],"readme":"# roadiz/skeleton\n**Headless API project skeleton built on Roadiz v2+**\n\n![Run test status](https://github.com/roadiz/skeleton/actions/workflows/run-test.yml/badge.svg?branch=develop)\n\n### Install\n\n```shell\nCOMPOSER_MEMORY_LIMIT=-1 composer create-project roadiz/skeleton my-website\n```\n\nCustomize configuration by copying `.env` to `.env.local`:\n\n```shell\ncp .env .env.local\n```\n\nMake sure to tell docker-compose to use `.env.local` if you are changing variables used for\ncontainers initialization (MySQL / Solr / SMTP credentials). Roadiz app will read `.env` then will override vars with your `.env.local`. \nThat's why `.env` file is committed in Git repository, and it MUST not contain any secret.\n\nIf Composer complains about memory limit issue, just prefix with `COMPOSER_MEMORY_LIMIT=-1`.\n\nEdit your `.env.local` and `docker-compose.yml` files according to your local environment.\n\n```shell\n# Copy override file to customize your local environment\ncp compose.override.yml.dist compose.override.yml\n# Do not forget to add your COMPOSER_DEPLOY_TOKEN and COMPOSER_DEPLOY_TOKEN_USER\n# in compose.override.yml to configure your container to fetch private repositories.\ndocker compose build\ndocker compose up -d --force-recreate\n```\n\nThen wait for your services to initialize, especially your *database* could take several seconds\nto initialize (filesystem, database and user creation).\n\nWhen you're ready you can check that *Symfony* console responds through your Docker service:\n\n```shell\ndocker compose exec app bin/console\n```\n\n#### Using Docker for development\n\nIf you want to ensure that your local environment is as close as possible to your production environment, \nyou should use Docker. This skeleton comes with development and production `Dockerfile` configurations. So you will\navoid troubles with installing PHP extensions, Solr, Varnish, Redis, MySQL, etc. You can also use `composer` inside\nyour app container to install your dependencies.\n\n```shell\n# This command will run once APP container to install your dependencies without starting other services\ndocker compose run --rm --no-deps --entrypoint= app composer install -o\n```\n\nTo access your app services, you will have to expose ports locally in your `compose.override.yml` file.\nCopy `compose.override.yml.dist` to `compose.override.yml` file to override your `compose.yml` file and expose \nyour app container ports for local development:\n\n```yaml\n# Expose all services default ports for local development\nservices:\n    db:\n        ports:\n            - ${PUBLIC_DB_PORT}:3306/tcp\n    nginx:\n        ports:\n            - ${PUBLIC_NGINX_PORT}:80/tcp\n    mailer:\n        ports:\n            - ${PUBLIC_MAILER_PORT}:8025/tcp\n    varnish:\n        ports:\n            - ${PUBLIC_VARNISH_PORT}:80/tcp\n    redis:\n        ports:\n            - ${PUBLIC_REDIS_PORT}:6379/tcp\n    pma:\n        ports:\n            - ${PUBLIC_PMA_PORT}:80/tcp\n    # If you depend on private Gitlab repositories, you must use a deploy token and username\n    #app:\n    #    build:\n    #        args:\n    #            UID: ${UID}\n    #            COMPOSER_DEPLOY_TOKEN: xxxxxxxxxxxxx\n    #            COMPOSER_DEPLOY_TOKEN_USER: \"gitlab+deploy-token-1\"\n```\n\n### Generate [Symfony secrets](https://symfony.com/doc/current/configuration/secrets.html)\n\nWhen you run `composer create-project` first time, following command should have been executed automatically:\n\n```shell script\ndocker compose exec app bin/console secrets:generate-keys\n```\n\nThen generate secrets values for your configuration variables such as `APP_SECRET` or `JWT_PASSPHRASE`:\n\n```shell script\ndocker compose exec app bin/console secrets:set JWT_PASSPHRASE --random\ndocker compose exec app bin/console secrets:set APP_SECRET --random\n```\n\n**Make sure your remove any of these variables from your `.env` and `.env.local` files**, it would override your\nsecrets (empty values for example), and lose all benefits from encrypting your secrets.\n\n### Generate JWT private and public keys\n\nUse built-in command to generate your key pair (following command should have been executed automatically at `composer create-project`):\n\n```shell\ndocker compose exec app bin/console lexik:jwt:generate-keypair\n```\n\n### Install database\n\nUse `make install` command to install your database schema and fixtures.\n\nOr manually:\n\n```shell\n# Create Roadiz database schema\ndocker compose exec app bin/console doctrine:migrations:migrate\n# Migrate any existing data types\ndocker compose exec app bin/console app:install\n# Install base Roadiz fixtures, roles and settings\ndocker compose exec app bin/console install\n# Clear cache\ndocker compose exec app bin/console cache:clear\n```\n\nBefore accessing the application, you need to create an admin user. Use the following command to create a user account:\n```shell\n# Create your admin account with the specified username and email\nexport EMAIL=\"username@roadiz.io\"\ndocker compose exec app bin/console users:create -m $EMAIL -b -s $EMAIL\n# By default, a random password will be generated for the new user.\n# If you want to set a custom password, you can add the -p option followed by your desired password\n```\n\n### Manage Node-types\n\nNode-types can be managed through back-office interface or by editing JSON files in `src/Resources/node-types` directory.\nIf you edit JSON files manually you need to synchronize your database with these files and generate Doctrine Migrations\nif this leads to database schema changes.\n\n#### Migrate node-types\n\nWhen you direct update the `node-types` JSON files, you need to add them into `src/Resources/config.yml` \nand run the following command to update the database:\n\n```bash \nmake migrate\n```\n\nThis command will **update PHP entities** and **create a Doctrine migration** file if necessary.\n\n#### Apply node-type migration\n\nWhen you pull the project and just want to sync your local node-types, you need to apply the migration:\n\n```bash \nmake update\n```\n\nThis will **only load node-types** that are not already in the database. But it won't create any migration.\nThis is the same script that is executed when you run `make install` and in your docker image entrypoint.\n\n### Features\n\n- Configured to be used in headless mode with *API Platform*\n- Configured with *lexik/jwt-authentication-bundle*\n- All-Docker development and production environments\n- Supervisor daemon for execution symfony/messenger consumers\n- Solr and Varnish services right out-the-box\n- Gitlab CI ready\n- Use *phpcs* and *phpstan* to ensure code-smell and static analysis\n- Packed with 4 *node-types*: `Menu`, `MenuLink` in order to create automatic menus in your `/api/common_content` response and `Page` and `AliasBlock` as a basic page and alias management system.\n\n#### Common content endpoint\n\n`/api/common_content` endpoint is meant to expose common data about your website.\nYou can fetch this endpoint once in your website frontend, instead of embedding the same data in each web response.\n`menus` entry will automatically hold any root-level `Menu` tree-walker.\n\n```json\n{\n    \"@context\": \"/api/contexts/CommonContent\",\n    \"@id\": \"/api/common_content?id=unique\",\n    \"@type\": \"CommonContent\",\n    \"home\": {\n        \"@id\": \"/api/pages/1\",\n        \"@type\": \"Page\",\n        \"title\": \"home\",\n        \"publishedAt\": \"2021-09-09T02:23:00+02:00\",\n        \"node\": {\n            \"@id\": \"/api/nodes/1\",\n            \"@type\": \"Node\",\n            \"nodeName\": \"home\",\n            \"visible\": true,\n            \"tags\": []\n        },\n        \"translation\": {\n            \"@id\": \"/api/translations/1\",\n            \"@type\": \"Translation\",\n            \"name\": \"English\",\n            \"defaultTranslation\": true,\n            \"available\": true,\n            \"locale\": \"en\"\n        },\n        \"slug\": \"home\",\n        \"url\": \"/\"\n    },\n    \"head\": {\n        \"@type\": \"NodesSourcesHead\",\n        \"googleAnalytics\": null,\n        \"googleTagManager\": null,\n        \"matomoUrl\": null,\n        \"matomoSiteId\": null,\n        \"siteName\": \"Roadiz dev website\",\n        \"metaTitle\": \"Roadiz dev website\",\n        \"metaDescription\": \"Roadiz dev website\",\n        \"policyUrl\": null,\n        \"mainColor\": null,\n        \"facebookUrl\": null,\n        \"instagramUrl\": null,\n        \"twitterUrl\": null,\n        \"youtubeUrl\": null,\n        \"linkedinUrl\": null,\n        \"homePageUrl\": \"/\",\n        \"shareImage\": null\n    },\n    \"menus\": {\n        \"mainMenuWalker\": {\n            \"@type\": \"MenuNodeSourceWalker\",\n            \"children\": [],\n            \"item\": { ... },\n            \"childrenCount\": 0,\n            \"level\": 0,\n            \"maxLevel\": 3\n        }\n    }\n}\n```\n\n### Versioning\n\nMake sure your `.env` file does not contain any sensitive data as it must be added to your repository: `git add --force .env`\nin order to be overridden by `.env.local` file.\nSensitive and local data must be filled in `.env.local` which is git-ignored.\n\n### Conventional commits\n\nThis project uses conventional commits to automate the release process and \n*changelog* generation with [git-cliff](https://github.com/orhun/git-cliff).\nA `cliff.toml` configuration file is already provided in this skeleton.\n\n#### Generate a CHANGELOG file\n```bash\ngit-cliff -o CHANGELOG.md\n```\n\n#### Before releasing\n\n- With a known tag\n    ```bash\n    git-cliff -o CHANGELOG.md --tag 1.0.0\n    ```\n- Without knowing tag, let `git-cliff` find the right version\n    ```bash\n    git-cliff -o CHANGELOG.md --bump\n    ```\n\n### Credits\n\nThis skeleton uses https://github.com/vishnubob/wait-for-it script to wait for MySQL readiness before launching app entrypoint.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Froadiz%2Fskeleton","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Froadiz%2Fskeleton","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Froadiz%2Fskeleton/lists"}