{"id":14976173,"url":"https://github.com/agoston-io/agoston-postgraphile","last_synced_at":"2026-01-03T19:40:47.777Z","repository":{"id":208208092,"uuid":"721063404","full_name":"agoston-io/agoston-postgraphile","owner":"agoston-io","description":"GraphQL backend stack (100% open-source) with all you need in one place. Opinionated implementation of Postgraphile.","archived":false,"fork":false,"pushed_at":"2024-09-13T09:24:55.000Z","size":513,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2024-10-30T08:48:59.381Z","etag":null,"topics":["backend","graphql-server","postgresql"],"latest_commit_sha":null,"homepage":"https://agoston.io/","language":"JavaScript","has_issues":true,"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/agoston-io.png","metadata":{"files":{"readme":"README.md","changelog":null,"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}},"created_at":"2023-11-20T09:33:14.000Z","updated_at":"2024-09-13T09:24:20.000Z","dependencies_parsed_at":"2024-01-04T14:47:44.816Z","dependency_job_id":"eacc60a9-b193-40ba-9038-9d69f0a2d4b3","html_url":"https://github.com/agoston-io/agoston-postgraphile","commit_stats":{"total_commits":38,"total_committers":4,"mean_commits":9.5,"dds":"0.42105263157894735","last_synced_commit":"433c03a8a5e329372ef0291c1d68fec07c2461f5"},"previous_names":["agoston-io/agoston-postgraphile"],"tags_count":21,"template":false,"template_full_name":null,"purl":"pkg:github/agoston-io/agoston-postgraphile","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/agoston-io%2Fagoston-postgraphile","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/agoston-io%2Fagoston-postgraphile/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/agoston-io%2Fagoston-postgraphile/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/agoston-io%2Fagoston-postgraphile/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/agoston-io","download_url":"https://codeload.github.com/agoston-io/agoston-postgraphile/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/agoston-io%2Fagoston-postgraphile/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":270922511,"owners_count":24668565,"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-08-17T02:00:09.016Z","response_time":129,"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":["backend","graphql-server","postgresql"],"created_at":"2024-09-24T13:53:25.935Z","updated_at":"2026-01-03T19:40:47.712Z","avatar_url":"https://github.com/agoston-io.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Agoston\n\nBuild and scale Apps like a team of experts in a week.\n\nAgoston extends the powerful [Postgraphile](https://github.com/graphile/crystal/tree/main/postgraphile/postgraphile) with all the features you need to develop a complete, full-stack, application:\n\n- Authentication: Google, Facebook, Github, Auth0, OIDC, HTTP Bearer token, user/password.\n- Session: Agoston creates a user session and stores it in the Postgres database.\n- User permissions: In Postgres, requests are identified with an `user_id` to allow fine-grained permissions with Postgres RLS.\n- [Files upload](https://github.com/graphile-contrib/postgraphile-upload-example): Upload files to your backend via standard GraphQL mutation.\n- [Job queue](https://worker.graphile.org/docs): Job queue which uses PostgreSQL to store jobs, and executes them on Node.js.\n- [Recurring tasks (crontab)](https://worker.graphile.org/docs/cron): Recurring tasks according to a cron-like schedule.\n\n## Cloud deployment\n\nWe provide Agoston in the cloud if your don't want to bother with the technical implementation.\nCreate an account here: [https://agoston.io/](https://agoston.io/).\n\n## Run backend\n\n```bash\ndocker compose -f ./docker-compose.yml up\n```\n\n```bash\n## Switch to a revious version\ngit checkout v3.14.3\ncd src/\nrm -rf ./node_modules/\nnpm i\ncd ..\n```\n\n### Access GraphiQL\n\n- HTTP: http://graphile.agoston.dev.local:8080/data/graphiql\n- HTTPS: https://graphile.agoston.dev.local:8043/data/graphiql\n\n### Connect to the Postgres database\n\n```bash\npsql postgresql://postgres:agoston@localhost:5552/agoston\n```\n\n### To restart on a fresh environment (with new db)\n\n```bash\ndocker rm agoston-postgraphile-postgres-1 agoston-postgraphile-postgraphile-1; \\\ndocker rmi agoston-postgraphile-dev agoston-postgres-dev\n```\n\n## Backend configuration\n\n```bash\n#---------- HTTP configuration\nexport HTTP_LISTENING=1\nexport HTTP_PORT_LISTENING=8080\n#---------- Log level\nexport LOG_LEVEL=silly # Winston log level\nexport LOG_COLOR=true  # Winston log color\n#---------- HTTPS configuration\nexport HTTPS_LISTENING=0  # Useful for development, otherwise disable and shield with a reverse proxy\nexport HTTPS_PORT_LISTENING=8043\nexport HTTPS_PORT_CERTIFICATE=/tmp/server.crt\nexport HTTPS_PORT_PRIVATEKEY=/tmp/server.key\n#---------- All\nexport ENVIRONMENT_NAME=development\nexport HTTP_BACKEND_ORIGIN='https://graphile.agoston.dev.local'\nexport PGHOST=localhost\nexport PGDATABASE=agoston-1\nexport POSTGRES_PASSWORD=agoston\nexport POSTGRAPHILE_USER='postgraphile-1'\nexport POSTGRAPHILE_PASSWORD=agoston\nexport DEVELOPER_USER='developer-1'\nexport DEVELOPER_PASSWORD=agoston\nexport CORS_ORIGIN='https://127.0.0.1:5173'\nexport SESSION_COOKIE_SECRET=JWaaEHOnJyMYvB06Q0cqRDhMgRpD0Cfy\n#---------- Recaptcha\nexport RECAPTCHA_SCORE_THRESHOLD=\nexport RECAPTCHA_SECRET_KEY=\n#---------- Auth\nexport AUTH_STRATEGIES='{\"http-bearer\": {\"enable\": true}, \"user-pwd\": {\"enable\": true }}'\nexport AUTH_OIDC='[]'\n#---------- Stripe\nexport STRIPE_HOOK_ENABLE=true\nexport STRIPE_API_KEY=\nexport STRIPE_HOOK_ENDPOINT_SECRET=\n#---------- Env\nexport NODE_ENV=development\n#---------- Worker\nexport GRAPHILE_LOGGER_DEBUG=1\nexport WORKER_SCHEMA=\nexport WORKER_CRON_JOB_LIMIT=10\nexport WORKER_CONCURRENCY=5\nexport WORKER_POLL_INTERVAL=1000\nexport WORKER_EMAIL_ENABLE=false\nexport WORKER_EMAIL_SMTP_HOST=\nexport WORKER_EMAIL_SMTP_PORT=25\nexport WORKER_EMAIL_SMTP_SECURE=true\nexport WORKER_EMAIL_SMTP_AUTH_USER=\nexport WORKER_EMAIL_SMTP_AUTH_PASS=\n#---------- GraphQL upload file location\nexport UPLOAD_DIR_NAME='./uploads'\n```\n\n## Tests\n\n```bash\n# export SKIP_FINAL_CLEANUP=1\n./tests/run.sh\n```\n\n## Authentication\n\n### HTTP Bearer\n\nYou can enable the HTTP Bearer authentication by appending the following configuration to the `AUTH_STRATEGIES` run time environment variable:\n\n```json\n{\n  \"http-bearer\": {\n    \"enable\": true\n  }\n}\n```\n\n#### Generate a token for a user\n\nGenerate a bearer token for a user (or a new user created on the fly with `agoston_api.add_user()`):\n\n```sql\nselect set_user_token(p_user_id =\u003e 1) as \"token\";\nselect set_user_token(p_user_id =\u003e agoston_api.add_user()) as \"token\";\n                                                             token\n-------------------------------------------------------------------------------------------------------------------------------\n uYNtAHQ5tRuByn8X7WBaK6TQRSdA9EzbR7zn8lq7tnJntfnwksLGVbnn2BxhhYj14RrnE2REB2Uxx11luAuGGP5afmQNQp4tR7vHd992wNXGfn6X2AF\n(1 row)\n```\n\nIt is also possible to add a name and/or an expiration date to the token:\n\n```sql\nfunction agoston_api.set_user_token (\n    p_user_id int,\n    p_token_name text default null,\n    -- Token expires after 10 years per default. You can overwrite with p_expiration_ts.\n    p_expiration_ts timestamp with time zone default null\n);\n```\n\n#### Example without bearer token\n\n```bash\n$ curl -s -X POST \\\n-H \"Content-Type: application/json\" \\\n-d '{\"query\": \"query {session}\"}' \\\n'http://localhost:8080/data/graphql' | jq\n```\n\n```json\n{\n  \"data\": {\n    \"session\": {\n      \"role\": \"anonymous\",\n      \"user_id\": 0,\n      \"auth_data\": null,\n      \"session_id\": \"iDYWVlGp5OYU6JyEd3zfOZH5RFVRwaZ0\",\n      \"auth_subject\": null,\n      \"auth_provider\": null,\n      \"is_authenticated\": false\n    }\n  }\n}\n```\n\n#### Example with bearer token\n\n```bash\ncurl -s -X POST \\\n-H \"\"Authorization\": Bearer uYNtAHQ5tRuByn8X7WBaK6TQRSdA9EzbR7zn8lq7tnJntfnwksLGVbnn2BxhhYj14RrnE2REB2Uxx11luAuGGP5afmQNQp4tR7vHd992wNXGfn6X2AF\" \\\n-H \"Content-Type: application/json\" \\\n-d '{\"query\": \"query {session}\"}' \\\n'http://localhost:8080/data/graphql' | jq\n```\n\n```json\n{\n  \"data\": {\n    \"session\": {\n      \"role\": \"authenticated\",\n      \"user_id\": 1,\n      \"auth_data\": {},\n      \"session_id\": \"PPDqL4IwaIZ3WmQmGyz5e_bV_iWgFnBj\",\n      \"auth_subject\": \"1\",\n      \"auth_provider\": \"http-bearer\",\n      \"is_authenticated\": true\n    }\n  }\n}\n```\n\n#### Delete a token for a user\n\n```sql\nselect agoston_api.delete_user_token(\n    p_user_token_id =\u003e \u003cuser_id\u003e\n);\n```\n\n### Local user and password\n\nYou can enable the local user and password authentication by appending the following configuration to the `AUTH_STRATEGIES` run time environment variable:\n\n```json\n{\n  \"user-pwd\": {\n    \"enable\": true,\n    \"params\": {\n      \"usernameComplexityPattern\": \"^[a-z0-9-_.@]{5,}$\",\n      \"passwordComplexityPattern\": \"^(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])(?=.*[!@#$%^\u0026*,-_])(?=.{8,})\"\n    }\n  }\n}\n```\n\n### Change user password\n\n```sql\nselect set_user_password(p_username =\u003e 'myusername', p_password =\u003e 'Azerty@2026');\n-- Ensure the old password is correct before changing to the new password\nselect set_user_password(p_username =\u003e 'myusername', p_password =\u003e 'Azerty@2026', p_current_password =\u003e 'Azerty@2025');\n```\n\n### Expire user password\n\n```sql\nselect set_user_password_expiration(p_username =\u003e 'myusername', p_password_expired =\u003e true);\nselect set_user_password_expiration(p_username =\u003e 'myusername', p_password_expired =\u003e false);\n```\n\n## Backend run time configuration\n\nYou can see the run-time configuration that the backend uses by calling the URL `\u003cHTTP_BACKEND_ORIGIN\u003e/.well-known/configuration`:\n\n```json\n{\n    \"version\": \"3.11.1\",\n    \"endpoints\": {\n        \"graphql\": \"https://graphile.agoston.dev.local/data/graphql\",\n        \"graphql_ws\": \"wss://graphile.agoston.dev.local/data/graphql\"\n    },\n    ...\n    // The JSON configuration will also show the session values:\n    \"currentSession\": {\n        \"role\": \"authenticated\",\n        \"user_id\": 1,\n        \"auth_data\": {\n            \"attr1\": \"val1\",\n            \"attr2\": \"val2\"\n        },\n        \"session_id\": \"KzNcgOEk-HkpKQcrPGTY00VS57crj2G6\",\n        \"auth_subject\": \"niolap2\",\n        \"auth_provider\": \"user-pwd\",\n        \"is_authenticated\": true\n    },\n    // The JSON configuration can render an optional custom query:\n    \"customGraphQLQueryResult\": {\n        \"data\": {\n            \"post\": {\n                \"id\": 2\n            }\n        }\n    }\n}\n```\n\n### Custom query\n\nYou can also add a custom query as a URL parameter `?gq=` with optional query variables parameter `\u0026gqv=`.\nIt's useful when you load from the frontend configuration and want to load some application data without having to perform an additional round trip to the backend.\n\n- gq: a GraphQL query or mutation (no subscription supported) URL-encoded.\n- gqv: a JSON string URL-encoded holding the variables of your graphQL query.\n\nFor instance:\n\n```json\n// $ curl 'http://localhost:8080/.well-known/configuration?gq=query%20MyQuery%28%24id%3A%20Int%20%3D%201%29%20%7B%0A%20%20post%28id%3A%20%24id%29%20%7B%0A%20%20%20%20id%0A%20%20%7D%0A%7D%0A\u0026gqv=%7B%22id%22%3A2%7D'\n{\n    \"version\": \"3.11.1\",\n    \"endpoints\": {\n        \"graphql\": \"https://graphile.agoston.dev.local/data/graphql\",\n        \"graphql_ws\": \"wss://graphile.agoston.dev.local/data/graphql\"\n    },\n    ...\n    \"customGraphQLQueryResult\": {\n        \"data\": {\n            \"post\": {\n                \"id\": 2\n            }\n        }\n    }\n}\n```\n\n## GraphQL file upload\n\nTo turn a GrahpQL attribute to an `upload` data type and thus accept uploads through GraphQL mutations, you must add a Postgraphile tag `@upload` in the table column. Such a column will then receive the file path and file metadata, and the file will be uploaded in the upload directory defined by `UPLOAD_DIR_NAME` (default value: `./uploads`). Example:\n\n```\ncomment on column post.header_image_file is E'@upload';\n```\n\n**NOTE**: You may need to adjust the reverse proxy configuration to allow bigger file uploads (e.g., `client_max_body_size 64M;` in nginx). Otherwise, the client would receive a `HTTP 413 (Request Entity Too Large)` error.\n\n## Stripe hook\n\n```\nstripe listen --forward-to localhost:4000/hook/stripe\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fagoston-io%2Fagoston-postgraphile","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fagoston-io%2Fagoston-postgraphile","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fagoston-io%2Fagoston-postgraphile/lists"}