# Task synopsis

I'd like to implement a URL shortener, mocking the de-facto `urlshortener` project, but with the following requirements:

# Task requirements

* We should implement it with python 3.8+, with minimum dependencies, in a single .py file. Using no 3rd party libraries/frameworks is the best.
* The configs should be passed as a single JSON file, containing these keys:
  * `base_url` - the base URL to use for the shortened URLs
  * `short_length` - the length of the shortened URLs
  * `api_key` - the API key to use this shortener to create new shortened URLs
  * ... other configs, if you think are necessary, ask me.
* The API should be RESTful, and simple enough to be used by a human.
* The shortened data should be stored within a sqlite database.
* Other than the .py file, provide a docker compose file to run it. Remember to keep the data in a mount dir so it won't be lost.

# Additional requirements
* API authentication should be purely done based on each API's api_key field, as described below. No session management or token management is needed. The API key can be passed as a query parameter or in the json request body, and it should be checked for every API call that requires authentication.
* The base path should be configurable, the same as both in current implementation and in README.
* Implement retention days feature where old URLs are deleted after a certain number of days. If 0 or not set for a shortened URL, it will never be deleted.
* The API design should be like this, remember to deal with trailing slashes:
  1. GET `<base_url>` - health check, same as current implementation in README.
  2. GET `<base_url>/api/urls&api_key=<api_key>` - returns all shortened URLs in json, newest first. The API key is required. The return json body should be same as described in current README.
  3. POST `<base_url>/api/shorten`, create new short URL. The fields needed can either be passed as query parameters (remember to deal with URL escaping/unescaping) or in the json request body.
    The response should be only the short URL in plain text. The fields needed are listed as below: 
    a) `api_key` (required) - the API key is required.
    b) `url` (required) - the URL to shorten
    c) `short_length` (optional) - the length of the shortened URLs, default to config value.
    d) `retention_days` (optional) - the number of days to keep current shortened URLs, default to config value.
    
  4. GET `<base_url>/api/urls/<short_id>` - no API key required, returns metadata json for a shortened URL, includes:
    ```json
    {
      "short_code": "aB3xYz",
      "short_url": "<base_url>/aB3xYz",
      "original_url": "https://example.com",
      "created_at": 1710000000,
      "visit_count": 5
    }
    ```
  5. DELETE `<base_url>/api/urls/<short_id>&api_key=<api_key>` - deletes a shortened URL. API key is required. 
    a) Returns 204 on success without body,
    b) 404 if not found, without body, 
    c) 403 if not authorized, without body.
  6. GET `<base_url>/<short_id>` - redirects to the original URL (302). Increments the visit count on each hit.

# Simple Frontend
* Implement a clean and simple frontend, follow the same design and style requirements for the single page HTML located in the `navpage` folder, as described in its TASK md file.
* Add an optional one-line API key input field to top right corner, so that admin can access to the restricted APIs.
* There is a long search input bar on top center of the page, where user can input a URL to shorten once enter is hit. if shortening is successful, show all its metadata below in a table at center of the page below the search bar;
* If the input URL is existing (even without hitting enter), also show all its metadata in the table.
* If the input URL is malformed on hitting enter, display nothing below the search bar.
* If the API key provided is not valid, show nothing and continue using the page as non admin.
* Once the provided API key is valid, list the existing shortened URLs in a table below the search bar (if the search bar is empty), with the following columns, ordered by created_at descending:
  1. shortened URL
  2. original URL
  3. visit count
  4. created at
  5. retention days
* For this admin table, each row should have a delete button on end, only displayed on mouse hover, which will call the delete API to delete the shortened URL.
* Each row should have a copy button on end, copying the shortened URL to clipboard.
* The table should be sortable by any column.
* The table should be paginated, with 20 rows per page by default, controlled by a dropdown of `20, 50, 100, 200, 500, all`, and the pagination controls should be displayed at the bottom of the table.
* The search bar should also function as the same as for admin (hide the listing table once start typing) - display metadata for existing URLs, create new one for valid URL on hitting enter.
* all static resources should be put under the `urlshort/static` folder.
* the strict "local-serve" requirement is the same as `navpage`, reuse the script in `navpage` if possible.
* Once the frontend implementation is done, rewrite the nginx config to serve it correctly. If possible, only write the locations config, for that I'm planning to deploy both frontend and backend in an existing vhost. Write the path mapping carefully to avoid possible conflicts with the existing vhost.

# Extra requirements on backend
* Also, implement simple but proper CORS to allow seamless redirection to the target URL.
* In hindsight, the API backend should at least implement simple rate limiting/throttling, by IP address.
* Field validation is also a must, checking and limiting ALL fields to reasonable values to prevent hacking, especially SQL injections and buffer overflows.
* If needed, implement other necessary guard features on the backend to prevent XSS, CSRF, and other common web attacks.
